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, 507fd46167SDavid du Colombier NPRIV = 8, 517dd7cddfSDavid du Colombier }; 527dd7cddfSDavid du Colombier 539a747e4fSDavid du Colombier struct Rgrp 549a747e4fSDavid du Colombier { 557dd7cddfSDavid du Colombier Lock lock; 569a747e4fSDavid du Colombier Thread *hash[RENDHASH]; 579a747e4fSDavid du Colombier }; 589a747e4fSDavid du Colombier 599a747e4fSDavid du Colombier struct Tqueue /* Thread queue */ 609a747e4fSDavid du Colombier { 619a747e4fSDavid du Colombier int asleep; 627dd7cddfSDavid du Colombier Thread *head; 639a747e4fSDavid du Colombier Thread **tail; 647dd7cddfSDavid du Colombier }; 657dd7cddfSDavid du Colombier 669a747e4fSDavid du Colombier struct Thread 679a747e4fSDavid du Colombier { 689a747e4fSDavid du Colombier Lock lock; /* protects thread data structure */ 699a747e4fSDavid du Colombier jmp_buf sched; /* for context switches */ 709a747e4fSDavid du Colombier int id; /* thread id */ 719a747e4fSDavid du Colombier int grp; /* thread group */ 729a747e4fSDavid du Colombier int moribund; /* thread needs to die */ 739a747e4fSDavid du Colombier State state; /* run state */ 749a747e4fSDavid du Colombier State nextstate; /* next run state */ 759a747e4fSDavid du Colombier uchar *stk; /* top of stack (lowest address of stack) */ 769a747e4fSDavid du Colombier uint stksize; /* stack size */ 779a747e4fSDavid du Colombier Thread *next; /* next on ready queue */ 7880ee5cbfSDavid du Colombier 799a747e4fSDavid du Colombier Proc *proc; /* proc of this thread */ 809a747e4fSDavid du Colombier Thread *nextt; /* next on list of threads in this proc*/ 819a747e4fSDavid du Colombier int ret; /* return value for Exec, Fork */ 829a747e4fSDavid du Colombier 839a747e4fSDavid du Colombier char *cmdname; /* ptr to name of thread */ 849a747e4fSDavid du Colombier 859a747e4fSDavid du Colombier int inrendez; 869a747e4fSDavid du Colombier Thread *rendhash; /* Trgrp linked list */ 8774f16c81SDavid du Colombier void* rendtag; /* rendezvous tag */ 8874f16c81SDavid du Colombier void* rendval; /* rendezvous value */ 899a747e4fSDavid du Colombier int rendbreak; /* rendezvous has been taken */ 909a747e4fSDavid du Colombier 919a747e4fSDavid du Colombier Chanstate chan; /* which channel operation is current */ 929a747e4fSDavid du Colombier Alt *alt; /* pointer to current alt structure (debugging) */ 939a747e4fSDavid du Colombier 947fd46167SDavid du Colombier void* udata[NPRIV]; /* User per-thread data pointer */ 957dd7cddfSDavid du Colombier }; 967dd7cddfSDavid du Colombier 979a747e4fSDavid du Colombier struct Execargs 989a747e4fSDavid du Colombier { 999a747e4fSDavid du Colombier char *prog; 1009a747e4fSDavid du Colombier char **args; 1019a747e4fSDavid du Colombier int fd[2]; 1029a747e4fSDavid du Colombier }; 1039a747e4fSDavid du Colombier 1049a747e4fSDavid du Colombier struct Proc 1059a747e4fSDavid du Colombier { 1067dd7cddfSDavid du Colombier Lock lock; 1079a747e4fSDavid du Colombier jmp_buf sched; /* for context switches */ 1089a747e4fSDavid du Colombier int pid; /* process id */ 1099a747e4fSDavid du Colombier int splhi; /* delay notes */ 1109a747e4fSDavid du Colombier Thread *thread; /* running thread */ 1117dd7cddfSDavid du Colombier 1129a747e4fSDavid du Colombier int needexec; 1139a747e4fSDavid du Colombier Execargs exec; /* exec argument */ 1149a747e4fSDavid du Colombier Proc *newproc; /* fork argument */ 1159a747e4fSDavid du Colombier char exitstr[ERRMAX]; /* exit status */ 1167dd7cddfSDavid du Colombier 1179a747e4fSDavid du Colombier int rforkflag; 1187dd7cddfSDavid du Colombier int nthreads; 1199a747e4fSDavid du Colombier Tqueue threads; /* All threads of this proc */ 1209a747e4fSDavid du Colombier Tqueue ready; /* Runnable threads */ 1219a747e4fSDavid du Colombier Lock readylock; 1227dd7cddfSDavid du Colombier 1239a747e4fSDavid du Colombier char printbuf[Printsize]; 1249a747e4fSDavid du Colombier int blocked; /* In a rendezvous */ 1259a747e4fSDavid du Colombier int pending; /* delayed note pending */ 1269a747e4fSDavid du Colombier int nonotes; /* delay notes */ 1279a747e4fSDavid du Colombier uint nextID; /* ID of most recently created thread */ 1289a747e4fSDavid du Colombier Proc *next; /* linked list of Procs */ 1297dd7cddfSDavid du Colombier 1309a747e4fSDavid du Colombier void *arg; /* passed between shared and unshared stk */ 1319a747e4fSDavid du Colombier char str[ERRMAX]; /* used by threadexits to avoid malloc */ 1327dd7cddfSDavid du Colombier 133d1be6b08SDavid du Colombier void* wdata; /* Lib(worker) per-proc data pointer */ 1349a747e4fSDavid du Colombier void* udata; /* User per-proc data pointer */ 135dc5a79c1SDavid du Colombier char threadint; /* tag for threadexitsall() */ 1367dd7cddfSDavid du Colombier }; 1377dd7cddfSDavid du Colombier 1389a747e4fSDavid du Colombier struct Pqueue { /* Proc queue */ 1397dd7cddfSDavid du Colombier Lock lock; 1407dd7cddfSDavid du Colombier Proc *head; 1419a747e4fSDavid du Colombier Proc **tail; 1427dd7cddfSDavid du Colombier }; 1437dd7cddfSDavid du Colombier 1443ff48bf5SDavid du Colombier struct Ioproc 1453ff48bf5SDavid du Colombier { 1467fd46167SDavid du Colombier int tid; 1477fd46167SDavid du Colombier Channel *c, *creply; 1483ff48bf5SDavid du Colombier int inuse; 1493ff48bf5SDavid du Colombier long (*op)(va_list*); 1503ff48bf5SDavid du Colombier va_list arg; 1513ff48bf5SDavid du Colombier long ret; 1523ff48bf5SDavid du Colombier char err[ERRMAX]; 1533ff48bf5SDavid du Colombier Ioproc *next; 1543ff48bf5SDavid du Colombier }; 1553ff48bf5SDavid du Colombier 1569a747e4fSDavid du Colombier void _freeproc(Proc*); 1579a747e4fSDavid du Colombier void _freethread(Thread*); 1589a747e4fSDavid du Colombier Proc* _newproc(void(*)(void*), void*, uint, char*, int, int); 1599a747e4fSDavid du Colombier int _procsplhi(void); 1609a747e4fSDavid du Colombier void _procsplx(int); 1619a747e4fSDavid du Colombier void _sched(void); 1629a747e4fSDavid du Colombier int _schedexec(Execargs*); 1639a747e4fSDavid du Colombier void _schedexecwait(void); 1649a747e4fSDavid du Colombier void _schedexit(Proc*); 1659a747e4fSDavid du Colombier int _schedfork(Proc*); 1669a747e4fSDavid du Colombier void _schedinit(void*); 1679a747e4fSDavid du Colombier void _systhreadinit(void); 1689a747e4fSDavid du Colombier void _threadassert(char*); 1699a747e4fSDavid du Colombier void _threadbreakrendez(void); 1709a747e4fSDavid du Colombier void _threaddebug(ulong, char*, ...); 1719a747e4fSDavid du Colombier void _threadexitsall(char*); 1729a747e4fSDavid du Colombier void _threadflagrendez(Thread*); 1739a747e4fSDavid du Colombier Proc* _threadgetproc(void); 1749a747e4fSDavid du Colombier void _threadsetproc(Proc*); 1759a747e4fSDavid du Colombier void _threadinitstack(Thread*, void(*)(void*), void*); 1769a747e4fSDavid du Colombier void* _threadmalloc(long, int); 1779a747e4fSDavid du Colombier void _threadnote(void*, char*); 1789a747e4fSDavid du Colombier void _threadready(Thread*); 17974f16c81SDavid du Colombier void* _threadrendezvous(void*, void*); 1809a747e4fSDavid du Colombier void _threadsignal(void); 1819a747e4fSDavid du Colombier void _threadsysfatal(char*, va_list); 182d1be6b08SDavid du Colombier void** _workerdata(void); 183*853458f3SDavid du Colombier void _xinc(long*); 184*853458f3SDavid du Colombier long _xdec(long*); 1859a747e4fSDavid du Colombier 1869a747e4fSDavid du Colombier extern int _threaddebuglevel; 1879a747e4fSDavid du Colombier extern char* _threadexitsallstatus; 1889a747e4fSDavid du Colombier extern Pqueue _threadpq; 1899a747e4fSDavid du Colombier extern Channel* _threadwaitchan; 1909a747e4fSDavid du Colombier extern Rgrp _threadrgrp; 1919a747e4fSDavid du Colombier 1929a747e4fSDavid du Colombier #define DBGAPPL (1 << 0) 1939a747e4fSDavid du Colombier #define DBGSCHED (1 << 16) 1949a747e4fSDavid du Colombier #define DBGCHAN (1 << 17) 1959a747e4fSDavid du Colombier #define DBGREND (1 << 18) 1969a747e4fSDavid du Colombier /* #define DBGKILL (1 << 19) */ 1979a747e4fSDavid du Colombier #define DBGNOTE (1 << 20) 1989a747e4fSDavid du Colombier #define DBGEXEC (1 << 21) 1993ff48bf5SDavid du Colombier 2003ff48bf5SDavid du Colombier #define ioproc_arg(io, type) (va_arg((io)->arg, type)) 201