shithub: mc

ref: d7740736da8f2ca830d558cdedd89266b9019375
dir: /lib/thread/futex+openbsd:6.2.myr/

View raw version
use std
use sys

use "atomic"
use "common"

pkg thread =
	type ftxtag = uint32
	impl atomic ftxtag

	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, 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)
}

const ftxwakeall = {uaddr
	sys.futex((uaddr : uint32#), sys.Futexwake, 0x7fffffff, Zptr, Zptr)
}

impl atomic ftxtag =
	xget = {p; -> (xget32((p : uint32#)) : ftxtag)}
	xset = {p, v; xset32((p : uint32#), (v : uint32))}
	xadd = {p, v; -> (xadd32((p : uint32#), (v : uint32)) : ftxtag)}
	xcas = {p, old, new; -> (xcas32((p : uint32#), (old : uint32), (new : uint32)) : ftxtag)}
	xchg = {p, v; -> (xchg32((p : uint32#), (v : uint32)) : ftxtag)}
;;