diff options
author | Ori Bernstein <ori@eigenstate.org> | 2016-01-04 23:05:41 -0800 |
---|---|---|
committer | Ori Bernstein <ori@eigenstate.org> | 2016-01-04 23:05:41 -0800 |
commit | 8e0443da2f98080d20efe818af4184b5ccb2ce73 (patch) | |
tree | 9b29d6f5105a2c5cc6e9d12911ba48a0e8648041 /lib/thread | |
parent | 9e6818a65d84979ea268135890d43eb485d7c152 (diff) | |
download | mc-8e0443da2f98080d20efe818af4184b5ccb2ce73.tar.gz |
Add umtx implementation of mutex.
umtx... it's basically futex.
Diffstat (limited to 'lib/thread')
-rw-r--r-- | lib/thread/bld.proj | 1 | ||||
-rw-r--r-- | lib/thread/mutex+freebsd.myr | 80 | ||||
-rw-r--r-- | lib/thread/mutex+linux.myr | 1 |
3 files changed, 82 insertions, 0 deletions
diff --git a/lib/thread/bld.proj b/lib/thread/bld.proj index 16ba36a..562cf29 100644 --- a/lib/thread/bld.proj +++ b/lib/thread/bld.proj @@ -10,6 +10,7 @@ lib thread = # freebsd impl of thread primitives spawn+freebsd.myr + mutex+freebsd.myr exit+freebsd-x64.s atomic-impl+x64.s diff --git a/lib/thread/mutex+freebsd.myr b/lib/thread/mutex+freebsd.myr new file mode 100644 index 0000000..61ba275 --- /dev/null +++ b/lib/thread/mutex+freebsd.myr @@ -0,0 +1,80 @@ +use std +use sys + +use "atomic.use" +use "common.use" + +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 = 0 + pkglocal const Locked = 1 + pkglocal const Contended = 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 + -> + ;; + ;; + + /* + 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.umtx_op( \ + &mtx._state castto(void#), \ + sys.Umtxwaituintpriv, \ + Contended castto(uint64), \ + 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 + -> + ;; + + /* wake all threads: for some reason nwake */ + sys.umtx_op(&mtx._state castto(void#), sys.Umtxwakepriv, 1, Zptr, Zptr) +} + diff --git a/lib/thread/mutex+linux.myr b/lib/thread/mutex+linux.myr index 7fd4270..3ce6d2a 100644 --- a/lib/thread/mutex+linux.myr +++ b/lib/thread/mutex+linux.myr @@ -70,6 +70,7 @@ const mtxunlock = {mtx -> ;; + /* wake one thread */ sys.futex(&mtx._state, sys.Futexwake | sys.Futexpriv, 1, Zptr, Zptr, 0) } |