Blob


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