diff options
Diffstat (limited to 'user/libthread/mutex_lock.S')
| -rw-r--r-- | user/libthread/mutex_lock.S | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/user/libthread/mutex_lock.S b/user/libthread/mutex_lock.S new file mode 100644 index 0000000..731ab59 --- /dev/null +++ b/user/libthread/mutex_lock.S @@ -0,0 +1,114 @@ +#include <syscall_int.h> + +// it is impossible to implement mutex_unlock_vanish without stack in c +// so we implement all lock functions in assembly and mutex_unlock can +// share function body with mutex_unlock_vanish + +.mutex_unlock_body: + xor %eax, %eax // + lock xchg %eax, (%ebp) // mp->locked = 0; +.mutex_unlock_try: // while(true) { + xor %eax, %eax // + mov $1, %edi // + lock cmpxchg %edi, 0x4(%ebp) // eax = compare_and_set(&mp->w_lock, 1); + test %eax, %eax // if(eax == 0) {break;} + jnz .mutex_unlock_try // } + mov 0x8(%ebp), %edi // edi = mp->w_list; + test %edi, %edi // + jz .mutex_unlock_w_empty // if(edi != NULL) { + mov $1, %edx // + mov %edx, 0x28(%edi) // edi->mutex_resume = 1; + mov (%edi), %esi // + int $MAKE_RUNNABLE_INT // make_runnable(edi->tid); +.mutex_unlock_w_empty: // } + xor %eax, %eax // + lock xchg %eax, 0x4(%ebp) // mp->w_lock = 0; + jmp *%ebx + +.global mutex_unlock +.type mutex_unlock, %function +mutex_unlock: + push %ebx + push %ebp + mov 0xc(%esp), %ebp // ebp = mp + lea .mutex_unlock_done, %ebx // ebx will be used by mutex_unlock_body as return address + jmp .mutex_unlock_body +.mutex_unlock_done: + pop %ebp + pop %ebx + ret + +.global mutex_unlock_vanish +.type mutex_unlock_vanish, %function +mutex_unlock_vanish: + mov 0x4(%esp), %ebp + lea .mutex_unlock_do_vanish, %ebx + jmp .mutex_unlock_body +.mutex_unlock_do_vanish: + int $VANISH_INT + +.global mutex_lock +.type mutex_lock, %function +mutex_lock: + push %ebx // + push %ebp // + call get_self_tcb // + mov %eax, %ebx // ebx = get_self_tcb(); + xor %eax, %eax // + mov %eax, 0x28(%ebx) // ebx->mutex_resume = 0; + mov 0xc(%esp), %ebp // ebp = mp; +.mutex_lock_w_lock: // while(true) { + xor %eax, %eax // + mov $1, %edi // + lock cmpxchg %edi, 0x4(%ebp) // eax = compare_and_set(&mp->w_lock, 1); + test %eax, %eax // if(eax == 0) {break;} + jnz .mutex_lock_w_lock // } + mov 0x8(%ebp), %edi // edi = mp->w_list; + test %edi, %edi // + jz .mutex_lock_w_empty // if(edi != NULL) { + mov %edi, 0x20(%ebx) // ebx->mutex_next = edi; + mov 0x24(%edi), %edx // edx = edi->mutex_prev; + mov %edx, 0x24(%ebx) // ebx->mutex_prev = edx; + mov %ebx, 0x20(%edx) // edx->mutex_next = ebx; + mov %ebx, 0x24(%edi) // edi->mutex_prev = ebx; + jmp .mutex_lock_w_done // } +.mutex_lock_w_empty: // else { + mov %ebx, 0x8(%ebp) // mp->w_list = ebx; + mov %ebx, 0x20(%ebx) // ebx->mutex_next = ebx; + mov %ebx, 0x24(%ebx) // ebx->mutex_prev = ebx; +.mutex_lock_w_done: // } + lock xchg %eax, 0x4(%ebp) // mp->w_lock = 0; +.mutex_lock_try: // + xor %eax, %eax // while(true) { + mov $1, %edi // + lock cmpxchg %edi, (%ebp) // eax = compare_and_set(&mp->locked, 1); + test %eax, %eax // + jz .mutex_lock_success // if(eax == 0) {break;} + lea 0x28(%ebx), %eax // + push %eax // + call deschedule // deschedule(&ebx->mutex_resume); + add $0x4, %esp // + jmp .mutex_lock_try // } +.mutex_lock_success: // while(true) { + xor %eax, %eax // + mov $1, %edi // + lock cmpxchg %edi, 0x4(%ebp) // eax = compare_and_set(&mp->w_lock, 1); + test %eax, %eax // if(eax == 0) {break;} + jnz .mutex_lock_success // } + mov 0x20(%ebx), %edi // edi = ebx->mutex_next; + mov 0x24(%ebx), %edx // edx = ebx->mutex_prev; + cmp %edi, %ebx // + je .mutex_lock_w_last // if(edi != ebx) { + mov %edx, 0x24(%edi) // edi->mutex_prev = edx; + mov %edi, 0x20(%edx) // edx->mutex_next = edi; + cmp %ebx, 0x8(%ebp) // + jne .mutex_lock_w_end // if(ebx == mp->w_list) + mov %edi, 0x8(%ebp) // mp->w_list = edi; + jmp .mutex_lock_w_end // } +.mutex_lock_w_last: // else { + mov %eax, 0x8(%ebp) // mp->w_list = NULL; +.mutex_lock_w_end: // } + lock xchg %eax, 0x4(%ebp) // mp->w_lock = 0; + pop %ebp + pop %ebx + ret |
