xref: /plan9-contrib/sys/src/libthread/threadimpl.h (revision a6a9e07217f318acf170f99684a55fba5200524f)
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 	ulong	rendtag;		/* rendezvous tag */
88 	ulong	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*	udata;		/* User per-proc data pointer */
134 };
135 
136 struct Pqueue {		/* Proc queue */
137 	Lock		lock;
138 	Proc		*head;
139 	Proc		**tail;
140 };
141 
142 struct Ioproc
143 {
144 	int tid;
145 	Channel *c, *creply;
146 	int inuse;
147 	long (*op)(va_list*);
148 	va_list arg;
149 	long ret;
150 	char err[ERRMAX];
151 	Ioproc *next;
152 };
153 
154 void		_freeproc(Proc*);
155 void		_freethread(Thread*);
156 Proc*	_newproc(void(*)(void*), void*, uint, char*, int, int);
157 int		_procsplhi(void);
158 void		_procsplx(int);
159 void		_sched(void);
160 int		_schedexec(Execargs*);
161 void		_schedexecwait(void);
162 void		_schedexit(Proc*);
163 int		_schedfork(Proc*);
164 void		_schedinit(void*);
165 void		_systhreadinit(void);
166 void		_threadassert(char*);
167 void		_threadbreakrendez(void);
168 void		_threaddebug(ulong, char*, ...);
169 void		_threadexitsall(char*);
170 void		_threadflagrendez(Thread*);
171 Proc*	_threadgetproc(void);
172 void		_threadsetproc(Proc*);
173 void		_threadinitstack(Thread*, void(*)(void*), void*);
174 void*	_threadmalloc(long, int);
175 void		_threadnote(void*, char*);
176 void		_threadready(Thread*);
177 ulong	_threadrendezvous(ulong, ulong);
178 void		_threadsignal(void);
179 void		_threadsysfatal(char*, va_list);
180 long		_xdec(long*);
181 void		_xinc(long*);
182 
183 extern int			_threaddebuglevel;
184 extern char*		_threadexitsallstatus;
185 extern Pqueue		_threadpq;
186 extern Channel*	_threadwaitchan;
187 extern Rgrp		_threadrgrp;
188 
189 #define DBGAPPL	(1 << 0)
190 #define DBGSCHED	(1 << 16)
191 #define DBGCHAN	(1 << 17)
192 #define DBGREND	(1 << 18)
193 /* #define DBGKILL	(1 << 19) */
194 #define DBGNOTE	(1 << 20)
195 #define DBGEXEC	(1 << 21)
196 
197 #define ioproc_arg(io, type)	(va_arg((io)->arg, type))
198