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