//// pthread-specific access functions// avoid complicated libthread_db interface// include("pthread-"+systype+"-"+objtype); // pick apart system mcontext_t structuresdefn 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);
//
// 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);