aboutsummaryrefslogtreecommitdiff
path: root/src/libthread/threadimpl.h
blob: 24d9b214d3c5d2ab1bb05010c5df248bd22b3e2d (plain)
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
/* 
 * 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"

enum{
STKSIZE = 16384,
STKMAGIC = 0xCAFEBEEF
};

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) */

	void*	udata[NPRIV];	/* User per-thread data pointer */
};

struct Execargs
{
	char		*prog;
	char		**args;
	int		fd[2];
};

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 */

	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 */

	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);
Proc*	_threaddelproc(void);
void		_threadsetproc(Proc*);
void		_threadinitstack(Thread*, void(*)(void*), void*);
void*	_threadmalloc(long, int);
void		_threadnote(void*, char*);
void		_threadready(Thread*);
ulong	_threadrendezvous(ulong, ulong);
void		_threadsignal(void);
void		_threadsysfatal(char*, va_list);
long		_xdec(long*);
void		_xinc(long*);
void		_threadremove(Proc*, Thread*);

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);