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