ref: 02ac617541ca1a7bf82b1615fb5a58235469b5d3
dir: /appl/alphabet/reports.b/
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);
}