shithub: mc

ref: 48434f5600e0d0096226462e4fe1e55270e1eb0d
dir: /lib/std/wait+plan9.myr/

View raw version
use sys

use "alloc"
use "chartype"
use "die"
use "extremum"
use "hashfuncs"
use "hasprefix"
use "htab"
use "intparse"
use "option"
use "strsplit"
use "striter"
use "syswrap"
use "utf"
use "sleq"
use "fmt"
use "threadhooks"

pkg std =
	type waitstatus = union
		`Wsuccess
		`Wfailure
		`Wsignalled
		`Waiterror
	;;

	const wait	: (pid : pid -> waitstatus)
	const waitany	: (-> (pid, waitstatus))
;;

var statusmap	: htab(pid, waitstatus)#

const __init__ = {
	statusmap = mkht(inthash, inteq)
}

const waitany = {
	var buf : byte[512]
	var ret, it

	lock(envlck)
	if htcount(statusmap) == 0
		unlock(envlck)
		match sys.await(buf[:])
		| -1:	-> (-1, `Waiterror)
		| n:	-> parsestatus(buf[:n])
		;;
	else
		it = std.byhtkeyvals(statusmap)
		__iternext__(&it, &ret)
		unlock(envlck)
		-> ret
	;;
}

const wait = {pid
	var buf : byte[512]
	var xpid, status

	lock(envlck)
	match htget(statusmap, pid)
	| `None:
	| `Some st:
		unlock(envlck)
		htdel(statusmap, pid)
		-> st
	;;
	unlock(envlck)

	while true
		match sys.await(buf[:])
		| -1:	-> `Waiterror
		| n:	(xpid, status) = parsestatus(buf[:n])
		;;
		if xpid == pid
			-> status
		else
			lock(envlck)
			htput(statusmap, xpid, status)
			unlock(envlck)
		;;
	;;
	/* impossible */
	-> `Waiterror
}

const parsestatus = {status	-> (pid, waitstatus)
	var st : waitstatus
	var spbuf : byte[:][5]
	var xpid, sp

	sp = bstrsplit(spbuf[:], status, " ")
	if sp.len == 0
		-> (-1, `Wfailure)
	;;

	match intparse(sp[0])
	| `Some pid:
		xpid = pid
		/* exits(nil) => sp[0] either not present or equal to '' */
		if sp.len == 4 || (sp.len == 5 && sleq(sp[4], "''"))
			st = `Wsuccess
		elif sp.len == 5
			st = `Wfailure
		else	/* we have a malformed await message */
			st = `Waiterror
		;;
	| `None:
		xpid = -1
		st = `Waiterror
	;;

	-> (xpid, st)

}