Moreover, is "every lock requires a syscall" accurate? Probably depends on target platform and standard library, but my impression was that at low contention it doesn't really require syscalls, at least on Linux and glibc's pthread.
https://github.com/lattera/glibc/blob/master/nptl/pthread_mu...
https://doc.rust-lang.org/src/std/sys/unix/locks/futex_mutex...
Unlock is just:: self.futex.swap(0, Release) -- if the value we get back is 2 then we know at least one thread is asleep waiting on this futex, so we need a system call to wake them, but in the uncontended case we're done immediately.
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.