1*9a747e4fSDavid du Colombier /* 2*9a747e4fSDavid du Colombier * Some notes on locking: 3*9a747e4fSDavid du Colombier * 4*9a747e4fSDavid du Colombier * All the locking woes come from implementing 5*9a747e4fSDavid du Colombier * threadinterrupt (and threadkill). 6*9a747e4fSDavid du Colombier * 7*9a747e4fSDavid du Colombier * _threadgetproc()->thread is always a live pointer. 8*9a747e4fSDavid du Colombier * p->threads, p->ready, and _threadrgrp also contain 9*9a747e4fSDavid du Colombier * live thread pointers. These may only be consulted 10*9a747e4fSDavid du Colombier * while holding p->lock or _threadrgrp.lock; in procs 11*9a747e4fSDavid du Colombier * other than p, the pointers are only guaranteed to be live 12*9a747e4fSDavid du Colombier * while the lock is still being held. 13*9a747e4fSDavid du Colombier * 14*9a747e4fSDavid du Colombier * Thread structures can only be freed by the proc 15*9a747e4fSDavid du Colombier * they belong to. Threads marked with t->inrendez 16*9a747e4fSDavid du Colombier * need to be extracted from the _threadrgrp before 17*9a747e4fSDavid du Colombier * being freed. 18*9a747e4fSDavid du Colombier * 19*9a747e4fSDavid du Colombier * _threadrgrp.lock cannot be acquired while holding p->lock. 20*9a747e4fSDavid du Colombier */ 217dd7cddfSDavid du Colombier 22*9a747e4fSDavid du Colombier typedef struct Pqueue Pqueue; 23*9a747e4fSDavid du Colombier typedef struct Rgrp Rgrp; 24*9a747e4fSDavid du Colombier typedef struct Tqueue Tqueue; 25*9a747e4fSDavid du Colombier typedef struct Thread Thread; 26*9a747e4fSDavid du Colombier typedef struct Execargs Execargs; 27*9a747e4fSDavid du Colombier typedef struct Proc Proc; 28*9a747e4fSDavid du Colombier 29*9a747e4fSDavid du Colombier /* must match list in sched.c */ 30*9a747e4fSDavid du Colombier typedef enum 31*9a747e4fSDavid du Colombier { 32*9a747e4fSDavid du Colombier Dead, 337dd7cddfSDavid du Colombier Running, 34*9a747e4fSDavid du Colombier Ready, 357dd7cddfSDavid du Colombier Rendezvous, 367dd7cddfSDavid du Colombier } State; 377dd7cddfSDavid du Colombier 38*9a747e4fSDavid du Colombier typedef enum 39*9a747e4fSDavid du Colombier { 40*9a747e4fSDavid du Colombier Channone, 41*9a747e4fSDavid du Colombier Chanalt, 42*9a747e4fSDavid du Colombier Chansend, 43*9a747e4fSDavid du Colombier Chanrecv, 44*9a747e4fSDavid du Colombier } Chanstate; 457dd7cddfSDavid du Colombier 46*9a747e4fSDavid du Colombier enum 47*9a747e4fSDavid du Colombier { 48*9a747e4fSDavid du Colombier RENDHASH = 13, 49*9a747e4fSDavid du Colombier Printsize = 2048, 507dd7cddfSDavid du Colombier }; 517dd7cddfSDavid du Colombier 52*9a747e4fSDavid du Colombier struct Rgrp 53*9a747e4fSDavid du Colombier { 547dd7cddfSDavid du Colombier Lock lock; 55*9a747e4fSDavid du Colombier Thread *hash[RENDHASH]; 56*9a747e4fSDavid du Colombier }; 57*9a747e4fSDavid du Colombier 58*9a747e4fSDavid du Colombier struct Tqueue /* Thread queue */ 59*9a747e4fSDavid du Colombier { 60*9a747e4fSDavid du Colombier int asleep; 617dd7cddfSDavid du Colombier Thread *head; 62*9a747e4fSDavid du Colombier Thread **tail; 637dd7cddfSDavid du Colombier }; 647dd7cddfSDavid du Colombier 65*9a747e4fSDavid du Colombier struct Thread 66*9a747e4fSDavid du Colombier { 67*9a747e4fSDavid du Colombier Lock lock; /* protects thread data structure */ 68*9a747e4fSDavid du Colombier jmp_buf sched; /* for context switches */ 69*9a747e4fSDavid du Colombier int id; /* thread id */ 70*9a747e4fSDavid du Colombier int grp; /* thread group */ 71*9a747e4fSDavid du Colombier int moribund; /* thread needs to die */ 72*9a747e4fSDavid du Colombier State state; /* run state */ 73*9a747e4fSDavid du Colombier State nextstate; /* next run state */ 74*9a747e4fSDavid du Colombier uchar *stk; /* top of stack (lowest address of stack) */ 75*9a747e4fSDavid du Colombier uint stksize; /* stack size */ 76*9a747e4fSDavid du Colombier Thread *next; /* next on ready queue */ 7780ee5cbfSDavid du Colombier 78*9a747e4fSDavid du Colombier Proc *proc; /* proc of this thread */ 79*9a747e4fSDavid du Colombier Thread *nextt; /* next on list of threads in this proc*/ 80*9a747e4fSDavid du Colombier int ret; /* return value for Exec, Fork */ 81*9a747e4fSDavid du Colombier 82*9a747e4fSDavid du Colombier char *cmdname; /* ptr to name of thread */ 83*9a747e4fSDavid du Colombier 84*9a747e4fSDavid du Colombier int inrendez; 85*9a747e4fSDavid du Colombier Thread *rendhash; /* Trgrp linked list */ 86*9a747e4fSDavid du Colombier ulong rendtag; /* rendezvous tag */ 87*9a747e4fSDavid du Colombier ulong rendval; /* rendezvous value */ 88*9a747e4fSDavid du Colombier int rendbreak; /* rendezvous has been taken */ 89*9a747e4fSDavid du Colombier 90*9a747e4fSDavid du Colombier Chanstate chan; /* which channel operation is current */ 91*9a747e4fSDavid du Colombier Alt *alt; /* pointer to current alt structure (debugging) */ 92*9a747e4fSDavid du Colombier 93*9a747e4fSDavid du Colombier void* udata; /* User per-thread data pointer */ 947dd7cddfSDavid du Colombier }; 957dd7cddfSDavid du Colombier 96*9a747e4fSDavid du Colombier struct Execargs 97*9a747e4fSDavid du Colombier { 98*9a747e4fSDavid du Colombier char *prog; 99*9a747e4fSDavid du Colombier char **args; 100*9a747e4fSDavid du Colombier int fd[2]; 101*9a747e4fSDavid du Colombier }; 102*9a747e4fSDavid du Colombier 103*9a747e4fSDavid du Colombier struct Proc 104*9a747e4fSDavid du Colombier { 1057dd7cddfSDavid du Colombier Lock lock; 106*9a747e4fSDavid du Colombier jmp_buf sched; /* for context switches */ 107*9a747e4fSDavid du Colombier int pid; /* process id */ 108*9a747e4fSDavid du Colombier int splhi; /* delay notes */ 109*9a747e4fSDavid du Colombier Thread *thread; /* running thread */ 1107dd7cddfSDavid du Colombier 111*9a747e4fSDavid du Colombier int needexec; 112*9a747e4fSDavid du Colombier Execargs exec; /* exec argument */ 113*9a747e4fSDavid du Colombier Proc *newproc; /* fork argument */ 114*9a747e4fSDavid du Colombier char exitstr[ERRMAX]; /* exit status */ 1157dd7cddfSDavid du Colombier 116*9a747e4fSDavid du Colombier int rforkflag; 1177dd7cddfSDavid du Colombier int nthreads; 118*9a747e4fSDavid du Colombier Tqueue threads; /* All threads of this proc */ 119*9a747e4fSDavid du Colombier Tqueue ready; /* Runnable threads */ 120*9a747e4fSDavid du Colombier Lock readylock; 1217dd7cddfSDavid du Colombier 122*9a747e4fSDavid du Colombier char printbuf[Printsize]; 123*9a747e4fSDavid du Colombier int blocked; /* In a rendezvous */ 124*9a747e4fSDavid du Colombier int pending; /* delayed note pending */ 125*9a747e4fSDavid du Colombier int nonotes; /* delay notes */ 126*9a747e4fSDavid du Colombier uint nextID; /* ID of most recently created thread */ 127*9a747e4fSDavid du Colombier Proc *next; /* linked list of Procs */ 1287dd7cddfSDavid du Colombier 129*9a747e4fSDavid du Colombier void *arg; /* passed between shared and unshared stk */ 130*9a747e4fSDavid du Colombier char str[ERRMAX]; /* used by threadexits to avoid malloc */ 1317dd7cddfSDavid du Colombier 132*9a747e4fSDavid du Colombier void* udata; /* User per-proc data pointer */ 1337dd7cddfSDavid du Colombier }; 1347dd7cddfSDavid du Colombier 135*9a747e4fSDavid du Colombier struct Pqueue { /* Proc queue */ 1367dd7cddfSDavid du Colombier Lock lock; 1377dd7cddfSDavid du Colombier Proc *head; 138*9a747e4fSDavid du Colombier Proc **tail; 1397dd7cddfSDavid du Colombier }; 1407dd7cddfSDavid du Colombier 141*9a747e4fSDavid du Colombier void _freeproc(Proc*); 142*9a747e4fSDavid du Colombier void _freethread(Thread*); 143*9a747e4fSDavid du Colombier Proc* _newproc(void(*)(void*), void*, uint, char*, int, int); 144*9a747e4fSDavid du Colombier int _procsplhi(void); 145*9a747e4fSDavid du Colombier void _procsplx(int); 146*9a747e4fSDavid du Colombier void _sched(void); 147*9a747e4fSDavid du Colombier int _schedexec(Execargs*); 148*9a747e4fSDavid du Colombier void _schedexecwait(void); 149*9a747e4fSDavid du Colombier void _schedexit(Proc*); 150*9a747e4fSDavid du Colombier int _schedfork(Proc*); 151*9a747e4fSDavid du Colombier void _schedinit(void*); 152*9a747e4fSDavid du Colombier void _systhreadinit(void); 153*9a747e4fSDavid du Colombier void _threadassert(char*); 154*9a747e4fSDavid du Colombier void _threadbreakrendez(void); 155*9a747e4fSDavid du Colombier void _threaddebug(ulong, char*, ...); 156*9a747e4fSDavid du Colombier void _threadexitsall(char*); 157*9a747e4fSDavid du Colombier void _threadflagrendez(Thread*); 158*9a747e4fSDavid du Colombier Proc* _threadgetproc(void); 159*9a747e4fSDavid du Colombier void _threadsetproc(Proc*); 160*9a747e4fSDavid du Colombier void _threadinitstack(Thread*, void(*)(void*), void*); 161*9a747e4fSDavid du Colombier void* _threadmalloc(long, int); 162*9a747e4fSDavid du Colombier void _threadnote(void*, char*); 163*9a747e4fSDavid du Colombier void _threadready(Thread*); 16459cc4ca5SDavid du Colombier ulong _threadrendezvous(ulong, ulong); 165*9a747e4fSDavid du Colombier void _threadsignal(void); 166*9a747e4fSDavid du Colombier void _threadsysfatal(char*, va_list); 1677dd7cddfSDavid du Colombier long _xdec(long*); 168*9a747e4fSDavid du Colombier void _xinc(long*); 169*9a747e4fSDavid du Colombier 170*9a747e4fSDavid du Colombier extern int _threaddebuglevel; 171*9a747e4fSDavid du Colombier extern char* _threadexitsallstatus; 172*9a747e4fSDavid du Colombier extern Pqueue _threadpq; 173*9a747e4fSDavid du Colombier extern Channel* _threadwaitchan; 174*9a747e4fSDavid du Colombier extern Rgrp _threadrgrp; 175*9a747e4fSDavid du Colombier 176*9a747e4fSDavid du Colombier #define DBGAPPL (1 << 0) 177*9a747e4fSDavid du Colombier #define DBGSCHED (1 << 16) 178*9a747e4fSDavid du Colombier #define DBGCHAN (1 << 17) 179*9a747e4fSDavid du Colombier #define DBGREND (1 << 18) 180*9a747e4fSDavid du Colombier /* #define DBGKILL (1 << 19) */ 181*9a747e4fSDavid du Colombier #define DBGNOTE (1 << 20) 182*9a747e4fSDavid du Colombier #define DBGEXEC (1 << 21) 183