| |
| 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"); |
| } |
| |
| 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, P, mainpid; |
| |
| if T.state == Running then { |
| P = (Proc)T.proc; |
| mainpid = pid; |
| if mainpid != P.pid then setproc(P.pid); |
| stk = strace({}); |
| if mainpid != P.pid then setproc(mainpid); |
| } 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/lib9/", 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; |
| Tq = (Tqueue)P.threads; |
| T = (Thread)Tq.$head; |
| while T != 0 do{ |
| print("\t"); |
| thread(T); |
| T = (Thread)T.nextt; |
| } |
| } |
| |
| 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/lib9/", |
| "plan9/src/lib9/(fmt|utf)/", |
| }; |
| 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{ |
| if P.pid != mainpid then |
| setproc(P.pid); |
| stk(); |
| if P.pid != mainpid then |
| setproc(mainpid); |
| } 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<empty>\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); |