19a747e4fSDavid du Colombier /* 29a747e4fSDavid du Colombier * Some notes on locking: 39a747e4fSDavid du Colombier * 49a747e4fSDavid du Colombier * All the locking woes come from implementing 59a747e4fSDavid du Colombier * threadinterrupt (and threadkill). 69a747e4fSDavid du Colombier * 79a747e4fSDavid du Colombier * _threadgetproc()->thread is always a live pointer. 89a747e4fSDavid du Colombier * p->threads, p->ready, and _threadrgrp also contain 99a747e4fSDavid du Colombier * live thread pointers. These may only be consulted 109a747e4fSDavid du Colombier * while holding p->lock or _threadrgrp.lock; in procs 119a747e4fSDavid du Colombier * other than p, the pointers are only guaranteed to be live 129a747e4fSDavid du Colombier * while the lock is still being held. 139a747e4fSDavid du Colombier * 149a747e4fSDavid du Colombier * Thread structures can only be freed by the proc 159a747e4fSDavid du Colombier * they belong to. Threads marked with t->inrendez 169a747e4fSDavid du Colombier * need to be extracted from the _threadrgrp before 179a747e4fSDavid du Colombier * being freed. 189a747e4fSDavid du Colombier * 199a747e4fSDavid du Colombier * _threadrgrp.lock cannot be acquired while holding p->lock. 209a747e4fSDavid du Colombier */ 217dd7cddfSDavid du Colombier 229a747e4fSDavid du Colombier typedef struct Pqueue Pqueue; 239a747e4fSDavid du Colombier typedef struct Rgrp Rgrp; 249a747e4fSDavid du Colombier typedef struct Tqueue Tqueue; 259a747e4fSDavid du Colombier typedef struct Thread Thread; 269a747e4fSDavid du Colombier typedef struct Execargs Execargs; 279a747e4fSDavid du Colombier typedef struct Proc Proc; 289a747e4fSDavid du Colombier 299a747e4fSDavid du Colombier /* must match list in sched.c */ 309a747e4fSDavid du Colombier typedef enum 319a747e4fSDavid du Colombier { 329a747e4fSDavid du Colombier Dead, 337dd7cddfSDavid du Colombier Running, 349a747e4fSDavid du Colombier Ready, 357dd7cddfSDavid du Colombier Rendezvous, 367dd7cddfSDavid du Colombier } State; 377dd7cddfSDavid du Colombier 389a747e4fSDavid du Colombier typedef enum 399a747e4fSDavid du Colombier { 409a747e4fSDavid du Colombier Channone, 419a747e4fSDavid du Colombier Chanalt, 429a747e4fSDavid du Colombier Chansend, 439a747e4fSDavid du Colombier Chanrecv, 449a747e4fSDavid du Colombier } Chanstate; 457dd7cddfSDavid du Colombier 469a747e4fSDavid du Colombier enum 479a747e4fSDavid du Colombier { 489a747e4fSDavid du Colombier RENDHASH = 13, 499a747e4fSDavid du Colombier Printsize = 2048, 507dd7cddfSDavid du Colombier }; 517dd7cddfSDavid du Colombier 529a747e4fSDavid du Colombier struct Rgrp 539a747e4fSDavid du Colombier { 547dd7cddfSDavid du Colombier Lock lock; 559a747e4fSDavid du Colombier Thread *hash[RENDHASH]; 569a747e4fSDavid du Colombier }; 579a747e4fSDavid du Colombier 589a747e4fSDavid du Colombier struct Tqueue /* Thread queue */ 599a747e4fSDavid du Colombier { 609a747e4fSDavid du Colombier int asleep; 617dd7cddfSDavid du Colombier Thread *head; 629a747e4fSDavid du Colombier Thread **tail; 637dd7cddfSDavid du Colombier }; 647dd7cddfSDavid du Colombier 659a747e4fSDavid du Colombier struct Thread 669a747e4fSDavid du Colombier { 679a747e4fSDavid du Colombier Lock lock; /* protects thread data structure */ 689a747e4fSDavid du Colombier jmp_buf sched; /* for context switches */ 699a747e4fSDavid du Colombier int id; /* thread id */ 709a747e4fSDavid du Colombier int grp; /* thread group */ 719a747e4fSDavid du Colombier int moribund; /* thread needs to die */ 729a747e4fSDavid du Colombier State state; /* run state */ 739a747e4fSDavid du Colombier State nextstate; /* next run state */ 749a747e4fSDavid du Colombier uchar *stk; /* top of stack (lowest address of stack) */ 759a747e4fSDavid du Colombier uint stksize; /* stack size */ 769a747e4fSDavid du Colombier Thread *next; /* next on ready queue */ 7780ee5cbfSDavid du Colombier 789a747e4fSDavid du Colombier Proc *proc; /* proc of this thread */ 799a747e4fSDavid du Colombier Thread *nextt; /* next on list of threads in this proc*/ 809a747e4fSDavid du Colombier int ret; /* return value for Exec, Fork */ 819a747e4fSDavid du Colombier 829a747e4fSDavid du Colombier char *cmdname; /* ptr to name of thread */ 839a747e4fSDavid du Colombier 849a747e4fSDavid du Colombier int inrendez; 859a747e4fSDavid du Colombier Thread *rendhash; /* Trgrp linked list */ 869a747e4fSDavid du Colombier ulong rendtag; /* rendezvous tag */ 879a747e4fSDavid du Colombier ulong rendval; /* rendezvous value */ 889a747e4fSDavid du Colombier int rendbreak; /* rendezvous has been taken */ 899a747e4fSDavid du Colombier 909a747e4fSDavid du Colombier Chanstate chan; /* which channel operation is current */ 919a747e4fSDavid du Colombier Alt *alt; /* pointer to current alt structure (debugging) */ 929a747e4fSDavid du Colombier 939a747e4fSDavid du Colombier void* udata; /* User per-thread data pointer */ 947dd7cddfSDavid du Colombier }; 957dd7cddfSDavid du Colombier 969a747e4fSDavid du Colombier struct Execargs 979a747e4fSDavid du Colombier { 989a747e4fSDavid du Colombier char *prog; 999a747e4fSDavid du Colombier char **args; 1009a747e4fSDavid du Colombier int fd[2]; 1019a747e4fSDavid du Colombier }; 1029a747e4fSDavid du Colombier 1039a747e4fSDavid du Colombier struct Proc 1049a747e4fSDavid du Colombier { 1057dd7cddfSDavid du Colombier Lock lock; 1069a747e4fSDavid du Colombier jmp_buf sched; /* for context switches */ 1079a747e4fSDavid du Colombier int pid; /* process id */ 1089a747e4fSDavid du Colombier int splhi; /* delay notes */ 1099a747e4fSDavid du Colombier Thread *thread; /* running thread */ 1107dd7cddfSDavid du Colombier 1119a747e4fSDavid du Colombier int needexec; 1129a747e4fSDavid du Colombier Execargs exec; /* exec argument */ 1139a747e4fSDavid du Colombier Proc *newproc; /* fork argument */ 1149a747e4fSDavid du Colombier char exitstr[ERRMAX]; /* exit status */ 1157dd7cddfSDavid du Colombier 1169a747e4fSDavid du Colombier int rforkflag; 1177dd7cddfSDavid du Colombier int nthreads; 1189a747e4fSDavid du Colombier Tqueue threads; /* All threads of this proc */ 1199a747e4fSDavid du Colombier Tqueue ready; /* Runnable threads */ 1209a747e4fSDavid du Colombier Lock readylock; 1217dd7cddfSDavid du Colombier 1229a747e4fSDavid du Colombier char printbuf[Printsize]; 1239a747e4fSDavid du Colombier int blocked; /* In a rendezvous */ 1249a747e4fSDavid du Colombier int pending; /* delayed note pending */ 1259a747e4fSDavid du Colombier int nonotes; /* delay notes */ 1269a747e4fSDavid du Colombier uint nextID; /* ID of most recently created thread */ 1279a747e4fSDavid du Colombier Proc *next; /* linked list of Procs */ 1287dd7cddfSDavid du Colombier 1299a747e4fSDavid du Colombier void *arg; /* passed between shared and unshared stk */ 1309a747e4fSDavid du Colombier char str[ERRMAX]; /* used by threadexits to avoid malloc */ 1317dd7cddfSDavid du Colombier 1329a747e4fSDavid du Colombier void* udata; /* User per-proc data pointer */ 1337dd7cddfSDavid du Colombier }; 1347dd7cddfSDavid du Colombier 1359a747e4fSDavid du Colombier struct Pqueue { /* Proc queue */ 1367dd7cddfSDavid du Colombier Lock lock; 1377dd7cddfSDavid du Colombier Proc *head; 1389a747e4fSDavid du Colombier Proc **tail; 1397dd7cddfSDavid du Colombier }; 1407dd7cddfSDavid du Colombier 141*3ff48bf5SDavid du Colombier struct Ioproc 142*3ff48bf5SDavid du Colombier { 143*3ff48bf5SDavid du Colombier int pid; 144*3ff48bf5SDavid du Colombier Channel *c; 145*3ff48bf5SDavid du Colombier int inuse; 146*3ff48bf5SDavid du Colombier long (*op)(va_list*); 147*3ff48bf5SDavid du Colombier va_list arg; 148*3ff48bf5SDavid du Colombier long ret; 149*3ff48bf5SDavid du Colombier char err[ERRMAX]; 150*3ff48bf5SDavid du Colombier Ioproc *next; 151*3ff48bf5SDavid du Colombier }; 152*3ff48bf5SDavid du Colombier 1539a747e4fSDavid du Colombier void _freeproc(Proc*); 1549a747e4fSDavid du Colombier void _freethread(Thread*); 1559a747e4fSDavid du Colombier Proc* _newproc(void(*)(void*), void*, uint, char*, int, int); 1569a747e4fSDavid du Colombier int _procsplhi(void); 1579a747e4fSDavid du Colombier void _procsplx(int); 1589a747e4fSDavid du Colombier void _sched(void); 1599a747e4fSDavid du Colombier int _schedexec(Execargs*); 1609a747e4fSDavid du Colombier void _schedexecwait(void); 1619a747e4fSDavid du Colombier void _schedexit(Proc*); 1629a747e4fSDavid du Colombier int _schedfork(Proc*); 1639a747e4fSDavid du Colombier void _schedinit(void*); 1649a747e4fSDavid du Colombier void _systhreadinit(void); 1659a747e4fSDavid du Colombier void _threadassert(char*); 1669a747e4fSDavid du Colombier void _threadbreakrendez(void); 1679a747e4fSDavid du Colombier void _threaddebug(ulong, char*, ...); 1689a747e4fSDavid du Colombier void _threadexitsall(char*); 1699a747e4fSDavid du Colombier void _threadflagrendez(Thread*); 1709a747e4fSDavid du Colombier Proc* _threadgetproc(void); 1719a747e4fSDavid du Colombier void _threadsetproc(Proc*); 1729a747e4fSDavid du Colombier void _threadinitstack(Thread*, void(*)(void*), void*); 1739a747e4fSDavid du Colombier void* _threadmalloc(long, int); 1749a747e4fSDavid du Colombier void _threadnote(void*, char*); 1759a747e4fSDavid du Colombier void _threadready(Thread*); 17659cc4ca5SDavid du Colombier ulong _threadrendezvous(ulong, ulong); 1779a747e4fSDavid du Colombier void _threadsignal(void); 1789a747e4fSDavid du Colombier void _threadsysfatal(char*, va_list); 1797dd7cddfSDavid du Colombier long _xdec(long*); 1809a747e4fSDavid du Colombier void _xinc(long*); 1819a747e4fSDavid du Colombier 1829a747e4fSDavid du Colombier extern int _threaddebuglevel; 1839a747e4fSDavid du Colombier extern char* _threadexitsallstatus; 1849a747e4fSDavid du Colombier extern Pqueue _threadpq; 1859a747e4fSDavid du Colombier extern Channel* _threadwaitchan; 1869a747e4fSDavid du Colombier extern Rgrp _threadrgrp; 1879a747e4fSDavid du Colombier 1889a747e4fSDavid du Colombier #define DBGAPPL (1 << 0) 1899a747e4fSDavid du Colombier #define DBGSCHED (1 << 16) 1909a747e4fSDavid du Colombier #define DBGCHAN (1 << 17) 1919a747e4fSDavid du Colombier #define DBGREND (1 << 18) 1929a747e4fSDavid du Colombier /* #define DBGKILL (1 << 19) */ 1939a747e4fSDavid du Colombier #define DBGNOTE (1 << 20) 1949a747e4fSDavid du Colombier #define DBGEXEC (1 << 21) 195*3ff48bf5SDavid du Colombier 196*3ff48bf5SDavid du Colombier #define ioproc_arg(io, type) (va_arg((io)->arg, type)) 197