@include // trace thread creation/termination @define test1(n) { @local ctl, mux, ns, as, dom; mux = mkctlmux_local(); ctl = mux.launch(["./clones", sprintfa("%d", n)], 0); as = ctl.mem(); ns = ctl.ns(); dom = mkdom(ns, as); dom.xcont(); mux.run(); } // trace child creation/termination @define test2(n) { @local ctl, mux, ns, as, dom; mux = mkctlmux_local(); ctl = mux.launch(["./forks", sprintfa("%d", n)], 0); as = ctl.mem(); ns = ctl.ns(); dom = mkdom(ns, as); dom.xcont(); mux.run(); } // trace multi-threaded breakpoints @define test3(n) { @local ctl, mux, ns, as, dom, nc, nw; nc = nw = 0; mux = mkctlmux_local(); ctl = mux.launch([ "./clones", sprintfa("%d", n)], 0); as = ctl.mem(); ns = ctl.ns(); dom = mkdom(ns, as); dom.trace(ctlmux`Eclone, @lambda(ctl, cctl){ printf("task %d has cloned %d\n", ctl.id, cctl.id); nc++; return nil; }); dom.xtrap(&dom`work, @lambda(ctl){ printf("task %d has entered work\n", ctl.id); nw++; return nil; }); dom.xcont(); mux.run(); printf("nclone = %d; nwork = %d\n", nc, nw); } if(length(args) == 1){ test1(5); test2(5); test3(5); } else if(length(args) == 2) test1(strton(args[1])); else if(length(args) == 3){ switch(args[1]){ case "1": return test1(strton(args[2])); case "2": return test2(strton(args[2])); case "3": return test3(strton(args[2])); default: error("no such test %a", args[1]); } }else error("usage: %s [] | %s ");