diff options
Diffstat (limited to 'lib/thread/mutex+openbsd:6.2.myr')
-rw-r--r-- | lib/thread/mutex+openbsd:6.2.myr | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/lib/thread/mutex+openbsd:6.2.myr b/lib/thread/mutex+openbsd:6.2.myr new file mode 100644 index 0000000..f2648f5 --- /dev/null +++ b/lib/thread/mutex+openbsd:6.2.myr @@ -0,0 +1,76 @@ +use std +use sys + +use "atomic" +use "common" + +pkg thread = + type mutex = struct + _state : uint32 + ;; + + const mkmtx : (-> mutex) + const mtxlock : (mtx : mutex# -> void) + const mtxtrylock : (mtx : mutex# -> bool) + const mtxunlock : (mtx : mutex# -> void) + + pkglocal const Unlocked : uint32 = 0 + pkglocal const Locked : uint32 = 1 + pkglocal const Contended : uint32 = 2 +;; + +var nspin = 10 /* 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. + */ + c = Locked + for var i = 0; i < nspin; i++ + c = xcas(&mtx._state, Unlocked, Locked) + if c == Unlocked + -> void + ;; + ;; + + /* + Contended case: we set the lock state to Contended. This indicates that there + the lock is locked, and we potentially have threads waiting on it, which means + that we will need to wake them up. + */ + if c == Locked + c = xchg(&mtx._state, Contended) + ;; + + while c != Unlocked + sys.futex(&mtx._state, sys.Futexwait, (Contended : int), Zptr, Zptr) + c = xchg(&mtx._state, Contended) + ;; +} + +const mtxtrylock = {mtx + -> xcas(&mtx._state, Unlocked, Locked) == Unlocked +} + +const mtxunlock = {mtx + /* + Uncontended case: If the mutex state is not contended, and we still + are uncontended by the xchg() call, then it's safe to simply return; + nobody was waiting for us. + */ + if mtx._state == Contended + mtx._state = Unlocked + elif xchg(&mtx._state, Unlocked) == Locked + -> void + ;; + + /* wake one thread */ + sys.futex(&mtx._state, sys.Futexwake, 1, Zptr, Zptr) +} + |