summaryrefslogtreecommitdiff
path: root/appl/cmd/mash/serve.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/mash/serve.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/cmd/mash/serve.b')
-rw-r--r--appl/cmd/mash/serve.b154
1 files changed, 154 insertions, 0 deletions
diff --git a/appl/cmd/mash/serve.b b/appl/cmd/mash/serve.b
new file mode 100644
index 00000000..e293a8f4
--- /dev/null
+++ b/appl/cmd/mash/serve.b
@@ -0,0 +1,154 @@
+#
+# This should be called by spawned (persistent) threads.
+# It arranges for them to be killed at the end of the day.
+#
+reap()
+{
+ if (pidchan == nil) {
+ pidchan = chan of int;
+ spawn zombie();
+ }
+ pidchan <-= sys->pctl(0, nil);
+}
+
+#
+# This thread records spawned threads and kills them.
+#
+zombie()
+{
+ pids := array[10] of int;
+ pidx := 0;
+ for (;;) {
+ pid := <- pidchan;
+ if (pid == PIDEXIT) {
+ for (i := 0; i < pidx; i++)
+ kill(pids[i]);
+ exit;
+ }
+ if (pidx == len pids) {
+ n := pidx * 3 / 2;
+ a := array[n] of int;
+ a[:] = pids;
+ pids = a;
+ }
+ pids[pidx++] = pid;
+ }
+}
+
+#
+# Kill a thread.
+#
+kill(pid: int)
+{
+ fd := sys->open("#p/" + string pid + "/ctl", sys->OWRITE);
+ if (fd != nil)
+ sys->fprint(fd, "kill");
+}
+
+#
+# Exit top level, killing spawned threads.
+#
+exitmash()
+{
+ if (pidchan != nil)
+ pidchan <-= PIDEXIT;
+ exit;
+}
+
+#
+# Slice a buffer if needed.
+#
+restrict(buff: array of byte, count: int): array of byte
+{
+ if (count < len buff)
+ return buff[:count];
+ else
+ return buff;
+}
+
+#
+# Serve mash console reads. Favours other programs
+# ahead of the input loop.
+#
+serve_read(c: ref Sys->FileIO, sync: chan of int)
+{
+ s: string;
+ in := sys->fildes(0);
+ sys->pctl(Sys->NEWFD, in.fd :: nil);
+ sync <-= 0;
+ reap();
+ buff := array[Sys->ATOMICIO] of byte;
+outer: for (;;) {
+ n := sys->read(in, buff, len buff);
+ if (n < 0) {
+ n = 0;
+ s = errstr();
+ } else
+ s = nil;
+ b := buff[:n];
+ alt {
+ (off, count, fid, rc) := <-c.read =>
+ if (rc == nil)
+ break;
+ rc <-= (restrict(b, count), s);
+ continue outer;
+ * =>
+ ;
+ }
+ inner: for (;;) {
+ alt {
+ (off, count, fid, rc) := <-c.read =>
+ if (rc == nil)
+ continue inner;
+ rc <-= (restrict(b, count), s);
+ inchan <-= b =>
+ ;
+ }
+ break;
+ }
+ }
+}
+
+#
+# Serve mash console writes.
+#
+serve_write(c: ref Sys->FileIO, sync: chan of int)
+{
+ out := sys->fildes(1);
+ sys->pctl(Sys->NEWFD, out.fd :: nil);
+ sync <-= 0;
+ reap();
+ for (;;) {
+ (off, data, fid, wc) := <-c.write;
+ if (wc == nil)
+ continue;
+ if (sys->write(out, data, len data) < 0)
+ wc <-= (0, errstr());
+ else
+ wc <-= (len data, nil);
+ }
+}
+
+#
+# Begin serving the mash console.
+#
+Env.serve(e: self ref Env)
+{
+ if (servechan != nil)
+ return;
+ (s, c) := e.servefile(nil);
+ inchan = chan of array of byte;
+ servechan = chan of array of byte;
+ sync := chan of int;
+ spawn serve_read(c, sync);
+ spawn serve_write(c, sync);
+ <-sync;
+ <-sync;
+ if (sys->bind(s, CONSOLE, Sys->MREPL) < 0)
+ e.couldnot("bind", CONSOLE);
+ sys->pctl(Sys->NEWFD, nil);
+ e.in = sys->open(CONSOLE, sys->OREAD | sys->ORCLOSE);
+ e.out = sys->open(CONSOLE, sys->OWRITE);
+ e.stderr = sys->open(CONSOLE, sys->OWRITE);
+ e.wait = nil;
+}