global SPINLOCK_WAIT global SPINLOCK_WAIT2 global SPINLOCK_UNLOCK LOCKED EQU 1 UNLOCKED EQU 0 section .data section .bss ; this will lock and unlock a shared memory value ; rdi will hold the address of the shared memory ; pointers are passed as 64 bit (qword) values ; we expect that the lock variable is an int section .text SPINLOCK_WAIT: .top: mov eax, LOCKED ; swap LOCKED with the contents of [rdi], the lock variable ; tmp <- [rdi] ; [rdi] <- eax ; eax <- tmp lock xchg eax, [rdi] ; if it held unlocked, we can exit, if not, do it again ; ie if we swapped locked for locked, it was already locked ; ie it was locked, but we locked it. ; if we swapped unlocked for locked, it was unlocked but we locked it cmp eax, UNLOCKED jne .top ret ; this will also lock a shared memory location ; rdi also holds the addres of the lock SPINLOCK_WAIT2: mov ecx, LOCKED .top: ; this is a quick bypass, if it is locked, skip the next section cmp dword [rdi], LOCKED je .locked ; if it was unloced, we will attempt to lock it mov eax, UNLOCKED ; This will ; tmp = ecx (locked) ; if [rdi] = rax (ie memory holds unlocked) ; zf = 1 (we can jump on equal, we have the lock) ; [rdi] = exc (ie store LOCKED in the variable) ; else ; zf = 0 ; eax = tmp ; [rdi] = tmp lock cmpxchg dword [rdi], ecx ; if zf is set, jump to done. jz .done ; fall through, we did not lock .locked: ; a pause might be good here. jmp .top .done: ret ; rdi will hold the address of the lock variable SPINLOCK_UNLOCK: mov eax, UNLOCKED ; this can not be a mov, apparently MOV is not ALWAYS atomic ; lock is optional here, but probably good documentation at least lock xchg eax,[rdi] ret