1 /* 2 * Some notes on locking: 3 * 4 * All the locking woes come from implementing 5 * threadinterrupt (and threadkill). 6 * 7 * _threadgetproc()->thread is always a live pointer. 8 * p->threads, p->ready, and _threadrgrp also contain 9 * live thread pointers. These may only be consulted 10 * while holding p->lock or _threadrgrp.lock; in procs 11 * other than p, the pointers are only guaranteed to be live 12 * while the lock is still being held. 13 * 14 * Thread structures can only be freed by the proc 15 * they belong to. Threads marked with t->inrendez 16 * need to be extracted from the _threadrgrp before 17 * being freed. 18 * 19 * _threadrgrp.lock cannot be acquired while holding p->lock. 20 */ 21 22 typedef struct Pqueue Pqueue; 23 typedef struct Rgrp Rgrp; 24 typedef struct Tqueue Tqueue; 25 typedef struct Thread Thread; 26 typedef struct Execargs Execargs; 27 typedef struct Execjob Execjob; 28 typedef struct Proc Proc; 29 30 /* must match list in sched.c */ 31 typedef enum 32 { 33 Dead, 34 Running, 35 Ready, 36 Rendezvous, 37 } State; 38 39 typedef enum 40 { 41 Channone, 42 Chanalt, 43 Chansend, 44 Chanrecv, 45 } Chanstate; 46 47 enum 48 { 49 RENDHASH = 13, 50 Printsize = 2048, 51 NPRIV = 8, 52 }; 53 54 struct Rgrp 55 { 56 Lock lock; 57 Thread *hash[RENDHASH]; 58 }; 59 60 struct Tqueue /* Thread queue */ 61 { 62 int asleep; 63 Thread *head; 64 Thread **tail; 65 }; 66 67 struct Thread 68 { 69 Lock lock; /* protects thread data structure */ 70 jmp_buf sched; /* for context switches */ 71 int id; /* thread id */ 72 int grp; /* thread group */ 73 int moribund; /* thread needs to die */ 74 State state; /* run state */ 75 State nextstate; /* next run state */ 76 uchar *stk; /* top of stack (lowest address of stack) */ 77 uint stksize; /* stack size */ 78 Thread *next; /* next on ready queue */ 79 80 Proc *proc; /* proc of this thread */ 81 Thread *nextt; /* next on list of threads in this proc*/ 82 int ret; /* return value for Exec, Fork */ 83 84 char *cmdname; /* ptr to name of thread */ 85 86 int inrendez; 87 Thread *rendhash; /* Trgrp linked list */ 88 void* rendtag; /* rendezvous tag */ 89 void* rendval; /* rendezvous value */ 90 int rendbreak; /* rendezvous has been taken */ 91 92 Chanstate chan; /* which channel operation is current */ 93 Alt *alt; /* pointer to current alt structure (debugging) */ 94 95 void* udata[NPRIV]; /* User per-thread data pointer */ 96 }; 97 98 struct Execargs 99 { 100 char *prog; 101 char **args; 102 int fd[2]; 103 }; 104 105 struct Execjob 106 { 107 int *fd; 108 char *cmd; 109 char **argv; 110 Channel *c; 111 }; 112 113 struct Proc 114 { 115 Lock lock; 116 jmp_buf sched; /* for context switches */ 117 int pid; /* process id */ 118 int splhi; /* delay notes */ 119 Thread *thread; /* running thread */ 120 121 int needexec; 122 Execargs exec; /* exec argument */ 123 Proc *newproc; /* fork argument */ 124 char exitstr[ERRMAX]; /* exit status */ 125 126 int rforkflag; 127 int nthreads; 128 Tqueue threads; /* All threads of this proc */ 129 Tqueue ready; /* Runnable threads */ 130 Lock readylock; 131 132 char printbuf[Printsize]; 133 int blocked; /* In a rendezvous */ 134 int pending; /* delayed note pending */ 135 int nonotes; /* delay notes */ 136 uint nextID; /* ID of most recently created thread */ 137 Proc *next; /* linked list of Procs */ 138 139 void *arg; /* passed between shared and unshared stk */ 140 char str[ERRMAX]; /* used by threadexits to avoid malloc */ 141 142 void* wdata; /* Lib(worker) per-proc data pointer */ 143 void* udata; /* User per-proc data pointer */ 144 char threadint; /* tag for threadexitsall() */ 145 }; 146 147 struct Pqueue { /* Proc queue */ 148 Lock lock; 149 Proc *head; 150 Proc **tail; 151 }; 152 153 struct Ioproc 154 { 155 int tid; 156 Channel *c, *creply; 157 int inuse; 158 long (*op)(va_list*); 159 va_list arg; 160 long ret; 161 char err[ERRMAX]; 162 Ioproc *next; 163 }; 164 165 void _freeproc(Proc*); 166 void _freethread(Thread*); 167 Proc* _newproc(void(*)(void*), void*, uint, char*, int, int); 168 int _procsplhi(void); 169 void _procsplx(int); 170 void _sched(void); 171 int _schedexec(Execargs*); 172 void _schedexecwait(void); 173 void _schedexit(Proc*); 174 int _schedfork(Proc*); 175 void _schedinit(void*); 176 void _systhreadinit(void); 177 void _threadassert(char*); 178 void _threadbreakrendez(void); 179 void _threaddebug(ulong, char*, ...); 180 void _threadexitsall(char*); 181 void _threadflagrendez(Thread*); 182 Proc* _threadgetproc(void); 183 void _threadsetproc(Proc*); 184 void _threadinitstack(Thread*, void(*)(void*), void*); 185 void* _threadmalloc(long, int); 186 void _threadnote(void*, char*); 187 void _threadready(Thread*); 188 void* _threadrendezvous(void*, void*); 189 void _threadsignal(void); 190 void _threadsysfatal(char*, va_list); 191 void** _workerdata(void); 192 void _xinc(long*); 193 long _xdec(long*); 194 195 extern int _threaddebuglevel; 196 extern char* _threadexitsallstatus; 197 extern Pqueue _threadpq; 198 extern Channel* _threadwaitchan; 199 extern Rgrp _threadrgrp; 200 201 #define DBGAPPL (1 << 0) 202 #define DBGSCHED (1 << 16) 203 #define DBGCHAN (1 << 17) 204 #define DBGREND (1 << 18) 205 /* #define DBGKILL (1 << 19) */ 206 #define DBGNOTE (1 << 20) 207 #define DBGEXEC (1 << 21) 208 209 #define ioproc_arg(io, type) (va_arg((io)->arg, type)) 210