shithub: mc

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

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
	var spbuf : byte[:][5]
	var xpid, sp

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

	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
	;;

	-> (st, xpid)

}