ref: 77c74d43d5540fd3bb3915d45d786986827ef0f8
dir: /lib/thread/mutex+linux.myr/
use std use sys use "atomic.use" pkg thread = type mutex = struct _state : int32 ;; const mkmtx : (-> mutex) const mtxlock : (mtx : mutex# -> void) const mtxtrylock : (mtx : mutex# -> bool) const mtxunlock : (mtx : mutex# -> void) ;; const Unlocked = 0 const Locked = 1 const Sleep = 2 generic Zptr = 0 castto(@a#) var nspin = 1 /* FIXME: pick a sane number, based on CPU count */ const mkmtx = { -> [._state = Unlocked] } const mtxlock = {mtx var c /* uncontended case: we get an unlocked mutex, and we lock it */ for var i = 0; i < nspin; i++ c = xcas(&mtx._state, Unlocked, Locked) if c == Unlocked -> ;; relax() ;; /* contended: we set the lock _state to sleep */ if c == Locked c = xchg(&mtx._state, Sleep) ;; while c != Unlocked sys.futex(&mtx._state, sys.Futexwait | sys.Futexpriv, Sleep, Zptr, Zptr, 0) c = xchg(&mtx._state, 2) ;; } const mtxtrylock = {mtx -> xcas(&mtx._state, Unlocked, Locked) == Unlocked } const mtxunlock = {mtx var r /* uncontended sleep means we can just unlock and move on */ if mtx._state == Sleep mtx._state = Unlocked elif xchg(&mtx._state, Unlocked) == Locked -> ;; for var i = 0; i < nspin; i++ if mtx._state != Unlocked /* there might have been waiters, but we set the _state to unlocked */ if xcas(&mtx._state, Locked, Sleep) == Sleep -> ;; ;; relax() ;; r = sys.futex(&mtx._state, sys.Futexwake | sys.Futexpriv, Locked, Zptr, Zptr, 0) } const relax = { }