@include @global mux; @define sym2brkaddr(id, dom) { @local a, s; s = dom.looksym(id); if(s == nil) error("no such symbol %a", id); a = {dom}symoff(s); a = {mkctype_ptr(symtype(s), nsptr(dom))}a; return a; } @define mkinterval(b, e) { @defloc prefix() { @local bp, ep, bx, inst; bp = b.path(); ep = e.path(); inst = nil; while(1){ if(bp == [] || ep == []) break; if(bp[0] != ep[0]) break; bx = pop(bp); pop(ep); if(inst == nil) inst = mkinstant(bx, nil); else inst = mkinstant(inst, bx); } if(inst == nil) error("interval of incomparable instants"); printf("common prefix is %a\n", inst.path()); return [ inst, bp, ep ]; } @defloc scan(this, pats) { @local ctl, inst, bp, ep, trace; [inst, bp, ep] = prefix(); trace = [inst]; ctl = inst.getctl(); printf("wound instant to end of prefix\n"); @defloc capture() { @local m; m = length(trace); if(m == 1) return mkinstantx(trace[0], []); else return mkinstantx(trace[0], slice(trace, 1, m)); } @defloc done() { return (ctl.state == ctlmux`Stopped || ctl.state == ctlmux`Dead); } printf("doing %a %a %a\n", inst, bp, ep); @defloc nextent(extents, which) { @local tid, x, sym; x = pop(extents); if(x == nil){ if(which == 'end && ctl.state != ctlmux`Dead){ printf("stopping\n"); ctl.xstop(); } return; } switch(x){ case nil: default: error("bad extent: %a", x); case ['entry, id]: sym = looksym(ctl.ns(), id); tid = ctl.xtrap(symoff(sym), @lambda(ctl){ if(which == 'beg) append(trace, x); ctl.trapdel(tid); nextent(extents, which); }); break; case ['exit]: ctl.trace(ctlmux`Eexit, @lambda(ctl){ printf("exit\n"); if(which == 'beg) append(trace, x); nextent(extents, which); }); break; } } @defloc setscan(pats) { foreach(@lambda(pat) { @local sym; switch(pat){ case nil: default: error("bad pattern: %a", pat); case ['entry, id, fn]: sym = looksym(ctl.ns(), id); ctl.xtrap(symoff(sym), @lambda(ctl){ append(trace, ['entry, id]); fn(capture()); }); break; } }, pats); } nextent(bp, 'beg); nextent(ep, 'end); if(bp != []){ printf("starting it\n"); ctl.xcont(); mux.runtil(done); } printf("made it to beginning of interval: %a\n", trace); /* ctl is at beginning of interval */ setscan(pats); ctl.xcont(); mux.runtil(done); printf("made it to end of interval: %a\n", trace); /* ctl is at end of interval */ } return mkas([ "scan" : scan, ], "interval"); } @define mkinstantx(base, extents) { @local i; i = base; foreach(@lambda(e){ i = mkinstant(i, e); }, extents); return i; } @define mkinstant(base, extent) { @defloc getctl(this) { @local ctl, tid, sym, rv; switch(extent){ case nil: ctl = base(); return ctl; case ['entry, id]: printf("getctl %a\n", extent); ctl = base.getctl(); sym = looksym(ctl.ns(), id); tid = ctl.xtrap(symoff(sym), @lambda(ctl){ printf("trapped at %a\n", id); ctl.xstop(); rv = ctl; }); ctl.xcont(); mux.runtil(@lambda() { ctl.state == ctlmux`Stopped; }); ctl.trapdel(tid); if(rv == nil) error("fail to wind instant"); return rv; case ['exit]: ctl = base.getctl(); ctl.trace(ctlmux`Exit, @lambda(ctl){ ctl.xstop(); rv = ctl; }); ctl.xcont(); mux.runtil(@lambda() { ctl.state == ctlmux`Dead; }); return rv; default: error("bad extent %a", extent); } } @defloc path(this) { @local p; if(extent == nil) return [ base ]; p = base.path(); append(p, extent); return p; } return mkas([ "path" : path, "getctl" : getctl ], "instant"); } @define mkexe(args) { @local b, e; @defloc mkbase() { @local ctl; ctl = mux.launch(args, 0); ctl.trace(ctlmux`Esignal, @lambda(ctl, sig){ printf("proc %d received signal %d\n", ctl.id, sig); printf("%s\n", fmtstack(ctl, ctl.ns())); ctl.kill(); }); return ctl; } b = mkinstant(mkbase, nil); e = mkinstant(b, ['exit]); return mkinterval(b, e); } mux = mkctlmux_local(); { @local e, lastfoo, is, pats0; //e = mkexe(["./l1", "./x.cqct"]); e = mkexe(["./t1"]); is = []; pats0 = [ ['entry, 'foo, @lambda(inst) { printf("enter foo: %a\n", inst.path()); lastfoo = inst; }], ['entry, 'bar, @lambda(inst) { printf("enter bar: %a\n", inst.path()); append(is, mkinterval(lastfoo, inst)); }] ]; e.scan(pats0); is[1].scan([]); is[2].scan([]); }