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 ulong rendtag; /* rendezvous tag */ 88 ulong 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* udata; /* User per-proc data pointer */ 134 char threadint; /* tag for threadexitsall() */ 135 }; 136 137 struct Pqueue { /* Proc queue */ 138 Lock lock; 139 Proc *head; 140 Proc **tail; 141 }; 142 143 struct Ioproc 144 { 145 int tid; 146 Channel *c, *creply; 147 int inuse; 148 long (*op)(va_list*); 149 va_list arg; 150 long ret; 151 char err[ERRMAX]; 152 Ioproc *next; 153 }; 154 155 void _freeproc(Proc*); 156 void _freethread(Thread*); 157 Proc* _newproc(void(*)(void*), void*, uint, char*, int, int); 158 int _procsplhi(void); 159 void _procsplx(int); 160 void _sched(void); 161 int _schedexec(Execargs*); 162 void _schedexecwait(void); 163 void _schedexit(Proc*); 164 int _schedfork(Proc*); 165 void _schedinit(void*); 166 void _systhreadinit(void); 167 void _threadassert(char*); 168 void _threadbreakrendez(void); 169 void _threaddebug(ulong, char*, ...); 170 void _threadexitsall(char*); 171 void _threadflagrendez(Thread*); 172 Proc* _threadgetproc(void); 173 void _threadsetproc(Proc*); 174 void _threadinitstack(Thread*, void(*)(void*), void*); 175 void* _threadmalloc(long, int); 176 void _threadnote(void*, char*); 177 void _threadready(Thread*); 178 ulong _threadrendezvous(ulong, ulong); 179 void _threadsignal(void); 180 void _threadsysfatal(char*, va_list); 181 long _xdec(long*); 182 void _xinc(long*); 183 184 extern int _threaddebuglevel; 185 extern char* _threadexitsallstatus; 186 extern Pqueue _threadpq; 187 extern Channel* _threadwaitchan; 188 extern Rgrp _threadrgrp; 189 190 #define DBGAPPL (1 << 0) 191 #define DBGSCHED (1 << 16) 192 #define DBGCHAN (1 << 17) 193 #define DBGREND (1 << 18) 194 /* #define DBGKILL (1 << 19) */ 195 #define DBGNOTE (1 << 20) 196 #define DBGEXEC (1 << 21) 197 198 #define ioproc_arg(io, type) (va_arg((io)->arg, type)) 199