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; 27*e7469f7cSDavid du Colombier typedef struct Execjob Execjob; 289a747e4fSDavid du Colombier typedef struct Proc Proc; 299a747e4fSDavid du Colombier 309a747e4fSDavid du Colombier /* must match list in sched.c */ 319a747e4fSDavid du Colombier typedef enum 329a747e4fSDavid du Colombier { 339a747e4fSDavid du Colombier Dead, 347dd7cddfSDavid du Colombier Running, 359a747e4fSDavid du Colombier Ready, 367dd7cddfSDavid du Colombier Rendezvous, 377dd7cddfSDavid du Colombier } State; 387dd7cddfSDavid du Colombier 399a747e4fSDavid du Colombier typedef enum 409a747e4fSDavid du Colombier { 419a747e4fSDavid du Colombier Channone, 429a747e4fSDavid du Colombier Chanalt, 439a747e4fSDavid du Colombier Chansend, 449a747e4fSDavid du Colombier Chanrecv, 459a747e4fSDavid du Colombier } Chanstate; 467dd7cddfSDavid du Colombier 479a747e4fSDavid du Colombier enum 489a747e4fSDavid du Colombier { 499a747e4fSDavid du Colombier RENDHASH = 13, 509a747e4fSDavid du Colombier Printsize = 2048, 517fd46167SDavid du Colombier NPRIV = 8, 527dd7cddfSDavid du Colombier }; 537dd7cddfSDavid du Colombier 549a747e4fSDavid du Colombier struct Rgrp 559a747e4fSDavid du Colombier { 567dd7cddfSDavid du Colombier Lock lock; 579a747e4fSDavid du Colombier Thread *hash[RENDHASH]; 589a747e4fSDavid du Colombier }; 599a747e4fSDavid du Colombier 609a747e4fSDavid du Colombier struct Tqueue /* Thread queue */ 619a747e4fSDavid du Colombier { 629a747e4fSDavid du Colombier int asleep; 637dd7cddfSDavid du Colombier Thread *head; 649a747e4fSDavid du Colombier Thread **tail; 657dd7cddfSDavid du Colombier }; 667dd7cddfSDavid du Colombier 679a747e4fSDavid du Colombier struct Thread 689a747e4fSDavid du Colombier { 699a747e4fSDavid du Colombier Lock lock; /* protects thread data structure */ 709a747e4fSDavid du Colombier jmp_buf sched; /* for context switches */ 719a747e4fSDavid du Colombier int id; /* thread id */ 729a747e4fSDavid du Colombier int grp; /* thread group */ 739a747e4fSDavid du Colombier int moribund; /* thread needs to die */ 749a747e4fSDavid du Colombier State state; /* run state */ 759a747e4fSDavid du Colombier State nextstate; /* next run state */ 769a747e4fSDavid du Colombier uchar *stk; /* top of stack (lowest address of stack) */ 779a747e4fSDavid du Colombier uint stksize; /* stack size */ 789a747e4fSDavid du Colombier Thread *next; /* next on ready queue */ 7980ee5cbfSDavid du Colombier 809a747e4fSDavid du Colombier Proc *proc; /* proc of this thread */ 819a747e4fSDavid du Colombier Thread *nextt; /* next on list of threads in this proc*/ 829a747e4fSDavid du Colombier int ret; /* return value for Exec, Fork */ 839a747e4fSDavid du Colombier 849a747e4fSDavid du Colombier char *cmdname; /* ptr to name of thread */ 859a747e4fSDavid du Colombier 869a747e4fSDavid du Colombier int inrendez; 879a747e4fSDavid du Colombier Thread *rendhash; /* Trgrp linked list */ 8874f16c81SDavid du Colombier void* rendtag; /* rendezvous tag */ 8974f16c81SDavid du Colombier void* rendval; /* rendezvous value */ 909a747e4fSDavid du Colombier int rendbreak; /* rendezvous has been taken */ 919a747e4fSDavid du Colombier 929a747e4fSDavid du Colombier Chanstate chan; /* which channel operation is current */ 939a747e4fSDavid du Colombier Alt *alt; /* pointer to current alt structure (debugging) */ 949a747e4fSDavid du Colombier 957fd46167SDavid du Colombier void* udata[NPRIV]; /* User per-thread data pointer */ 967dd7cddfSDavid du Colombier }; 977dd7cddfSDavid du Colombier 989a747e4fSDavid du Colombier struct Execargs 999a747e4fSDavid du Colombier { 1009a747e4fSDavid du Colombier char *prog; 1019a747e4fSDavid du Colombier char **args; 1029a747e4fSDavid du Colombier int fd[2]; 1039a747e4fSDavid du Colombier }; 1049a747e4fSDavid du Colombier 105*e7469f7cSDavid du Colombier struct Execjob 106*e7469f7cSDavid du Colombier { 107*e7469f7cSDavid du Colombier int *fd; 108*e7469f7cSDavid du Colombier char *cmd; 109*e7469f7cSDavid du Colombier char **argv; 110*e7469f7cSDavid du Colombier Channel *c; 111*e7469f7cSDavid du Colombier }; 112*e7469f7cSDavid du Colombier 1139a747e4fSDavid du Colombier struct Proc 1149a747e4fSDavid du Colombier { 1157dd7cddfSDavid du Colombier Lock lock; 1169a747e4fSDavid du Colombier jmp_buf sched; /* for context switches */ 1179a747e4fSDavid du Colombier int pid; /* process id */ 1189a747e4fSDavid du Colombier int splhi; /* delay notes */ 1199a747e4fSDavid du Colombier Thread *thread; /* running thread */ 1207dd7cddfSDavid du Colombier 1219a747e4fSDavid du Colombier int needexec; 1229a747e4fSDavid du Colombier Execargs exec; /* exec argument */ 1239a747e4fSDavid du Colombier Proc *newproc; /* fork argument */ 1249a747e4fSDavid du Colombier char exitstr[ERRMAX]; /* exit status */ 1257dd7cddfSDavid du Colombier 1269a747e4fSDavid du Colombier int rforkflag; 1277dd7cddfSDavid du Colombier int nthreads; 1289a747e4fSDavid du Colombier Tqueue threads; /* All threads of this proc */ 1299a747e4fSDavid du Colombier Tqueue ready; /* Runnable threads */ 1309a747e4fSDavid du Colombier Lock readylock; 1317dd7cddfSDavid du Colombier 1329a747e4fSDavid du Colombier char printbuf[Printsize]; 1339a747e4fSDavid du Colombier int blocked; /* In a rendezvous */ 1349a747e4fSDavid du Colombier int pending; /* delayed note pending */ 1359a747e4fSDavid du Colombier int nonotes; /* delay notes */ 1369a747e4fSDavid du Colombier uint nextID; /* ID of most recently created thread */ 1379a747e4fSDavid du Colombier Proc *next; /* linked list of Procs */ 1387dd7cddfSDavid du Colombier 1399a747e4fSDavid du Colombier void *arg; /* passed between shared and unshared stk */ 1409a747e4fSDavid du Colombier char str[ERRMAX]; /* used by threadexits to avoid malloc */ 1417dd7cddfSDavid du Colombier 142d1be6b08SDavid du Colombier void* wdata; /* Lib(worker) per-proc data pointer */ 1439a747e4fSDavid du Colombier void* udata; /* User per-proc data pointer */ 144dc5a79c1SDavid du Colombier char threadint; /* tag for threadexitsall() */ 1457dd7cddfSDavid du Colombier }; 1467dd7cddfSDavid du Colombier 1479a747e4fSDavid du Colombier struct Pqueue { /* Proc queue */ 1487dd7cddfSDavid du Colombier Lock lock; 1497dd7cddfSDavid du Colombier Proc *head; 1509a747e4fSDavid du Colombier Proc **tail; 1517dd7cddfSDavid du Colombier }; 1527dd7cddfSDavid du Colombier 1533ff48bf5SDavid du Colombier struct Ioproc 1543ff48bf5SDavid du Colombier { 1557fd46167SDavid du Colombier int tid; 1567fd46167SDavid du Colombier Channel *c, *creply; 1573ff48bf5SDavid du Colombier int inuse; 1583ff48bf5SDavid du Colombier long (*op)(va_list*); 1593ff48bf5SDavid du Colombier va_list arg; 1603ff48bf5SDavid du Colombier long ret; 1613ff48bf5SDavid du Colombier char err[ERRMAX]; 1623ff48bf5SDavid du Colombier Ioproc *next; 1633ff48bf5SDavid du Colombier }; 1643ff48bf5SDavid du Colombier 1659a747e4fSDavid du Colombier void _freeproc(Proc*); 1669a747e4fSDavid du Colombier void _freethread(Thread*); 1679a747e4fSDavid du Colombier Proc* _newproc(void(*)(void*), void*, uint, char*, int, int); 1689a747e4fSDavid du Colombier int _procsplhi(void); 1699a747e4fSDavid du Colombier void _procsplx(int); 1709a747e4fSDavid du Colombier void _sched(void); 1719a747e4fSDavid du Colombier int _schedexec(Execargs*); 1729a747e4fSDavid du Colombier void _schedexecwait(void); 1739a747e4fSDavid du Colombier void _schedexit(Proc*); 1749a747e4fSDavid du Colombier int _schedfork(Proc*); 1759a747e4fSDavid du Colombier void _schedinit(void*); 1769a747e4fSDavid du Colombier void _systhreadinit(void); 1779a747e4fSDavid du Colombier void _threadassert(char*); 1789a747e4fSDavid du Colombier void _threadbreakrendez(void); 1799a747e4fSDavid du Colombier void _threaddebug(ulong, char*, ...); 1809a747e4fSDavid du Colombier void _threadexitsall(char*); 1819a747e4fSDavid du Colombier void _threadflagrendez(Thread*); 1829a747e4fSDavid du Colombier Proc* _threadgetproc(void); 1839a747e4fSDavid du Colombier void _threadsetproc(Proc*); 1849a747e4fSDavid du Colombier void _threadinitstack(Thread*, void(*)(void*), void*); 1859a747e4fSDavid du Colombier void* _threadmalloc(long, int); 1869a747e4fSDavid du Colombier void _threadnote(void*, char*); 1879a747e4fSDavid du Colombier void _threadready(Thread*); 18874f16c81SDavid du Colombier void* _threadrendezvous(void*, void*); 1899a747e4fSDavid du Colombier void _threadsignal(void); 1909a747e4fSDavid du Colombier void _threadsysfatal(char*, va_list); 191d1be6b08SDavid du Colombier void** _workerdata(void); 192853458f3SDavid du Colombier void _xinc(long*); 193853458f3SDavid du Colombier long _xdec(long*); 1949a747e4fSDavid du Colombier 1959a747e4fSDavid du Colombier extern int _threaddebuglevel; 1969a747e4fSDavid du Colombier extern char* _threadexitsallstatus; 1979a747e4fSDavid du Colombier extern Pqueue _threadpq; 1989a747e4fSDavid du Colombier extern Channel* _threadwaitchan; 1999a747e4fSDavid du Colombier extern Rgrp _threadrgrp; 2009a747e4fSDavid du Colombier 2019a747e4fSDavid du Colombier #define DBGAPPL (1 << 0) 2029a747e4fSDavid du Colombier #define DBGSCHED (1 << 16) 2039a747e4fSDavid du Colombier #define DBGCHAN (1 << 17) 2049a747e4fSDavid du Colombier #define DBGREND (1 << 18) 2059a747e4fSDavid du Colombier /* #define DBGKILL (1 << 19) */ 2069a747e4fSDavid du Colombier #define DBGNOTE (1 << 20) 2079a747e4fSDavid du Colombier #define DBGEXEC (1 << 21) 2083ff48bf5SDavid du Colombier 2093ff48bf5SDavid du Colombier #define ioproc_arg(io, type) (va_arg((io)->arg, type)) 210