// // pthread-specific access functions // avoid complicated libthread_db interface // include("pthread-"+systype+"-"+objtype); // pick apart system mcontext_t structures defn mcontext(m) { complex mcontext_t m; if systype == "linux" then { m = m\X; return {"PC", m[14], "SP", m[7], "BP", m[6]}; } else if systype == "freebsd" then { return {"PC", m.mc_eip, "SP", m.mc_esp, "BP", m.mc_ebp}; } else error("do not know how to read mcontext_t on system "+systype); } // // plan 9 thread library support // defn context(c) { c = (Context)c; return mcontext(c.uc.uc_mcontext); } defn contextstk(c) { _stk(context(c), 0); } defn contextlstk(c) { _stk(context(c), 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 channel(C) { complex Channel C; local i, p; print("channel ", C\X, " // ", *(C.name\s)); if C.freed then { print(" (moribund)"); } print("\n"); print("\telemsize=", C.elemsize\D, " bufsize=", C.bufsize, "\n"); if C.bufsize then { print("\t", C.nbuf\D, " values in channel:\n"); print("\t"); p = C.buf+C.off*C.elemsize; loop 1,C.nbuf do { if C.elemsize==4 then { print(*p\X, " "); }else { print("data(", p\X, ") "); } p = p+C.elemsize; if p == C.buf+C.bufsize*C.elemsize then { p = C.buf; } } } print("\n"); print(" senders:\n"); _altarray(C.asend); print(" recvers:\n"); _altarray(C.arecv); } defn _altarray(aa) { local i, a, t; i = 0; aa = (_Altarray)aa; while i < aa.n do { a = (Alt)aa.a[i]; print("\t"+threadstkline(a.thread)+"\n"); i++; } } 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; T = (_Thread)T; P = (Proc)T.proc; if P.thread == T then { mainpid = pid; setproc(pthread2tid(P.osprocid)); stk = strace({}); setproc(mainpid); } else stk = strace(context(T.context)); 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) && file != "?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 P, s, name; P = (Proc)T.proc; s = "t=(_Thread)"+itoa(T, "%#-10x")+" // "; if P.thread == T then s = s + "Running "; else s = s + "Sleeping "; s = s + threadstkline(T); name = T+392; // T+offsetof(_Thread, name); if *(name\b) != 0 then s = s + " ["+*(name\s)+"]"; return s; } defn thread(T){ print(threadfmt(T), "\n"); } defn procthreads(P){ complex Proc P; local T; T = (_Thread)P.allthreads.$head; while T != 0 do{ print("\t"); thread(T); T = (_Thread)T.allnext; } } defn prociter(x) { local P; P = (Proc)*_threadprocs; while P != 0 do{ if P != (Proc)*_threadprocs then print("\n"); proc(P); if x == 1 then procthreads(P); if x == 2 then threadstks(P); P = (Proc)P.next; } } defn procs() { prociter(0); } defn threads() { prociter(1); } defn stacks() { prociter(2); } threadstkignore = { "plan9/src/libthread/", "plan9/src/lib9/", "plan9/src/lib9/(fmt|utf)/", }; defn threadstks(P){ complex Proc P; local T, mainpid, pref, ign; pref = stkprefix; stkprefix = pref+"\t\t"; ign = stkignore; stkignore = threadstkignore; T = (_Thread)P.allthreads.$head; while T != 0 do{ print("\t"); thread(T); threadstk(T); T = (_Thread)T.allnext; print("\n"); } stkprefix = pref; stkignore = ign; } defn proc(P){ complex Proc P; print("p=(Proc)", itoa(P, "%#-10x"), " // pthread ", P.osprocid\X, " pid ", pthread2tid(P.osprocid)\D, " "); if P.thread==0 then print(" Sched"); else print(" Running"); print("\n"); } defn threadlstk(T){ complex _Thread T; local P, mainpid; P = (Proc)T.proc; mainpid = pid; setproc(pthread2tid(P.osprocid)); if P.thread == T then lstk(); else contextlstk(T.context); setproc(mainpid); } defn threadstk(T){ complex _Thread T; local P, mainpid; P = (Proc)T.proc; mainpid = pid; setproc(pthread2tid(P.osprocid)); if P.thread == T then stk(); else contextstk(T.context); setproc(mainpid); } print(acidfile);