shithub: purgatorio

ref: ee695eff4329234e20abb68ff3100d3b15929418
dir: /appl/alphabet/reports.b/

View raw version
implement Reports;
include "sys.m";
	sys: Sys;
include "draw.m";
include "sh.m";
include "alphabet/reports.m";

Reporter: adt {
	id: int;
	name: string;
	stopc: chan of int;
};

reportproc(errorc: chan of string, stopc: chan of int, reply: chan of ref Report)
{
	if(sys == nil)
		sys = load Sys Sys->PATH;
	r := ref Report(chan of (string, chan of string, chan of int), chan of int);
	if(stopc == nil)
		stopc = chan of int;
	else
		sys->pctl(Sys->NEWPGRP, nil);
	reply <-= r;
	reportproc0(stopc, errorc, r.startc, r.enablec);
}

Report.start(r: self ref Report, name: string): chan of string
{
	if(r == nil)
		return nil;
	errorc := chan of string;
	r.startc <-= (name, errorc, nil);
	return errorc;
}

Report.add(r: self ref Report, name: string, errorc: chan of string, stopc: chan of int)
{
	r.startc <-= (name, errorc, stopc);
}

Report.enable(r: self ref Report)
{
	r.enablec <-= 0;
}

reportproc0(
		stopc: chan of int,
		reportc: chan of string,
		startc: chan of (string, chan of string, chan of int),
		enablec: chan of int
	)
{
	realc := array[2] of chan of string;
	p := array[len realc] of Reporter;
	a := array[0] of chan of string;
	id := n := 0;
	stopped := 0;
out:
	for(;;) alt{
	<-stopc =>
		stopped = 1;
		break out;
	(prefix, c, stop) := <-startc =>
		if(n == len realc){
			if(realc == a)
				a = nil;
			realc = (array[n * 2] of chan of string)[0:] = realc;
			p = (array[n * 2] of Reporter)[0:] = p;
			if(a == nil)
				a = realc;
		}
		realc[n] = c;
		p[n] = (id++, prefix, stop);
		n++;
	<-enablec =>
		if(n == 0)
			break out;
		a = realc;
	(x, msg) := <-a =>
		if(msg == nil){
			if(--n == 0)
				break out;
			if(n != x){
				a[x] = a[n];
				a[n] = nil;
				p[x] = p[n];
				p[n] = (-1, nil, nil);
			}
		}else{
			if(reportc != nil){
				alt{
				reportc <-= sys->sprint("%d. %s: %s", p[x].id, p[x].name, msg) =>
					;
				<-stopc =>
					stopped = 1;
					break out;
				}
			}
		}
	}
	if(stopped == 0){
		if(reportc != nil){
			alt{
			reportc <-= nil =>
				;
			<-stopc =>
				stopped = 1;
			}
		}
	}
	if(stopped){
		for(i := 0; i < n; i++)
			note(p[i].stopc);
		note(stopc);
	}
}

quit(errorc: chan of string)
{
	if(errorc != nil)
		errorc <-= nil;
	exit;
}

report(errorc: chan of string, err: string)
{
	if(errorc != nil)
		errorc <-= err;
}

newpgrp(stopc: chan of int, flags: int): chan of int
{
	if(sys == nil)
		sys = load Sys Sys->PATH;
	if(flags&PROPAGATE){
		if(stopc == nil)
			stopc = chan[1] of int;
		sys->pipe(p := array[2] of ref Sys->FD);
		spawn deadman(p[1]);
		sys->pctl(Sys->NEWPGRP, nil);
		spawn watchproc(p[0], stopc); 
	}else
		sys->pctl(Sys->NEWPGRP, nil);
	spawn grpproc(stopc, newstopc := chan[1] of int, flags&KILL);
	return newstopc;
}

grpproc(noteparent, noteself: chan of int, kill: int)
{
	if(noteparent == nil)
		noteparent = chan of int;
	alt{
	<-noteparent =>
		note(noteparent);
	<-noteself =>
		;
	}
	note(noteself);
	if(kill){
		pid := sys->pctl(0, nil);
		fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE);
		if(fd == nil)
			fd = sys->open("/prog/"+string pid+"/ctl", Sys->OWRITE);
		sys->fprint(fd, "killgrp");
	}
}

note(c: chan of int)
{
	if(c != nil){
		alt {
		c <-= 1 =>
			;
		* =>
			;
		}
	}
}

deadman(nil: ref Sys->FD)
{
	<-chan of int;
}

watchproc(fd: ref Sys->FD, stopc: chan of int)
{
	sys->read(fd, array[1] of byte, 1);
	note(stopc);
}