374 lines
6.1 KiB
Text
374 lines
6.1 KiB
Text
include("/sys/src/libthread/sched." + objtype + ".acid");
|
|
|
|
defn labpc(l)
|
|
{
|
|
if objtype == "386" || objtype == "amd64" then
|
|
return longjmp;
|
|
return *(l+4);
|
|
}
|
|
|
|
defn labsp(l)
|
|
{
|
|
return *l;
|
|
}
|
|
|
|
defn labstk(l)
|
|
{
|
|
_stk(labpc(l), labsp(l), 0, 1);
|
|
}
|
|
|
|
defn lablstk(l)
|
|
{
|
|
_stk(labpc(l), labsp(l), 0, 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 = {
|
|
"^/sys/src/libc",
|
|
"^/sys/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;
|
|
}
|
|
if a == {} then
|
|
return "{}";
|
|
return itoa(a\X, "%x");
|
|
}
|
|
|
|
stkignorelist = {};
|
|
|
|
defn stkignore(s){
|
|
append stkignorelist, s;
|
|
}
|
|
|
|
defn threadstkline(T){
|
|
local ostk, stk, frame, pc, pc0, file, lastpc0, s, sym, i, stop;
|
|
|
|
if T.state == Running then{
|
|
pc = *PC;
|
|
stk = strace(*PC, *SP, linkreg(0));
|
|
}else{
|
|
pc = labpc(T.sched);
|
|
stk = strace(labpc(T.sched), labsp(T.sched), 0);
|
|
}
|
|
firstpc = pc;
|
|
lastpc0 = 0;
|
|
pc0 = 0;
|
|
stop = 0;
|
|
ostk = stk;
|
|
while stk && !stop do {
|
|
file = pcfile(pc);
|
|
if !regexp("^/sys/src/libc/", file)
|
|
&& !regexp("^/sys/src/libthread/", file)
|
|
&& match(file, stkignore)==-1 then
|
|
stop = 1;
|
|
else if stk[0][1] == 0xfefefefe then {
|
|
pc = ostk[0][1];
|
|
pc0 = ostk[1][0];
|
|
stop = 1;
|
|
}else{
|
|
lastpc0 = pc0;
|
|
frame = head stk;
|
|
stk = tail stk;
|
|
nextframe = head stk;
|
|
pc = frame[1];
|
|
pc0 = nextframe[0];
|
|
}
|
|
}
|
|
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 = T.nextt;
|
|
}
|
|
setproc(mainpid);
|
|
}
|
|
|
|
defn threads(){
|
|
local P;
|
|
|
|
P = (Proc)_threadpq.$head;
|
|
while P != 0 do{
|
|
if P != (Proc)_threadpq.$head then print("\n");
|
|
lproc(P);
|
|
P = P.next;
|
|
}
|
|
}
|
|
|
|
defn stacks(){
|
|
local P, mainpid;
|
|
|
|
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 = P.next;
|
|
print("\n");
|
|
}
|
|
setproc(mainpid);
|
|
}
|
|
|
|
defn stacksizes(){
|
|
local P, T, Tq, top, sp, mainpid;
|
|
|
|
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, " / ", T.stksize\D, "\n");
|
|
T = T.nextt;
|
|
}
|
|
P = P.next;
|
|
}
|
|
setproc(mainpid);
|
|
}
|
|
|
|
defn lproc(P){
|
|
proc(P);
|
|
pthreads(P);
|
|
}
|
|
|
|
defn threadstks(P){
|
|
complex Proc P;
|
|
local T, Tq, mainpid, pref, ign;
|
|
|
|
mainpid = pid;
|
|
pref = stkprefix;
|
|
stkprefix = pref+"\t\t";
|
|
ign = stkignore;
|
|
stkignore = {
|
|
"^/sys/src/libthread/",
|
|
"^/sys/src/libc/(386|arm|sparc|power|mips)/"
|
|
};
|
|
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 = 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;
|
|
|
|
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{
|
|
lstk();
|
|
} 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;
|
|
}
|
|
}
|
|
|
|
print("/sys/lib/acid/thread");
|