xref: /plan9-contrib/sys/src/libthread/threadimpl.h (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier /*
2*9a747e4fSDavid du Colombier  * Some notes on locking:
3*9a747e4fSDavid du Colombier  *
4*9a747e4fSDavid du Colombier  *	All the locking woes come from implementing
5*9a747e4fSDavid du Colombier  *	threadinterrupt (and threadkill).
6*9a747e4fSDavid du Colombier  *
7*9a747e4fSDavid du Colombier  *	_threadgetproc()->thread is always a live pointer.
8*9a747e4fSDavid du Colombier  *	p->threads, p->ready, and _threadrgrp also contain
9*9a747e4fSDavid du Colombier  * 	live thread pointers.  These may only be consulted
10*9a747e4fSDavid du Colombier  *	while holding p->lock or _threadrgrp.lock; in procs
11*9a747e4fSDavid du Colombier  *	other than p, the pointers are only guaranteed to be live
12*9a747e4fSDavid du Colombier  *	while the lock is still being held.
13*9a747e4fSDavid du Colombier  *
14*9a747e4fSDavid du Colombier  *	Thread structures can only be freed by the proc
15*9a747e4fSDavid du Colombier  *	they belong to.  Threads marked with t->inrendez
16*9a747e4fSDavid du Colombier  * 	need to be extracted from the _threadrgrp before
17*9a747e4fSDavid du Colombier  *	being freed.
18*9a747e4fSDavid du Colombier  *
19*9a747e4fSDavid du Colombier  *	_threadrgrp.lock cannot be acquired while holding p->lock.
20*9a747e4fSDavid du Colombier  */
217dd7cddfSDavid du Colombier 
22*9a747e4fSDavid du Colombier typedef struct Pqueue	Pqueue;
23*9a747e4fSDavid du Colombier typedef struct Rgrp		Rgrp;
24*9a747e4fSDavid du Colombier typedef struct Tqueue	Tqueue;
25*9a747e4fSDavid du Colombier typedef struct Thread	Thread;
26*9a747e4fSDavid du Colombier typedef struct Execargs	Execargs;
27*9a747e4fSDavid du Colombier typedef struct Proc		Proc;
28*9a747e4fSDavid du Colombier 
29*9a747e4fSDavid du Colombier /* must match list in sched.c */
30*9a747e4fSDavid du Colombier typedef enum
31*9a747e4fSDavid du Colombier {
32*9a747e4fSDavid du Colombier 	Dead,
337dd7cddfSDavid du Colombier 	Running,
34*9a747e4fSDavid du Colombier 	Ready,
357dd7cddfSDavid du Colombier 	Rendezvous,
367dd7cddfSDavid du Colombier } State;
377dd7cddfSDavid du Colombier 
38*9a747e4fSDavid du Colombier typedef enum
39*9a747e4fSDavid du Colombier {
40*9a747e4fSDavid du Colombier 	Channone,
41*9a747e4fSDavid du Colombier 	Chanalt,
42*9a747e4fSDavid du Colombier 	Chansend,
43*9a747e4fSDavid du Colombier 	Chanrecv,
44*9a747e4fSDavid du Colombier } Chanstate;
457dd7cddfSDavid du Colombier 
46*9a747e4fSDavid du Colombier enum
47*9a747e4fSDavid du Colombier {
48*9a747e4fSDavid du Colombier 	RENDHASH = 13,
49*9a747e4fSDavid du Colombier 	Printsize = 2048,
507dd7cddfSDavid du Colombier };
517dd7cddfSDavid du Colombier 
52*9a747e4fSDavid du Colombier struct Rgrp
53*9a747e4fSDavid du Colombier {
547dd7cddfSDavid du Colombier 	Lock		lock;
55*9a747e4fSDavid du Colombier 	Thread	*hash[RENDHASH];
56*9a747e4fSDavid du Colombier };
57*9a747e4fSDavid du Colombier 
58*9a747e4fSDavid du Colombier struct Tqueue		/* Thread queue */
59*9a747e4fSDavid du Colombier {
60*9a747e4fSDavid du Colombier 	int		asleep;
617dd7cddfSDavid du Colombier 	Thread	*head;
62*9a747e4fSDavid du Colombier 	Thread	**tail;
637dd7cddfSDavid du Colombier };
647dd7cddfSDavid du Colombier 
65*9a747e4fSDavid du Colombier struct Thread
66*9a747e4fSDavid du Colombier {
67*9a747e4fSDavid du Colombier 	Lock		lock;			/* protects thread data structure */
68*9a747e4fSDavid du Colombier 	jmp_buf	sched;		/* for context switches */
69*9a747e4fSDavid du Colombier 	int		id;			/* thread id */
70*9a747e4fSDavid du Colombier 	int 		grp;			/* thread group */
71*9a747e4fSDavid du Colombier 	int		moribund;	/* thread needs to die */
72*9a747e4fSDavid du Colombier 	State		state;		/* run state */
73*9a747e4fSDavid du Colombier 	State		nextstate;		/* next run state */
74*9a747e4fSDavid du Colombier 	uchar	*stk;			/* top of stack (lowest address of stack) */
75*9a747e4fSDavid du Colombier 	uint		stksize;		/* stack size */
76*9a747e4fSDavid du Colombier 	Thread	*next;		/* next on ready queue */
7780ee5cbfSDavid du Colombier 
78*9a747e4fSDavid du Colombier 	Proc		*proc;		/* proc of this thread */
79*9a747e4fSDavid du Colombier 	Thread	*nextt;		/* next on list of threads in this proc*/
80*9a747e4fSDavid du Colombier 	int		ret;			/* return value for Exec, Fork */
81*9a747e4fSDavid du Colombier 
82*9a747e4fSDavid du Colombier 	char		*cmdname;	/* ptr to name of thread */
83*9a747e4fSDavid du Colombier 
84*9a747e4fSDavid du Colombier 	int		inrendez;
85*9a747e4fSDavid du Colombier 	Thread	*rendhash;	/* Trgrp linked list */
86*9a747e4fSDavid du Colombier 	ulong	rendtag;		/* rendezvous tag */
87*9a747e4fSDavid du Colombier 	ulong	rendval;		/* rendezvous value */
88*9a747e4fSDavid du Colombier 	int		rendbreak;	/* rendezvous has been taken */
89*9a747e4fSDavid du Colombier 
90*9a747e4fSDavid du Colombier 	Chanstate	chan;		/* which channel operation is current */
91*9a747e4fSDavid du Colombier 	Alt		*alt;			/* pointer to current alt structure (debugging) */
92*9a747e4fSDavid du Colombier 
93*9a747e4fSDavid du Colombier 	void*	udata;		/* User per-thread data pointer */
947dd7cddfSDavid du Colombier };
957dd7cddfSDavid du Colombier 
96*9a747e4fSDavid du Colombier struct Execargs
97*9a747e4fSDavid du Colombier {
98*9a747e4fSDavid du Colombier 	char		*prog;
99*9a747e4fSDavid du Colombier 	char		**args;
100*9a747e4fSDavid du Colombier 	int		fd[2];
101*9a747e4fSDavid du Colombier };
102*9a747e4fSDavid du Colombier 
103*9a747e4fSDavid du Colombier struct Proc
104*9a747e4fSDavid du Colombier {
1057dd7cddfSDavid du Colombier 	Lock		lock;
106*9a747e4fSDavid du Colombier 	jmp_buf	sched;		/* for context switches */
107*9a747e4fSDavid du Colombier 	int		pid;			/* process id */
108*9a747e4fSDavid du Colombier 	int		splhi;		/* delay notes */
109*9a747e4fSDavid du Colombier 	Thread	*thread;		/* running thread */
1107dd7cddfSDavid du Colombier 
111*9a747e4fSDavid du Colombier 	int		needexec;
112*9a747e4fSDavid du Colombier 	Execargs	exec;		/* exec argument */
113*9a747e4fSDavid du Colombier 	Proc		*newproc;	/* fork argument */
114*9a747e4fSDavid du Colombier 	char		exitstr[ERRMAX];	/* exit status */
1157dd7cddfSDavid du Colombier 
116*9a747e4fSDavid du Colombier 	int		rforkflag;
1177dd7cddfSDavid du Colombier 	int		nthreads;
118*9a747e4fSDavid du Colombier 	Tqueue	threads;		/* All threads of this proc */
119*9a747e4fSDavid du Colombier 	Tqueue	ready;		/* Runnable threads */
120*9a747e4fSDavid du Colombier 	Lock		readylock;
1217dd7cddfSDavid du Colombier 
122*9a747e4fSDavid du Colombier 	char		printbuf[Printsize];
123*9a747e4fSDavid du Colombier 	int		blocked;		/* In a rendezvous */
124*9a747e4fSDavid du Colombier 	int		pending;		/* delayed note pending */
125*9a747e4fSDavid du Colombier 	int		nonotes;		/*  delay notes */
126*9a747e4fSDavid du Colombier 	uint		nextID;		/* ID of most recently created thread */
127*9a747e4fSDavid du Colombier 	Proc		*next;		/* linked list of Procs */
1287dd7cddfSDavid du Colombier 
129*9a747e4fSDavid du Colombier 	void		*arg;			/* passed between shared and unshared stk */
130*9a747e4fSDavid du Colombier 	char		str[ERRMAX];	/* used by threadexits to avoid malloc */
1317dd7cddfSDavid du Colombier 
132*9a747e4fSDavid du Colombier 	void*	udata;		/* User per-proc data pointer */
1337dd7cddfSDavid du Colombier };
1347dd7cddfSDavid du Colombier 
135*9a747e4fSDavid du Colombier struct Pqueue {		/* Proc queue */
1367dd7cddfSDavid du Colombier 	Lock		lock;
1377dd7cddfSDavid du Colombier 	Proc		*head;
138*9a747e4fSDavid du Colombier 	Proc		**tail;
1397dd7cddfSDavid du Colombier };
1407dd7cddfSDavid du Colombier 
141*9a747e4fSDavid du Colombier void		_freeproc(Proc*);
142*9a747e4fSDavid du Colombier void		_freethread(Thread*);
143*9a747e4fSDavid du Colombier Proc*	_newproc(void(*)(void*), void*, uint, char*, int, int);
144*9a747e4fSDavid du Colombier int		_procsplhi(void);
145*9a747e4fSDavid du Colombier void		_procsplx(int);
146*9a747e4fSDavid du Colombier void		_sched(void);
147*9a747e4fSDavid du Colombier int		_schedexec(Execargs*);
148*9a747e4fSDavid du Colombier void		_schedexecwait(void);
149*9a747e4fSDavid du Colombier void		_schedexit(Proc*);
150*9a747e4fSDavid du Colombier int		_schedfork(Proc*);
151*9a747e4fSDavid du Colombier void		_schedinit(void*);
152*9a747e4fSDavid du Colombier void		_systhreadinit(void);
153*9a747e4fSDavid du Colombier void		_threadassert(char*);
154*9a747e4fSDavid du Colombier void		_threadbreakrendez(void);
155*9a747e4fSDavid du Colombier void		_threaddebug(ulong, char*, ...);
156*9a747e4fSDavid du Colombier void		_threadexitsall(char*);
157*9a747e4fSDavid du Colombier void		_threadflagrendez(Thread*);
158*9a747e4fSDavid du Colombier Proc*	_threadgetproc(void);
159*9a747e4fSDavid du Colombier void		_threadsetproc(Proc*);
160*9a747e4fSDavid du Colombier void		_threadinitstack(Thread*, void(*)(void*), void*);
161*9a747e4fSDavid du Colombier void*	_threadmalloc(long, int);
162*9a747e4fSDavid du Colombier void		_threadnote(void*, char*);
163*9a747e4fSDavid du Colombier void		_threadready(Thread*);
16459cc4ca5SDavid du Colombier ulong	_threadrendezvous(ulong, ulong);
165*9a747e4fSDavid du Colombier void		_threadsignal(void);
166*9a747e4fSDavid du Colombier void		_threadsysfatal(char*, va_list);
1677dd7cddfSDavid du Colombier long		_xdec(long*);
168*9a747e4fSDavid du Colombier void		_xinc(long*);
169*9a747e4fSDavid du Colombier 
170*9a747e4fSDavid du Colombier extern int			_threaddebuglevel;
171*9a747e4fSDavid du Colombier extern char*		_threadexitsallstatus;
172*9a747e4fSDavid du Colombier extern Pqueue		_threadpq;
173*9a747e4fSDavid du Colombier extern Channel*	_threadwaitchan;
174*9a747e4fSDavid du Colombier extern Rgrp		_threadrgrp;
175*9a747e4fSDavid du Colombier 
176*9a747e4fSDavid du Colombier #define DBGAPPL	(1 << 0)
177*9a747e4fSDavid du Colombier #define DBGSCHED	(1 << 16)
178*9a747e4fSDavid du Colombier #define DBGCHAN	(1 << 17)
179*9a747e4fSDavid du Colombier #define DBGREND	(1 << 18)
180*9a747e4fSDavid du Colombier /* #define DBGKILL	(1 << 19) */
181*9a747e4fSDavid du Colombier #define DBGNOTE	(1 << 20)
182*9a747e4fSDavid du Colombier #define DBGEXEC	(1 << 21)
183