aboutsummaryrefslogtreecommitdiff
path: root/src/libthread/threadimpl.h
blob: 8d7a7a75d5dc30eb01af9111011dd01dad90bff7 (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
220
221
222
223
224
225
226
227
228
229
/* 
 * 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; 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.
 */

#include <u.h>
#include <assert.h>
#include <libc.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 Execargs	Execargs;

typedef enum
{
	Dead,
	Running,
	Ready,
	Rendezvous,
} State;
	
typedef enum
{
	Channone,
	Chanalt,
	Chansend,
	Chanrecv,
} Chanstate;

enum
{
	NPRIV = 8,
};

struct Tqueue		/* Thread queue */
{
	int		asleep;
	Thread	*head;
	Thread	*tail;
};

struct Pqueue {		/* Proc queue */
	Lock		lock;
	Proc		*head;
	Proc		**tail;
};

struct Thread
{
	Lock		lock;			/* protects thread data structure */

	int		asleep;		/* thread is in _threadsleep */
	Label	context;		/* for context switches */
	int 		grp;			/* thread group */
	Proc		*homeproc;	/* ``home'' proc */
	int		id;			/* thread id */
	int		moribund;	/* thread needs to die */
	char		*name;		/* name of thread */
	Thread	*next;		/* next on ready queue */
	Thread	*nextt;		/* next on list of threads in this proc */
	Proc		*nextproc;	/* next proc in which to run (rarely changes) */
	State		nextstate;		/* next run state */
	Proc		*proc;		/* proc of this thread */
	Thread	*prevt;		/* prev on list of threads in this proc */
	int		ret;			/* return value for Exec, Fork */
	State		state;		/* run state */
	uchar	*stk;			/* top of stack (lowest address of stack) */
	uint		stksize;		/* stack size */
	void*	udata[NPRIV];	/* User per-thread data pointer */

	/*
	 * for debugging only
	 * (could go away without impacting correct behavior):
	 */

	Channel	*altc;
	_Procrend	altrend;

	Chanstate	chan;		/* which channel operation is current */
	Alt		*alt;			/* pointer to current alt structure (debugging) */
	ulong		userpc;
	Channel	*c;

};

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

struct Proc
{
	Lock		lock;

	Label	context;		/* for context switches */
	Proc		*link;		/* in ptab */
	int		splhi;		/* delay notes */
	Thread	*thread;		/* running thread */
	Thread	*idle;			/* idle thread */
	int		id;
	int		procid;

	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;

	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		(*schedfn)(Proc*);	/* function to call in scheduler */

	_Procrend	rend;	/* sleep here for more ready threads */

	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 */
	int		nsched;

	/*
	 * for debugging only
	 */
	int		pid;			/* process id */
	int		pthreadid;		/* pthread id */
};

void		_swaplabel(Label*, Label*);
Proc*	_newproc(void);
int		_newthread(Proc*, void(*)(void*), void*, uint, char*, int);
int		_procsplhi(void);
void		_procsplx(int);
int		_sched(void);
int		_schedexec(Execargs*);
void		_schedexecwait(void);
void		_schedexit(Proc*);
int		_schedfork(Proc*);
void		_threadfree(Thread*);
void		_threadscheduler(void*);
void		_systhreadinit(void);
void		_threadassert(char*);
void		__threaddebug(ulong, char*, ...);
#define _threaddebug if(!_threaddebuglevel){}else __threaddebug
void		_threadexitsall(char*);
Proc*	_threadgetproc(void);
extern void	_threadmultiproc(void);
Proc*	_threaddelproc(void);
void		_threadinitproc(Proc*);
void		_threadwaitkids(Proc*);
void		_threadsetproc(Proc*);
void		_threadinitstack(Thread*, void(*)(void*), void*);
void		_threadlinkmain(void);
void*	_threadmalloc(long, int);
void		_threadnote(void*, char*);
void		_threadready(Thread*);
void		_threadsetidle(int);
void		_threadsleep(_Procrend*);
void		_threadwakeup(_Procrend*);
void		_threadsignal(void);
void		_threadsysfatal(char*, va_list);
long		_xdec(long*);
void		_xinc(long*);
void		_threadremove(Proc*, Thread*);
void		threadstatus(void);
void		_threadstartproc(Proc*);
void		_threadexitproc(char*);
void		_threadexitallproc(char*);
void		_threadefork(int[3], int[2], char*, char**);

extern int			_threadmainpid;
extern int			_threadnprocs;
extern int			_threaddebuglevel;
extern char*		_threadexitsallstatus;
extern Pqueue		_threadpq;
extern Channel*	_threadwaitchan;

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

extern void _threadmemset(void*, int, int);
extern void _threaddebugmemset(void*, int, int);
extern int _threadprocs;
extern void _threadstacklimit(void*, void*);
extern void _procdelthread(Proc*, Thread*);
extern void _procaddthread(Proc*, Thread*);

extern void _threadafterexec(void);
extern void _threadmaininit(void);
extern void _threadfirstexec(void);
extern int _threadexec(Channel*, int[3], char*, char*[], int);
extern int _callthreadexec(Channel*, int[3], char*, char*[], int);