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