defn labpc(l) { complex Label l; return l.pc; } defn label(l) { complex Label l; if objtype == "386" then return {"PC", l.pc, "BX", l.bx, "SP", l.sp, "BP", l.bp, "SI", l.si, "DI", l.di}; return {}; } defn labstk(l) { _stk(label(l), 0); } defn lablstk(l) { _stk(label(l), 1); } defn altfmt(A){ local i, s, yes; complex Alt A; s = "alt("; s = s + "tag(*" + itoa(A.tag, "%x") + "=" + itoa(*A.tag, "%x") + ") "; i = 0; yes = 0; while A.op != CHANEND && A.op != CHANNOBLK do{ if A.op != CHANNOP then{ if yes then s = s + " "; s = s + itoa(i, "%d"); s = s + ":"; if A.op == CHANSND then s = s + "send"; if A.op == CHANRCV then s = s + "recv"; s = s + "(channel("; s = s + itoa(A.c, "%x"); s = s + "))"; yes = 1; } i = i + 1; A = (Alt)(A + sizeofAlt); } if A.op==CHANNOBLK then{ if yes then s = s + " "; s = s + "noblock"; } s = s + ")"; return s; } defn alt(A){ print(altfmt(A), "\n"); } threadignsrc = { "plan9/src/libc", "plan9/src/libthread", }; defn fnname(a){ local sym, s; s = symbols; while s do { sym = head s; if sym[2] == a then return sym[0]; s = tail s; } return itoa(a, "%x"); } stkignorelist = {}; defn stkignore(s){ append stkignorelist, s; } defn threadstkline(T){ local stk, frame, pc, pc0, file, s, sym, i, stop; if T.state == Running then stk = strace({}); else stk = strace(label(T.sched)); stop = 0; while stk && !stop do { frame = head stk; stk = tail stk; pc = frame[2]; pc0 = frame[0]; file = pcfile(pc); if !regexp("plan9/src/libc/", file) && !regexp("plan9/src/libthread/", file) && match(file, stkignore)==-1 then stop = 1; } file = pcfile(pc); s = file+":"+itoa(pcline(pc), "%d"); if pc0 != 0 then s = s + " "+fnname(pc0); return s; } defn threadfmt(T){ complex Thread T; local A, yes, i, P, s; P = (Proc)T.proc; s = "t=(Thread)"+itoa(T, "%-10x")+" "; if T.state == Running then s = s + "Running "; else if T.state == Ready then s = s + "Ready "; else if T.state == Rendezvous then s = s + "Rendez "; else s = s + "Bad state "+itoa(T.state, "%x")+" "; A = (Alt)T.alt; if 1 then s = s + threadstkline(T); else if T.chan == Chanalt then s = s + altfmt(T.alt); else if T.chan == Chansend then s = s + "send(Channel("+itoa(A.c, "%x")+"))"; else if T.chan == Chanrecv then s = s + "recv(Channel("+itoa(A.c, "%x")+"))"; else s = s + threadstkline(T); if T.moribund == 1 then s = s + " Moribund"; if T.cmdname != 0 then s = s + " ["+*(T.cmdname\s)+"]"; return s; } defn thread(T){ print(threadfmt(T), "\n"); } defn pthreads(P){ complex Proc P; local T, Tq, mainpid; mainpid = pid; setproc(P.pid); Tq = (Tqueue)P.threads; T = (Thread)Tq.$head; while T != 0 do{ print("\t"); thread(T); T = (Thread)T.nextt; } setproc(mainpid); } defn threads(){ local P; complex Pqueue _threadpq; P = (Proc)_threadpq.$head; while P != 0 do{ if P != (Proc)_threadpq.$head then print("\n"); lproc(P); P = (Proc)P.next; } } defn stacks(){ local P, mainpid; complex Pqueue _threadpq; stkprefix = ""; mainpid = pid; P = (Proc)_threadpq.$head; while P != 0 do{ proc(P); // setproc(P.pid); // if P.thread==0 then{ // print("=== thread scheduler stack\n"); // stk(); // } // print("threadstks(", P\X, ")\n"); threadstks(P); P = (Proc)P.next; print("\n"); } setproc(mainpid); } defn stacksizes(){ local P, T, Tq, top, sp, mainpid; complex Pqueue _threadpq; mainpid = pid; P = (Proc)_threadpq.$head; while P != 0 do{ P = (Proc)P; Tq = (Tqueue)P.threads; T = (Thread)Tq.$head; while T != 0 do{ top = T.stk+T.stksize; if T.state==Running then { sp = *SP; }else{ sp = *(T.sched); } sp = *(T.sched); print(top-sp\D, "\n"); T = (Thread)T.nextt; } P = P.next; } setproc(mainpid); } defn lproc(P){ proc(P); pthreads(P); } threadstkignore = { "plan9/src/libthread/", "plan9/src/libc/(386|arm|alpha|sparc|power|mips)/" }; defn threadstks(P){ complex Proc P; local T, Tq, mainpid, pref, ign; mainpid = pid; pref = stkprefix; stkprefix = pref+"\t\t"; ign = stkignore; stkignore = threadstkignore; setproc(P.pid); Tq = (Tqueue)P.threads; T = (Thread)Tq.$head; while T != 0 do{ // print("=============================\n"); // print(" thread(", T\X, ")\n"); print("\t"); thread(T); threadstk(T); T = (Thread)T.nextt; print("\n"); } setproc(mainpid); stkprefix = pref; stkignore = ign; } defn proc(P){ complex Proc P; print("p=(Proc)", itoa(P, "%-10x"), " pid ", P.pid\D, " "); if P.thread==0 then print(" Sched"); else print(" Running"); print("\n"); } defn procs(){ local P; complex Pqueue _threadpq; P = (Proc)_threadpq.$head; while P != 0 do{ proc(P); P = P.next; } } defn threadlstk(T){ complex Thread T; local P, mainpid; P = (Proc)T.proc; mainpid = pid; setproc(P.pid); if T.state == Running then{ lstk(); } else { lablstk(T.sched); } setproc(mainpid); } defn threadstk(T){ complex Thread T; local P, mainpid; P = (Proc)T.proc; mainpid = pid; setproc(P.pid); if T.state == Running then{ stk(); } else { labstk(T.sched); } setproc(mainpid); } defn tqueue(Q) { complex Tqueue Q; while Q != 0 do { print(Q.$head\X, " "); Q = *(Q.$tail); } print("#\n"); } defn channel(C) { complex Channel C; local i, p; print("channel ", C\X); if C.freed then { print(" (moribund)"); } print("\n"); print("\telementsize=", C.e\D, " buffersize=", C.s, "\n"); if C.s then { print("\t", C.n\D, " values in channel:\n"); print("\t"); p = C.v+C.e*(C.f%C.s); loop 1,C.n do { if C.e==4 then { print((*p)\X, " "); }else { print("data(", (*p)\X, ") "); } p = p+C.e; if p == C.v+C.s*C.e then { p = C.v; } } } print("\n"); print(C.nentry\D, " queue slots:\n"); i=0; loop 1,C.nentry do { if C.qentry[i] then print("\t", altfmt(C.qentry[i]), "\n"); else print("\t\n"); i=i+1; } } defn polling() { local i, c, t, p, pf; p=(Poll)polls; pf=(struct_pollfd)pfd; loop 1,*npoll do { print("\tfd ", pf.fd\D, " "); if pf.events & 1 then print("r"); else if pf.events & 2 then print("w"); else print(pf.events\D); print(" chan Channel(", p.c\X, ")\n"); p = (Poll)(p+sizeofPoll); pf = (struct_pollfd)(pf+sizeofstruct_pollfd); } c=sleepchan; t=sleeptime; loop 1,*nsleep do { print("\tsleep ", *t\D, " Channel(", *c\X, ")\n"); c++; t++; } } print(acidfile);