lock.asm

URL: https://mirkwood.cs.edinboro.edu/~bennett/class/cmsc4000/spring2026/notes/ch6/code/lock.asm
 
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