Re:A collection of lock-free data structures written in stan...
by planede on Wednesday May 10, 2023 @08:44AM
(#35886506)
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.
[ Parent
| on HN ]
Re:A collection of lock-free data structures written in stan...
by kevincox on Wednesday May 10, 2023 @08:57AM
(#35886664)
Definitely not. I don't think there any many standard libraries that use syscalls for every lock. It is near universal to attempt a lock in user space (maybe even spin a few times) and only call the kernel if you need to wait. So low-contention locks should very rarely make a syscall.
Re:A collection of lock-free data structures written in stan...
by adzm on Wednesday May 10, 2023 @09:28AM
(#35887050)
Critical sections in Windows certainly behave this way with a configurable spin count.
Re:A collection of lock-free data structures written in stan...
by m4nu3l on Wednesday May 10, 2023 @10:30AM
(#35887924)
That's my understanding too. In Linux mutexes are implemented by futexes (Fast User-Space mutexes). If there is no contention they are guaranteed to not perform a syscall https://en.wikipedia.org/wiki/Futex
Re:A collection of lock-free data structures written in stan...
by cout on Wednesday May 10, 2023 @03:30PM
(#35892304)
Maybe this has changed, but last time I looked at futexes there was no syscall for locking (assuming no contention), but unlocking always made a syscall. This was many years ago so it could be different now.
Re:A collection of lock-free data structures written in stan...
by m4nu3l on Wednesday May 10, 2023 @03:58PM
(#35892665)
The code isn't the easiest to read but in glibc it seems that the syscall is only performed if waiters are detected in userspace during an unlock operation
https://github.com/lattera/glibc/blob/master/nptl/pthread_mu...
Re:A collection of lock-free data structures written in stan...
by gpderetta on Wednesday May 10, 2023 @05:34PM
(#35893836)
Indeed You only need to FUTEX_WAKE if you know there are waiters (or of you lost track of the number of waiters).
Re:A collection of lock-free data structures written in stan...
by m4nu3l on Wednesday May 10, 2023 @07:13PM
(#35894807)
What can cause the mutex to lose track of the number of waiters?
Re:A collection of lock-free data structures written in stan...
by ot on Wednesday May 10, 2023 @07:20PM
(#35894907)
Generally you have a small number of bits to count the waiters, because the mutex state has to be a word you can CAS and so you have either 32 or 64 bits to pack all the state you need. If your counter saturates you lose track of the waiters, and you have to fallback somehow.
Re:A collection of lock-free data structures written in stan...
by m4nu3l on Thursday May 11, 2023 @02:44AM
(#35898597)
Makes sense, thanks for the explanation!
Re:A collection of lock-free data structures written in stan...
by tialaramex on Wednesday May 10, 2023 @07:38PM
(#35895095)
Although it's not the code C++ will be using the Rust implementation is a bit easier to follow:
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.
Re:A collection of lock-free data structures written in stan...
by maldev on Wednesday May 10, 2023 @12:35PM
(#35889766)
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.