You can literally just do an atomic swap on some memory location. Three lines of assembly, like.
mov rax, 1 ; load the value to exchange into rax
acquire_lock:
; attempt to acquire the lock
xchg byte [ADDR_LOCK], al ; atomically swap the lock value with rax
test al, al ; test if the original lock value was 0 (unlocked)
jnz acquire_lock ; if it was not, loop until we can acquire the lock
The downside is you want a backoff to sleep the thread so it doesn't go into a loop. But the actual lock code is simple. You can easily have this be your function "AcquireLock()" and then dowhile(!AcquireLock()) { //pause thread execution. }
And I think this is where they get the syscall being needed, since this will normally require a syscall to pause the thread from the scheduler.