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; in procs other than p, the
11 * pointers are only guaranteed to be live while the lock
12 * 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 */
20 #include <u.h>
21 #include <assert.h>
22 #include <libc.h>
23 #include <thread.h>
24 #include "label.h"
26 typedef struct Thread Thread;
27 typedef struct Proc Proc;
28 typedef struct Tqueue Tqueue;
29 typedef struct Pqueue Pqueue;
30 typedef struct Execargs Execargs;
32 typedef enum
33 {
34 Dead,
35 Running,
36 Ready,
37 Rendezvous,
38 } State;
40 typedef enum
41 {
42 Channone,
43 Chanalt,
44 Chansend,
45 Chanrecv,
46 } Chanstate;
48 enum
49 {
50 NPRIV = 8,
51 };
53 struct Tqueue /* Thread queue */
54 {
55 int asleep;
56 Thread *head;
57 Thread *tail;
58 };
60 struct Pqueue { /* Proc queue */
61 Lock lock;
62 Proc *head;
63 Proc **tail;
64 };
66 struct Thread
67 {
68 Lock lock; /* protects thread data structure */
70 int asleep; /* thread is in _threadsleep */
71 Label context; /* for context switches */
72 int grp; /* thread group */
73 int id; /* thread id */
74 int moribund; /* thread needs to die */
75 char *name; /* name of thread */
76 Thread *next; /* next on ready queue */
77 Thread *nextt; /* next on list of threads in this proc */
78 State nextstate; /* next run state */
79 Proc *proc; /* proc of this thread */
80 Thread *prevt; /* prev on list of threads in this proc */
81 int ret; /* return value for Exec, Fork */
82 State state; /* run state */
83 uchar *stk; /* top of stack (lowest address of stack) */
84 uint stksize; /* stack size */
85 void* udata[NPRIV]; /* User per-thread data pointer */
87 /*
88 * for debugging only
89 * (could go away without impacting correct behavior):
90 */
92 Channel *altc;
93 _Procrend altrend;
95 Chanstate chan; /* which channel operation is current */
96 Alt *alt; /* pointer to current alt structure (debugging) */
97 ulong userpc;
98 Channel *c;
100 };
102 struct Execargs
104 char *prog;
105 char **args;
106 int fd[2];
107 int *stdfd;
108 };
110 struct Proc
112 Lock lock;
114 Label context; /* for context switches */
115 Proc *link; /* in ptab */
116 int splhi; /* delay notes */
117 Thread *thread; /* running thread */
118 Thread *idle; /* idle thread */
119 int id;
121 int needexec;
122 Execargs exec; /* exec argument */
123 Proc *newproc; /* fork argument */
124 char exitstr[ERRMAX]; /* exit status */
126 int rforkflag;
127 int nthreads;
128 Tqueue threads; /* All threads of this proc */
129 Tqueue ready; /* Runnable threads */
130 Lock readylock;
132 int blocked; /* In a rendezvous */
133 int pending; /* delayed note pending */
134 int nonotes; /* delay notes */
135 uint nextID; /* ID of most recently created thread */
136 Proc *next; /* linked list of Procs */
139 void (*schedfn)(Proc*); /* function to call in scheduler */
141 _Procrend rend; /* sleep here for more ready threads */
143 void *arg; /* passed between shared and unshared stk */
144 char str[ERRMAX]; /* used by threadexits to avoid malloc */
145 char errbuf[ERRMAX]; /* errstr */
146 Waitmsg *waitmsg;
148 void* udata; /* User per-proc data pointer */
149 int nsched;
151 /*
152 * for debugging only
153 */
154 int pid; /* process id */
155 int pthreadid; /* pthread id */
156 };
158 void _swaplabel(Label*, Label*);
159 Proc* _newproc(void);
160 int _newthread(Proc*, void(*)(void*), void*, uint, char*, int);
161 int _procsplhi(void);
162 void _procsplx(int);
163 int _sched(void);
164 int _schedexec(Execargs*);
165 void _schedexecwait(void);
166 void _schedexit(Proc*);
167 int _schedfork(Proc*);
168 void _threadfree(Thread*);
169 void _threadscheduler(void*);
170 void _systhreadinit(void);
171 void _threadassert(char*);
172 void __threaddebug(ulong, char*, ...);
173 #define _threaddebug if(!_threaddebuglevel){}else __threaddebug
174 void _threadexitsall(char*);
175 Proc* _threadgetproc(void);
176 extern void _threadmultiproc(void);
177 Proc* _threaddelproc(void);
178 void _threadinitproc(Proc*);
179 void _threadwaitkids(Proc*);
180 void _threadsetproc(Proc*);
181 void _threadinitstack(Thread*, void(*)(void*), void*);
182 void _threadlinkmain(void);
183 void* _threadmalloc(long, int);
184 void _threadnote(void*, char*);
185 void _threadready(Thread*);
186 void _threadsetidle(int);
187 void _threadsleep(_Procrend*);
188 void _threadwakeup(_Procrend*);
189 void _threadsignal(void);
190 void _threadsysfatal(char*, va_list);
191 long _xdec(long*);
192 void _xinc(long*);
193 void _threadremove(Proc*, Thread*);
194 void threadstatus(void);
195 void _threadstartproc(Proc*);
196 void _threadexitproc(char*);
197 void _threadexitallproc(char*);
199 extern int _threadnprocs;
200 extern int _threaddebuglevel;
201 extern char* _threadexitsallstatus;
202 extern Pqueue _threadpq;
203 extern Channel* _threadwaitchan;
205 #define DBGAPPL (1 << 0)
206 #define DBGSCHED (1 << 16)
207 #define DBGCHAN (1 << 17)
208 #define DBGREND (1 << 18)
209 /* #define DBGKILL (1 << 19) */
210 #define DBGNOTE (1 << 20)
211 #define DBGEXEC (1 << 21)
213 extern void _threadmemset(void*, int, int);
214 extern void _threaddebugmemset(void*, int, int);
215 extern int _threadprocs;
216 extern void _threadstacklimit(void*, void*);