summaryrefslogtreecommitdiff
path: root/lib/thread
diff options
context:
space:
mode:
authorOri Bernstein <ori@eigenstate.org>2016-01-04 23:05:41 -0800
committerOri Bernstein <ori@eigenstate.org>2016-01-04 23:05:41 -0800
commit8e0443da2f98080d20efe818af4184b5ccb2ce73 (patch)
tree9b29d6f5105a2c5cc6e9d12911ba48a0e8648041 /lib/thread
parent9e6818a65d84979ea268135890d43eb485d7c152 (diff)
downloadmc-8e0443da2f98080d20efe818af4184b5ccb2ce73.tar.gz
Add umtx implementation of mutex.
umtx... it's basically futex.
Diffstat (limited to 'lib/thread')
-rw-r--r--lib/thread/bld.proj1
-rw-r--r--lib/thread/mutex+freebsd.myr80
-rw-r--r--lib/thread/mutex+linux.myr1
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)
}