diff options
Diffstat (limited to 'lib/lock_release.asm')
-rw-r--r-- | lib/lock_release.asm | 132 |
1 files changed, 0 insertions, 132 deletions
diff --git a/lib/lock_release.asm b/lib/lock_release.asm deleted file mode 100644 index f86caa2..0000000 --- a/lib/lock_release.asm +++ /dev/null @@ -1,132 +0,0 @@ -; Under MIT license, see /LICENSE.txt - - -; Cheat sheet for Linux' x86_64 calling convention: -; -; - free to overwrite (caller should save them): -; rax, rcx, rdx, rsi, rdi, r8-r11, xmm0-xmm15 -; - caller expects be kept (callee should save them): -; rbx, rbp, r12-r15 -; -; - for passing paramters to functions: -; rdi, rsi, rdx, rcx, r8, r9, xmm0-xmm7 -; - for getting return values from functions: -; rax, rdx, xmm0 -; -; - for passing parameters to syscalls: -; rax, rdi, rsi, rdx, r10, r8, r9 -; - for getting return values from syscalls: -; rax, rdx -; - overwritten by syscalls (all others preserved): -; rcx, r11 - - -section .text - - -; Relevant system call IDs -%define SYS_GETTID 186 -%define SYS_FUTEX 202 - -; Relevant operations for futex -%define FUTEX_UNLOCK_PI 7 -%define FUTEX_PRIVATE_FLAG 0x80 - -; Relevant bits for futex dword -%define FUTEX_TID_MASK 0x3fffffff -%define FUTEX_OWNER_DIED 0x40000000 -%define FUTEX_WAITERS 0x80000000 - - -; Release an acquired lock if we're who acquired it. Argument: -; rdi: struct{u32,u32,u32}* = handle of lock to release -; Returns zero on success, or a standard error code. -global linen_lock_release -linen_lock_release: - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ;;;; Check validity of argument ;;;; - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - ; Return EINVAL if rdi is NULL or invalid - mov eax, -22 ; (EINVAL = -22) - - test rdi, rdi - jz release_return ; rdi is NULL - - ; rdi is nonzero, so let's just assume it's a valid pointer; - ; if that assumption is wrong we'll get a segmentation fault. - ; But we don't yet trust that [rdi] is a valid lock handle! - ; To verify this we check the canary value stored at [rdi + 8]. - mov ecx, [rdi + 8] - cmp ecx, 0xCAFEBABE - jnz release_return - - ; Lock owners are identified by their TID; let's find ours. - ; The gettid system call simply returns our Linux thread ID. - ; See: man 2 gettid - - ; gettid: rax = system call ID - mov eax, SYS_GETTID - ; gettid: rax = gettid() - syscall - - ; Save a copy of our TID (no need for an error check) - mov edx, eax - - ; Return EPERM if this lock currently doesn't belong to us - mov eax, -1 ; (EPERM = -1) - - ; Read the futex dword at [rdi] and keep its lowest 30 bits - mov ecx, [rdi] - and ecx, FUTEX_TID_MASK - ; Those bits contain the owner's TID; it should be our TID - cmp ecx, edx - jne release_return - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ;;;; (Partially) release our lock ;;;; - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - ; Decrement the recursion counter. If it's still > 1, we're done here. - dec dword [rdi + 4] - jnz release_success - ; If it reaches 0, it's time for a full release by setting [rdi] to 0. - - ; Restore our saved TID to eax for "lock cmpxchg" below - mov eax, edx - - ; Atomically try to set the dword at [rdi] to 0 if it was equal to our TID. - ; if ([rdi] == eax]) { [rdi] = 0; goto release_success; } else { eax = [rdi]; } - xor ecx, ecx - lock cmpxchg [rdi], ecx - je release_success - - ; We failed because [rdi] wasn't equal to our TID. In theory, - ; that can mean only one thing: [rdi] = (edx | FUTEX_WAITERS). - ; In that case we need to ask the kernel to wake up the threads - ; who are waiting (via a futex system call) for [rdi] to change. - ; See: man 2 futex - - ; futex: rdi = uaddr: address of the dword to announce for - ; futex: rsi = futex_op: which futex operation we want: - ; - FUTEX_UNLOCK_PI: wake up one thread sleeping via FUTEX_LOCK_PI - ; - FUTEX_PRIVATE_FLAG: this lock isn't shared with another process - mov esi, (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG) ; futex: futex_op - ; futex: rdx = val: ignored when FUTEX_UNLOCK_PI is used - ; futex: r10 = timeout: ignored when FUTEX_UNLOCK_PI is used - ; futex: r8 = uaddr2: ignored when FUTEX_UNLOCK_PI is used - ; futex: r9 = val3: ignored when FUTEX_UNLOCK_PI is used - ; futex: rax = system call ID - mov eax, SYS_FUTEX - ; futex: rax = futex(rdi, rsi, (rdx), (r10), (r8), (r9)) - syscall - - ; Check result of futex: nonzero means failure - test rax, rax - jnz release_return - - release_success: - xor eax, eax - - release_return: - ret |