shithub: mc

ref: 6f479559c4aa6efaaa4352c70d1e7755d2267573
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(pidhash, pideq)
		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)

}

const pidhash	= {x;	-> inthash(x castto(int32))}
const pideq	= {a, b;	-> a == b}