shithub: mc

Download patch

ref: 8e0443da2f98080d20efe818af4184b5ccb2ce73
parent: 9e6818a65d84979ea268135890d43eb485d7c152
author: Ori Bernstein <[email protected]>
date: Mon Jan 4 18:05:41 EST 2016

Add umtx implementation of mutex.

	umtx... it's basically futex.

--- a/lib/thread/bld.proj
+++ b/lib/thread/bld.proj
@@ -10,6 +10,7 @@
 
 	# freebsd impl of thread primitives
 	spawn+freebsd.myr
+	mutex+freebsd.myr
 	exit+freebsd-x64.s
 
 	atomic-impl+x64.s
--- /dev/null
+++ b/lib/thread/mutex+freebsd.myr
@@ -1,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)
+}
+
--- a/lib/thread/mutex+linux.myr
+++ b/lib/thread/mutex+linux.myr
@@ -70,6 +70,7 @@
 		->
 	;;
 
+	/* wake one thread */
 	sys.futex(&mtx._state, sys.Futexwake | sys.Futexpriv, 1, Zptr, Zptr, 0)
 }