shithub: mc

ref: a4250ceb2489b320e220dbbd9a71a3523001bd50
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"

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

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

var statusinit	: bool = false
var statusmap	: htab(pid, waitstatus)#

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

	if !statusinit
		statusmap = mkht(inthash, inteq)
		statusinit = true
	;;
		
	match htget(statusmap, pid)
	| `Some st:
		htdel(statusmap, pid)
		-> st
	| `None:	/* nothing */
	;;

	while true
		n = sys.await(buf[:])
		if n < 0
			-> `Waiterror
		;;

		(status, xpid) = parsestatus(buf[:n])
		if xpid == pid
			-> status
		else
			htput(statusmap, pid, status)
		;;
	;;
	/* impossible */
	-> `Waiterror
}

const parsestatus = {status	-> (waitstatus, pid)
	var st : waitstatus, xpid, sp

	sp = strsplit(status, " ")
	if sp.len == 0
		slfree(sp)
		-> (`Wfailure, -1)
	;;

	match intparse(sp[0])
	| `Some pid:
		xpid = pid
		if sp.len == 4 || (sp.len == 5 && sp[4].len > 0)	/* we exited with nil */
			st = `Wsuccess
		elif sp.len == 5	/* we have a status */
			st = `Wfailure
		else	/* we have a malformed await message */
			st = `Waiterror
		;;
	| `None:
		xpid = -1
		st = `Waiterror
	;;

	slfree(sp)
	-> (st, xpid)

}