diff options
author | Prefetch | 2023-07-24 19:21:30 +0200 |
---|---|---|
committer | Prefetch | 2023-07-24 19:21:30 +0200 |
commit | 94e3e3652f9f04810126ee754fa9a788289e2897 (patch) | |
tree | af5aac9f176039e97f1ebc46b497b5fd192a4fa2 /src/lock_release.asm | |
parent | a211da8cfe9b0565881537cc81b09ae55c722111 (diff) |
Diffstat (limited to 'src/lock_release.asm')
-rw-r--r-- | src/lock_release.asm | 32 |
1 files changed, 18 insertions, 14 deletions
diff --git a/src/lock_release.asm b/src/lock_release.asm index f86caa2..2892cc3 100644 --- a/src/lock_release.asm +++ b/src/lock_release.asm @@ -43,12 +43,15 @@ section .text ; Returns zero on success, or a standard error code. global linen_lock_release linen_lock_release: + ; It's handy to have a register that's 0 during most of this function + xor esi, esi + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Check validity of argument ;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; Return EINVAL if rdi is NULL or invalid - mov eax, -22 ; (EINVAL = -22) + ; Return EINVAL (-22) if rdi is NULL or invalid + lea eax, [rsi - 22] ; mov eax, -22 test rdi, rdi jz release_return ; rdi is NULL @@ -57,8 +60,7 @@ linen_lock_release: ; 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 + cmp dword [rdi + 8], 0xCAFEBABE ; Oh CISC... jnz release_return ; Lock owners are identified by their TID; let's find ours. @@ -66,17 +68,19 @@ linen_lock_release: ; See: man 2 gettid ; gettid: rax = system call ID - mov eax, SYS_GETTID + xor eax, eax + mov al, 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) + ; Return EPERM (-1) if this lock currently doesn't belong to us + or eax, -1 ; mov eax, -1 - ; Read the futex dword at [rdi] and keep its lowest 30 bits + ; Read the futex dword at [rdi] and keep its lowest 30 bits. + ; No need to use atomics, since we currently own this lock. mov ecx, [rdi] and ecx, FUTEX_TID_MASK ; Those bits contain the owner's TID; it should be our TID @@ -96,9 +100,8 @@ linen_lock_release: 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 + ; if ([rdi] == eax) { [rdi] = 0; goto release_success; } else { eax = [rdi]; } + lock cmpxchg [rdi], esi ; esi = 0 je release_success ; We failed because [rdi] wasn't equal to our TID. In theory, @@ -111,18 +114,19 @@ linen_lock_release: ; 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 + mov sil, (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG) ; 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 + xor eax, eax + mov al, SYS_FUTEX ; futex: rax = futex(rdi, rsi, (rdx), (r10), (r8), (r9)) syscall ; Check result of futex: nonzero means failure - test rax, rax + test eax, eax jnz release_return release_success: |