shithub: mc

Download patch

ref: 2fca1caa1935baf0473efc367e24dab57c52517d
parent: 0bb2378d7e2b714998b34394f6977b2ead023d6c
author: iriri <iri@konnichiwastevenspielbergde.su>
date: Sat Aug 18 12:17:42 EDT 2018

Fix futex timeouts and handle futex error codes.

--- a/lib/sys/sys+freebsd-x64.myr
+++ b/lib/sys/sys+freebsd-x64.myr
@@ -582,10 +582,10 @@
 	;;
 	
 	const Umtxabstime = 1
-	type _umtx_time = struct
-		_timeout	: timespec
-		_flags		: uint32
-		_clockid	: uint32
+	type umtx_time = struct
+		timeout	: timespec
+		flags	: uint32
+		clockid	: uint32
 	;;
 	
 	/* open options */
@@ -1192,6 +1192,7 @@
 		const getsockopt	: (sock : fd, lev : sockproto, opt : sockopt, val : void#, len : size# -> int)
 		const munmap	: (addr:byte#, len:size -> int64)
 		const mmap	: (addr:byte#, len:size, prot:mprot, flags:mopt, fd:fd, off:off -> byte#)
+		const clockid		: (clk : clock -> uint64)
 		const clock_getres	: (clk : clock, ts : timespec# -> int32)
 		const clock_gettime	: (clk : clock, ts : timespec# -> int32)
 		const clock_settime	: (clk : clock, ts : timespec# -> int32)
--- a/lib/sys/sys+linux-x64.myr
+++ b/lib/sys/sys+linux-x64.myr
@@ -563,6 +563,8 @@
 	const Futexpriv	: futexop = 128
 	const Futexclockrt	: futexop = 256
 	
+	const Futexbitsetmatchany : int32 = -1
+	
 	/* poll events : posix */
 	const Pollin	: pollevt = 0x001	/* There is data to read.  */
 	const Pollpri	: pollevt = 0x002	/* There is urgent data to read.  */
@@ -1273,7 +1275,7 @@
 	const dup	: (fd : fd -> fd)
 	const dup2	: (src : fd, dst : fd -> fd)
 	const futex	: (uaddr : int32#, op : futexop, val : int32, \
-	timeout : timespec#, uaddr2 : int32#, val3 : int32 -> int64)
+		timeout : timespec#, uaddr2 : int32#, val3 : int32 -> int)
 	const semctl	:  (semid : int, semnum : int, cmd : int, arg : void# -> int)
 	const epollcreate	: (flg : epollflags	-> fd)	/* actually epoll_create1 */
 	const epollctl	: (epfd : fd, op : int, fd : fd, evt : epollevt# -> int)
@@ -1692,7 +1694,7 @@
 	
 	/* threading */
 	const futex	= {uaddr, op, val, timeout, uaddr2, val3
-		-> syscall(Sysfutex, a(uaddr), a(op), a(val), a(timeout), a(uaddr2), a(val3))
+		-> (syscall(Sysfutex, a(uaddr), a(op), a(val), a(timeout), a(uaddr2), a(val3)) : int)
 	}
 	const semctl	= {semid, semnum, cmd, arg
 		-> (syscall(Syssemctl, a(semnum), a(cmd), a(arg)) : int)
--- a/lib/thread/condvar+freebsd.myr
+++ b/lib/thread/condvar+freebsd.myr
@@ -1,7 +1,6 @@
 use std
 
 use "atomic"
-use "common"
 use "mutex"
 use "futex"
 
@@ -22,19 +21,17 @@
 }
 
 const condwait = {cond
-	var seq
-	var mtx
+	var mtx = cond._mtx
+	var seq = xget(&cond._seq)
 
-	mtx = cond._mtx
-	seq = cond._seq
 	mtxunlock(mtx)
+	ftxwait(&cond._seq, seq, -1)
 
 	/*
-	FIXME?: `ftxwait` can be interrupted but `condwait` should always be
-	done in a loop anyway.
+	In the event of a broadcast, we aren't requeueing waiters from the
+	condvar's futex to the mutex's futex so we can just reacquire the mutex
+	normally.
 	*/
-	ftxwait(&cond._seq, seq, Zptr)
-
 	mtxlock(mtx)
 }
 
--- a/lib/thread/condvar+linux.myr
+++ b/lib/thread/condvar+linux.myr
@@ -3,12 +3,13 @@
 
 use "atomic"
 use "common"
+use "futex"
 use "mutex"
 
 pkg thread =
 	type cond = struct
 		_mtx	: mutex#
-		_seq	: int32
+		_seq	: ftxtag
 	;;
 
 	const mkcond	: (mtx : mutex# -> cond)
@@ -22,30 +23,24 @@
 }
 
 const condwait = {cond
-	var seq
-	var mtx
+	var mtx = cond._mtx
+	var seq = xget(&cond._seq)
 
-	mtx = cond._mtx
-	seq = cond._seq
 	mtxunlock(mtx)
+	ftxwait(&cond._seq, seq, -1)
 
 	/*
-	FIXME?: `futex` can be interrupted but `condwait` should always be done
-	in a loop anyway.
+	In the event of a broadcast, we need to atomically set the mutex to
+	contended. This allows us to pass responsibility for waking up the
+	potential other waiters from the requeue operation on to the unlocker
+	of the mutex.
 	*/
-	sys.futex(&cond._seq, sys.Futexwait | sys.Futexpriv, seq, Zptr, Zptr, 0)
-
-	/*
-	We need to atomically set the mutex to contended. This allows us to
-	pass responsibility for waking up the potential other waiters on to the
-	unlocker of the mutex.
-	*/
 	mtxcontended(mtx)
 }
 
 const condsignal = {cond : cond#
 	xadd(&cond._seq, 1)
-	sys.futex(&cond._seq, sys.Futexwake | sys.Futexpriv, 1, Zptr, Zptr, 0)
+	ftxwake(&cond._seq)
 }
 
 const condbroadcast = {cond : cond#
@@ -55,7 +50,7 @@
 	used for the number of threads to move, and is not ignored when
 	requeueing
 	*/
-	sys.futex(&cond._seq, sys.Futexrequeue | sys.Futexpriv,
+	sys.futex((&cond._seq : int32#), sys.Futexrequeue | sys.Futexpriv,
 		1, (0x7fffffff : sys.timespec#),
 		(&cond._mtx._state : int32#), 0)
 }
--- a/lib/thread/condvar+openbsd:6.2.myr
+++ b/lib/thread/condvar+openbsd:6.2.myr
@@ -3,12 +3,13 @@
 
 use "atomic"
 use "common"
+use "futex"
 use "mutex"
 
 pkg thread =
 	type cond = struct
 		_mtx	: mutex#
-		_seq	: uint32
+		_seq	: ftxtag
 	;;
 
 	const mkcond	: (mtx : mutex# -> cond)
@@ -22,35 +23,29 @@
 }
 
 const condwait = {cond
-	var seq : uint32
-	var mtx
+	var mtx = cond._mtx
+	var seq = xget(&cond._seq)
 
-	mtx = cond._mtx
-	seq = cond._seq
 	mtxunlock(mtx)
+	ftxwait(&cond._seq, seq, -1)
 
 	/*
-	FIXME?: `futex` can be interrupted but `condwait` should always be done
-	in a loop anyway.
+	In the event of a broadcast, we need to atomically set the mutex to
+	contended. This allows us to pass responsibility for waking up the
+	potential other waiters from the requeue operation on to the unlocker
+	of the mutex.
 	*/
-	sys.futex(&cond._seq, sys.Futexwait, (seq : int), Zptr, Zptr)
-
-	/*
-	We need to atomically set the mutex to contended. This allows us to
-	pass responsibility for waking up the potential other waiters on to the
-	unlocker of the mutex.
-	*/
 	mtxcontended(mtx)
 }
 
 const condsignal = {cond : cond#
 	xadd(&cond._seq, 1)
-	sys.futex(&cond._seq, sys.Futexwake, 1, Zptr, Zptr)
+	ftxwake(&cond._seq)
 }
 
 const condbroadcast = {cond : cond#
 	xadd(&cond._seq, 1)
-	sys.futex(&cond._seq, sys.Futexrequeue, 1,
+	sys.futex((&cond._seq : uint32#), sys.Futexrequeue, 1,
 		(0x7fffffff : sys.timespec#),
 		(&cond._mtx._state : uint32#))
 }
--- a/lib/thread/condvar+osx.myr
+++ b/lib/thread/condvar+osx.myr
@@ -1,7 +1,6 @@
 use std
 
 use "atomic"
-use "common"
 use "mutex"
 use "futex"
 
@@ -22,19 +21,17 @@
 }
 
 const condwait = {cond
-	var seq
-	var mtx
+	var mtx = cond._mtx
+	var seq = xget(&cond._seq)
 
-	mtx = cond._mtx
-	seq = cond._seq
 	mtxunlock(mtx)
+	ftxwait(&cond._seq, seq, -1)
 
 	/*
-	FIXME?: `ftxwait` can be interrupted but `condwait` should always be
-	done in a loop anyway.
+	In the event of a broadcast, we aren't requeueing waiters from the
+	condvar's futex to the mutex's futex so we can just reacquire the mutex
+	normally.
 	*/
-	ftxwait(&cond._seq, seq, Zptr)
-
 	mtxlock(mtx)
 }
 
--- a/lib/thread/condvar.myr
+++ b/lib/thread/condvar.myr
@@ -8,7 +8,8 @@
 pkg thread =
 	type cond = struct
 		_mtx	: mutex#
-		_waitq	: condwaiter#
+		_head	: condwaiter#
+		_tail	: condwaiter#
 		_lock	: mutex
 	;;
 
@@ -18,15 +19,8 @@
 	const condbroadcast	: (cond : cond# -> void)
 ;;
 
-/*
-The waitqueue is a doubly-linked list because we'll need to remove waiters from
-anywhere in the list when we add timeout support.
-
-`cond._waitq.prev` is the tail of the queue.
-*/
 type condwaiter = struct
 	next : condwaiter#
-	prev : condwaiter#
 	sem : sem
 ;;
 
@@ -40,14 +34,9 @@
 	var waiter = std.mk([.sem = mksem(0)])
 
 	mtxlock(lock)
-	match cond._waitq
-	| Zptr:
-		waiter.prev = waiter
-		cond._waitq = waiter
-	| q:
-		waiter.prev = q.prev
-		waiter.prev.next = waiter
-		q.prev = waiter
+	match cond._tail
+	| Zptr: cond._head = cond._tail = waiter
+	| tail: cond._tail = tail.next = waiter
 	;;
 
 	mtxunlock(lock)
@@ -61,13 +50,13 @@
 	var lock = &cond._lock
 
 	mtxlock(lock)
-	var head = cond._waitq
+	var head = cond._head
 	if head != Zptr
-		if head.next != Zptr
-			head.next.prev = head.prev
-		;;
-		cond._waitq = head.next
+		cond._head = head.next
 		sempost(&head.sem)
+		if cond._head == Zptr
+			cond._tail = Zptr
+		;;
 	;;
 	mtxunlock(lock)
 }
@@ -81,9 +70,10 @@
 	var head = Zptr
 
 	mtxlock(lock)
-	while (head = cond._waitq) != Zptr
-		cond._waitq = head.next
+	while (head = cond._head) != Zptr
+		cond._head = head.next
 		sempost(&head.sem)
 	;;
+	cond._tail = Zptr
 	mtxunlock(lock)
 }
--- a/lib/thread/futex+freebsd.myr
+++ b/lib/thread/futex+freebsd.myr
@@ -1,3 +1,4 @@
+use std
 use sys
 
 use "atomic"
@@ -7,34 +8,53 @@
 	type ftxtag = uint32
 	impl atomic ftxtag
 
-	const ftxwait : (uaddr : ftxtag#, val : ftxtag, timeout : sys.timespec# -> int)
-	const ftxwake : (uaddr : ftxtag# -> int)
-	const ftxwakeall : (uaddr : ftxtag# -> int)
+	const ftxwait : (uaddr : ftxtag#, val : ftxtag, tmout : std.time -> sys.errno)
+	const ftxwake : (uaddr : ftxtag# -> void)
+	const ftxwakeall : (uaddr : ftxtag# -> void)
 ;;
 
-const ftxwait = {uaddr, val, timeout
-	if timeout == Zptr
-		-> sys.umtx_op((uaddr : void#), sys.Umtxwaituintpriv, (val : uint64), Zptr, Zptr)
+const ftxwait = {uaddr, val, tmout
+	var ut : sys.umtx_time, utp, utsize, rc
+
+	if tmout < 0
+		utp = Zptr
+		utsize = Zptr
+	else
+		var t = (tmout : int64)
+		std.assert(sys.clock_gettime(`sys.Clockmonotonic, &ut.timeout) == 0,
+			"error: clock_gettime returned -1\n")
+		ut.timeout.nsec += (t % 1_000_000) * 1000
+		ut.timeout.sec += (ut.timeout.nsec / 1_000_000_000) + (t / 1_000_000)
+		ut.timeout.nsec %= 1_000_000_000
+		ut.flags = (sys.Umtxabstime : uint32)
+		ut.clockid = (sys.clockid(`sys.Clockmonotonic) : uint32)
+		utp = (&ut : void#)
+		utsize = (sizeof(sys.umtx_time) : void#)
 	;;
 
-	var ut : sys._umtx_time = [
-		._timeout = timeout#,
-		._flags = (sys.Umtxabstime : uint32),
-		._clockid = 1, /* CLOCK_MONOTONIC. Not exported from sys. */
-	]
-	-> sys.umtx_op((uaddr : void#),
-		sys.Umtxwaituintpriv,
-		(val : uint64),
-		(sizeof(sys._umtx_time) : void#),
-		(&ut : void#))
+	while (rc = (sys.umtx_op((uaddr : void#),
+			sys.Umtxwaituintpriv,
+			(val : uint64),
+			utsize,
+			utp) : sys.errno)) == sys.Eintr
+	;;
+
+	match rc
+	| 0: -> 0
+	| sys.Eagain: -> sys.Eagain
+	| sys.Etimedout: -> sys.Etimedout
+	| err:
+		std.fput(2, "error: umtx_op returned {}\n", err)
+		std.suicide()
+	;;
 }
 
 const ftxwake = {uaddr
-	-> sys.umtx_op((uaddr : void#), sys.Umtxwakepriv, 1, Zptr, Zptr)
+	sys.umtx_op((uaddr : void#), sys.Umtxwakepriv, 1, Zptr, Zptr)
 }
 
 const ftxwakeall = {uaddr
-	-> sys.umtx_op((uaddr : void#), sys.Umtxwakepriv, 0x7fffffff, Zptr, Zptr)
+	sys.umtx_op((uaddr : void#), sys.Umtxwakepriv, 0x7fffffff, Zptr, Zptr)
 }
 
 impl atomic ftxtag =
--- a/lib/thread/futex+linux.myr
+++ b/lib/thread/futex+linux.myr
@@ -1,3 +1,4 @@
+use std
 use sys
 
 use "atomic"
@@ -7,26 +8,60 @@
 	type ftxtag = uint32
 	impl atomic ftxtag
 
-	const ftxwait : (uaddr : ftxtag#, val : ftxtag, timeout : sys.timespec# -> int)
-	const ftxwake : (uaddr : ftxtag# -> int)
-	const ftxwakeall : (uaddr : ftxtag# -> int)
+	const ftxwait : (uaddr : ftxtag#, val : ftxtag, tmout : std.time -> sys.errno)
+	const ftxwake : (uaddr : ftxtag# -> void)
+	const ftxwakeall : (uaddr : ftxtag# -> void)
 ;;
 
-const ftxwait = {uaddr, val, timeout
-	-> (sys.futex((uaddr : int32#),
-		sys.Futexwait | sys.Futexpriv,
-		(val : int32),
-		timeout,
-		Zptr,
-		0) : int)
+const ftxwait = {uaddr, val, tmout
+	var rc
+
+	if tmout < 0
+		while (rc = (sys.futex((uaddr : int32#),
+				sys.Futexwait | sys.Futexpriv,
+				(val : int32),
+				Zptr,
+				Zptr,
+				0) : sys.errno)) == sys.Eintr
+		;;
+	else
+		var t = (tmout : int64)
+		var ts
+		std.assert(sys.clock_gettime(`sys.Clockmonotonic, &ts) == 0,
+			"error: clock_gettime returned -1\n")
+		ts.nsec += (t % 1_000_000) * 1000
+		ts.sec += (ts.nsec / 1_000_000_000) + (t / 1_000_000)
+		ts.nsec %= 1_000_000_000
+
+		/*
+		Futexwaitbitset + Futexbitsetmatchany causes the timeout to be
+		treated as absolute rather than relative.
+		*/
+		while (rc = (sys.futex((uaddr : int32#),
+				sys.Futexwaitbitset | sys.Futexpriv,
+				(val : int32),
+				&ts,
+				Zptr,
+				sys.Futexbitsetmatchany) : sys.errno)) == sys.Eintr
+		;;
+	;;
+
+	match rc
+	| 0: -> 0
+	| sys.Eagain: -> sys.Eagain
+	| sys.Etimedout: -> sys.Etimedout
+	| err:
+		std.fput(2, "error: futex returned {}\n", err)
+		std.suicide()
+	;;
 }
 
 const ftxwake = {uaddr
-	-> (sys.futex((uaddr : int32#), sys.Futexwake | sys.Futexpriv, 1, Zptr, Zptr, 0) : int)
+	sys.futex((uaddr : int32#), sys.Futexwake | sys.Futexpriv, 1, Zptr, Zptr, 0)
 }
 
 const ftxwakeall = {uaddr
-	-> (sys.futex((uaddr : int32#), sys.Futexwake | sys.Futexpriv, 0x7fffffff, Zptr, Zptr, 0) : int)
+	sys.futex((uaddr : int32#), sys.Futexwake | sys.Futexpriv, 0x7fffffff, Zptr, Zptr, 0)
 }
 
 impl atomic ftxtag =
--- a/lib/thread/futex+openbsd:6.2.myr
+++ b/lib/thread/futex+openbsd:6.2.myr
@@ -1,3 +1,4 @@
+use std
 use sys
 
 use "atomic"
@@ -7,21 +8,78 @@
 	type ftxtag = uint32
 	impl atomic ftxtag
 
-	const ftxwait : (uaddr : ftxtag#, val : ftxtag, timeout : sys.timespec# -> int)
-	const ftxwake : (uaddr : ftxtag# -> int)
-	const ftxwakeall : (uaddr : ftxtag# -> int)
+	const ftxwait : (uaddr : ftxtag#, val : ftxtag, tmout : std.time -> sys.errno)
+	const ftxwake : (uaddr : ftxtag# -> void)
+	const ftxwakeall : (uaddr : ftxtag# -> void)
 ;;
 
-const ftxwait = {uaddr, val, timeout
-	-> sys.futex((uaddr : uint32#), sys.Futexwait, (val : int), timeout, Zptr)
+const ftxwait = {uaddr, val, tmout
+	var rc
+
+	if tmout < 0
+		while (rc = (sys.futex((uaddr : uint32#),
+				sys.Futexwait,
+				(val : int),
+				Zptr,
+				Zptr) : sys.errno)) == sys.Eintr
+		;;
+	else
+		var t = (tmout : int64)
+		var start
+		std.assert(sys.clock_gettime(`sys.Clockmonotonic, &start) == 0,
+			"error: clock_gettime returned -1\n")
+		var ts = [
+			.sec = t / 1_000_000,
+			.nsec = (t % 1_000_000) * 1000,
+		]
+
+		while (rc = (sys.futex((uaddr : uint32#),
+				sys.Futexwait,
+				(val : int),
+				&ts,
+				Zptr) : sys.errno)) == sys.Eintr
+			var now
+			std.assert(sys.clock_gettime(`sys.Clockmonotonic, &now) == 0,
+				"error: clock_gettime returned -1\n")
+			var t1 = t - ((now.sec - start.sec) * 1_000_000)
+			var nsec = now.nsec - start.nsec
+			if nsec >= 0
+				t1 -= nsec / 1000
+			else
+				t1 -= (1_000_000_000 + nsec) / 1000
+			;;
+
+			if t1 > t
+				-> sys.Etimedout
+			;;
+			ts.sec = t1 / 1_000_000
+			ts.nsec = (t1 % 1_000_000) * 1000
+			t = t1
+		;;
+	;;
+
+	/* 
+	 * Since Myrddin uses the convention that negative
+	 * values flag an error, but futexes just return a
+	 * positive, non-errno value, we need to match against
+	 * the positive value.
+	 */
+	match rc
+	| 0: -> 0
+	| -sys.Eagain:	-> sys.Eagain
+	| -sys.Etimedout: -> sys.Etimedout
+	| err:
+		std.fput(2, "error: futex returned {}\n", err)
+		std.suicide()
+	;;
 }
 
 const ftxwake = {uaddr
-	-> sys.futex((uaddr : uint32#), sys.Futexwake, 1, Zptr, Zptr)
+	sys.futex((uaddr : uint32#), sys.Futexwake, 1, Zptr, Zptr)
 }
 
 const ftxwakeall = {uaddr
-	-> sys.futex((uaddr : uint32#), sys.Futexwake, 0x7fffffff, Zptr, Zptr)
+	sys.futex((uaddr : uint32#), sys.Futexwake, 0x7fffffff, Zptr, Zptr)
 }
 
 impl atomic ftxtag =
--- a/lib/thread/futex+osx.myr
+++ b/lib/thread/futex+osx.myr
@@ -8,9 +8,9 @@
 	type ftxtag = uint64
 	impl atomic ftxtag
 
-	const ftxwait : (uaddr : ftxtag#, val : ftxtag, timeout : sys.timespec# -> int)
-	const ftxwake : (uaddr : ftxtag# -> int)
-	const ftxwakeall : (uaddr : ftxtag# -> int)
+	const ftxwait : (uaddr : ftxtag#, val : ftxtag, tmout : std.time -> sys.errno)
+	const ftxwake : (uaddr : ftxtag# -> void)
+	const ftxwakeall : (uaddr : ftxtag# -> void)
 ;;
 
 /*
@@ -17,40 +17,63 @@
  * The ulock_ functions are undocumented but the relevant source can be found at
  * https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/kern/sys_ulock.c
  */
-const ftxwait = {uaddr, val, timeout
-	if timeout == Zptr
-		-> sys.ulock_wait(sys.Ulockcompareandwait, (uaddr : uint64#), (val : uint64), 0)
-	;;
+const ftxwait = {uaddr, val, tmout
+	var rc
 
-	var ts
-	var err = sys.clock_gettime(`sys.Clockmonotonic, &ts)
-	std.assert(err == 0, "error: clock_gettime returned {}\n", err)
-	if timeout.sec < ts.sec
-		-> (std.Etimedout : int)
-	;;
+	if tmout < 0
+		while (rc = (sys.ulock_wait(sys.Ulockcompareandwait,
+				(uaddr : uint64#),
+				(val : uint64),
+				0) : sys.errno)) == sys.Eintr
+		;;
+	else
+		var start, t
+		std.assert(tmout <= 0xffffffff, "error: maximum os x futex timeout exceeded\n")
+		std.assert(sys.clock_gettime(`sys.Clockmonotonic, &start) == 0,
+			"error: clock_gettime returned -1\n")
+		t = (tmout : uint32)
 
-	var usec = 0
-	var sec = (timeout.sec - ts.sec) * 1000
-	std.assert(sec <= 0xffffffff, "error: maximum futex timeout exceeded\n")
-	usec = (sec : uint32)
-	if timeout.nsec > ts.nsec
-		var nsec = (timeout.nsec - ts.nsec) / 1000
-		std.assert(usec + nsec > usec, "error: maximum futex timeout exceeded\n")
-		usec += nsec
+		while (rc = (sys.ulock_wait(sys.Ulockcompareandwait,
+				(uaddr : uint64#),
+				(val : uint64),
+				t) : sys.errno)) == sys.Eintr
+			var now
+			std.assert(sys.clock_gettime(`sys.Clockmonotonic, &now) == 0,
+				"error: clock_gettime returned -1\n")
+			var t1 = t - (((now.sec - start.sec) * 1_000_000) : uint32)
+			var nsec = now.nsec - start.nsec
+			if nsec >= 0
+				t1 -= (nsec / 1000 : uint32)
+			else
+				t1 -= ((1_000_000_000 + nsec) / 1000 : uint32)
+			;;
+
+			if t1 > t
+				-> sys.Etimedout
+			;;
+			t = t1
+		;;
 	;;
 
-	if usec == 0
-		-> (std.Etimedout : int)
+	match rc
+	| 0: -> 0
+	| sys.Eagain: -> sys.Eagain
+	| sys.Etimedout: -> sys.Etimedout
+	| err:
+		if err > 0
+			-> 0
+		;;
+		std.fput(2, "error: ulock_wait returned {}\n", err)
+		std.suicide()
 	;;
-	-> sys.ulock_wait(sys.Ulockcompareandwait, (uaddr : uint64#), (val : uint64), usec)
 }
 
 const ftxwake = {uaddr
-	-> sys.ulock_wake(sys.Ulockcompareandwait, (uaddr : uint64#), 0)
+	sys.ulock_wake(sys.Ulockcompareandwait, (uaddr : uint64#), 0)
 }
 
 const ftxwakeall = {uaddr
-	-> sys.ulock_wake(sys.Ulockcompareandwait | sys.Ulockulfwakeall, (uaddr : uint64#), 0)
+	sys.ulock_wake(sys.Ulockcompareandwait | sys.Ulockulfwakeall, (uaddr : uint64#), 0)
 }
 
 impl atomic ftxtag =
--- a/lib/thread/mutex+futex.myr
+++ b/lib/thread/mutex+futex.myr
@@ -1,5 +1,4 @@
 use "atomic"
-use "common"
 use "futex"
 
 pkg thread =
@@ -28,12 +27,12 @@
 const mtxlock = {mtx
 	var c
 
-	/* 
+	/*
 	Uncontended case: we get an unlocked mutex, and we lock it.
 	*/
-        c = Locked
+	c = Locked
 	for var i = 0; i < nspin; i++
-		c = xcas(&mtx._state, Unlocked, Locked) 
+		c = xcas(&mtx._state, Unlocked, Locked)
 		if c == Unlocked
 			-> void
 		;;
@@ -49,7 +48,7 @@
 	;;
 
 	while c != Unlocked
-		ftxwait(&mtx._state, Contended, Zptr)
+		ftxwait(&mtx._state, Contended, -1)
 		c = xchg(&mtx._state, Contended)
 	;;
 }
@@ -74,6 +73,6 @@
 
 const mtxcontended = {mtx
 	while xchg(&mtx._state, Contended) != Unlocked
-		ftxwait(&mtx._state, Contended, Zptr)
+		ftxwait(&mtx._state, Contended, -1)
 	;;
 }
--- a/lib/thread/mutex+plan9.myr
+++ b/lib/thread/mutex+plan9.myr
@@ -1,9 +1,7 @@
 use std
 use sys
 
-
 use "atomic"
-use "common"
 
 pkg thread =
 	type mutex = struct
--- a/lib/thread/mutex.myr
+++ b/lib/thread/mutex.myr
@@ -1,9 +1,7 @@
 use std
 use sys
 
-
 use "atomic"
-use "common"
 
 pkg thread =
 	type mutex = struct
--- a/lib/thread/sem+futex.myr
+++ b/lib/thread/sem+futex.myr
@@ -1,7 +1,6 @@
 use std
 
 use "atomic"
-use "common"
 use "futex"
 
 pkg thread =
@@ -28,7 +27,7 @@
 				-> void
 			;;
 		;;
-		ftxwait(&s._val, v, Zptr)
+		ftxwait(&s._val, v, -1)
 	;;
 }
 
--- a/lib/thread/sem+plan9.myr
+++ b/lib/thread/sem+plan9.myr
@@ -2,7 +2,6 @@
 use sys
 
 use "atomic"
-use "common"
 
 pkg thread =
 	type sem = struct
--- a/lib/thread/waitgrp+futex.myr
+++ b/lib/thread/waitgrp+futex.myr
@@ -1,7 +1,6 @@
 use std
 
 use "atomic"
-use "common"
 use "futex"
 
 pkg thread =
@@ -22,7 +21,7 @@
 	var v = 0
 
 	while (v = xget(&w._val)) != 0
-		ftxwait(&w._val, v, Zptr)
+		ftxwait(&w._val, v, -1)
 	;;
 }
 
--- a/support/syscall-gen/specials+freebsd-x64.frag
+++ b/support/syscall-gen/specials+freebsd-x64.frag
@@ -65,6 +65,7 @@
 	const mmap	: (addr:byte#, len:size, prot:mprot, flags:mopt, fd:fd, off:off -> byte#)
 
 	/* time - doublecheck if this is right */
+	const clockid		: (clk : clock -> uint64)
 	const clock_getres	: (clk : clock, ts : timespec# -> int32)
 	const clock_gettime	: (clk : clock, ts : timespec# -> int32)
 	const clock_settime	: (clk : clock, ts : timespec# -> int32)
--- a/support/syscall-gen/specials+linux-x64.frag
+++ b/support/syscall-gen/specials+linux-x64.frag
@@ -62,7 +62,7 @@
 
 /* threading */
 const futex	: (uaddr : int32#, op : futexop, val : int32, \
-	timeout : timespec#, uaddr2 : int32#, val3 : int32 -> int64)
+	timeout : timespec#, uaddr2 : int32#, val3 : int32 -> int)
 const semctl	:  (semid : int, semnum : int, cmd : int, arg : void# -> int)
 
 /* polling */
@@ -205,7 +205,7 @@
 
 /* threading */
 const futex	= {uaddr, op, val, timeout, uaddr2, val3
-	-> syscall(Sysfutex, a(uaddr), a(op), a(val), a(timeout), a(uaddr2), a(val3))
+	-> (syscall(Sysfutex, a(uaddr), a(op), a(val), a(timeout), a(uaddr2), a(val3)) : int)
 }
 const semctl	= {semid, semnum, cmd, arg
 	-> (syscall(Syssemctl, a(semnum), a(cmd), a(arg)) : int)
--- a/support/syscall-gen/types+freebsd-x64.frag
+++ b/support/syscall-gen/types+freebsd-x64.frag
@@ -575,6 +575,13 @@
 	node				: uint8[_Uuidnodesz];
 ;;
 
+const Umtxabstime = 1
+type umtx_time = struct
+	timeout	: timespec
+	flags	: uint32
+	clockid	: uint32
+;;
+
 /* open options */
 const Ordonly  	: fdopt = 0x0
 const Owronly  	: fdopt = 0x1
--- a/support/syscall-gen/types+linux-x64.frag
+++ b/support/syscall-gen/types+linux-x64.frag
@@ -556,6 +556,8 @@
 const Futexpriv	: futexop = 128
 const Futexclockrt	: futexop = 256
 
+const Futexbitsetmatchany : int32 = -1
+
 /* poll events : posix */
 const Pollin	: pollevt = 0x001	/* There is data to read.  */
 const Pollpri	: pollevt = 0x002	/* There is urgent data to read.  */