shithub: mc

ref: ee50a71ce18d4721e868e575d26d894bc8f13e37
dir: /lib/std/wait+plan9.myr/

View raw version
use sys

use "alloc.use"
use "chartype.use"
use "die.use"
use "extremum.use"
use "hashfuncs.use"
use "hasprefix.use"
use "htab.use"
use "intparse.use"
use "option.use"
use "strsplit.use"
use "syswrap.use"
use "utf.use"

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}