Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

include("/sys/src/libthread/sched.acid");

defn labpc(l)
{
        if objtype == "386" then
                return longjmp;
        return *(l+4);
}

defn labsp(l)
{
        return *l;
}

defn labstk(l)
{
        _stk(labpc(l), labsp(l), 0, 0);
}

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|alpha|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{
                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<empty>\n");
                i=i+1;
        }
}

print("/sys/lib/acid/thread");