xref: /plan9-contrib/sys/src/libthread/threadimpl.h (revision e7469f7cc458260881920c645908657cf1c4e7b7)
19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier  * Some notes on locking:
39a747e4fSDavid du Colombier  *
49a747e4fSDavid du Colombier  *	All the locking woes come from implementing
59a747e4fSDavid du Colombier  *	threadinterrupt (and threadkill).
69a747e4fSDavid du Colombier  *
79a747e4fSDavid du Colombier  *	_threadgetproc()->thread is always a live pointer.
89a747e4fSDavid du Colombier  *	p->threads, p->ready, and _threadrgrp also contain
99a747e4fSDavid du Colombier  * 	live thread pointers.  These may only be consulted
109a747e4fSDavid du Colombier  *	while holding p->lock or _threadrgrp.lock; in procs
119a747e4fSDavid du Colombier  *	other than p, the pointers are only guaranteed to be live
129a747e4fSDavid du Colombier  *	while the lock is still being held.
139a747e4fSDavid du Colombier  *
149a747e4fSDavid du Colombier  *	Thread structures can only be freed by the proc
159a747e4fSDavid du Colombier  *	they belong to.  Threads marked with t->inrendez
169a747e4fSDavid du Colombier  * 	need to be extracted from the _threadrgrp before
179a747e4fSDavid du Colombier  *	being freed.
189a747e4fSDavid du Colombier  *
199a747e4fSDavid du Colombier  *	_threadrgrp.lock cannot be acquired while holding p->lock.
209a747e4fSDavid du Colombier  */
217dd7cddfSDavid du Colombier 
229a747e4fSDavid du Colombier typedef struct Pqueue	Pqueue;
239a747e4fSDavid du Colombier typedef struct Rgrp		Rgrp;
249a747e4fSDavid du Colombier typedef struct Tqueue	Tqueue;
259a747e4fSDavid du Colombier typedef struct Thread	Thread;
269a747e4fSDavid du Colombier typedef struct Execargs	Execargs;
27*e7469f7cSDavid du Colombier typedef struct Execjob	Execjob;
289a747e4fSDavid du Colombier typedef struct Proc		Proc;
299a747e4fSDavid du Colombier 
309a747e4fSDavid du Colombier /* must match list in sched.c */
319a747e4fSDavid du Colombier typedef enum
329a747e4fSDavid du Colombier {
339a747e4fSDavid du Colombier 	Dead,
347dd7cddfSDavid du Colombier 	Running,
359a747e4fSDavid du Colombier 	Ready,
367dd7cddfSDavid du Colombier 	Rendezvous,
377dd7cddfSDavid du Colombier } State;
387dd7cddfSDavid du Colombier 
399a747e4fSDavid du Colombier typedef enum
409a747e4fSDavid du Colombier {
419a747e4fSDavid du Colombier 	Channone,
429a747e4fSDavid du Colombier 	Chanalt,
439a747e4fSDavid du Colombier 	Chansend,
449a747e4fSDavid du Colombier 	Chanrecv,
459a747e4fSDavid du Colombier } Chanstate;
467dd7cddfSDavid du Colombier 
479a747e4fSDavid du Colombier enum
489a747e4fSDavid du Colombier {
499a747e4fSDavid du Colombier 	RENDHASH = 13,
509a747e4fSDavid du Colombier 	Printsize = 2048,
517fd46167SDavid du Colombier 	NPRIV = 8,
527dd7cddfSDavid du Colombier };
537dd7cddfSDavid du Colombier 
549a747e4fSDavid du Colombier struct Rgrp
559a747e4fSDavid du Colombier {
567dd7cddfSDavid du Colombier 	Lock		lock;
579a747e4fSDavid du Colombier 	Thread	*hash[RENDHASH];
589a747e4fSDavid du Colombier };
599a747e4fSDavid du Colombier 
609a747e4fSDavid du Colombier struct Tqueue		/* Thread queue */
619a747e4fSDavid du Colombier {
629a747e4fSDavid du Colombier 	int		asleep;
637dd7cddfSDavid du Colombier 	Thread	*head;
649a747e4fSDavid du Colombier 	Thread	**tail;
657dd7cddfSDavid du Colombier };
667dd7cddfSDavid du Colombier 
679a747e4fSDavid du Colombier struct Thread
689a747e4fSDavid du Colombier {
699a747e4fSDavid du Colombier 	Lock		lock;		/* protects thread data structure */
709a747e4fSDavid du Colombier 	jmp_buf		sched;		/* for context switches */
719a747e4fSDavid du Colombier 	int		id;		/* thread id */
729a747e4fSDavid du Colombier 	int 		grp;		/* thread group */
739a747e4fSDavid du Colombier 	int		moribund;	/* thread needs to die */
749a747e4fSDavid du Colombier 	State		state;		/* run state */
759a747e4fSDavid du Colombier 	State		nextstate;	/* next run state */
769a747e4fSDavid du Colombier 	uchar		*stk;		/* top of stack (lowest address of stack) */
779a747e4fSDavid du Colombier 	uint		stksize;	/* stack size */
789a747e4fSDavid du Colombier 	Thread		*next;		/* next on ready queue */
7980ee5cbfSDavid du Colombier 
809a747e4fSDavid du Colombier 	Proc		*proc;		/* proc of this thread */
819a747e4fSDavid du Colombier 	Thread		*nextt;		/* next on list of threads in this proc*/
829a747e4fSDavid du Colombier 	int		ret;		/* return value for Exec, Fork */
839a747e4fSDavid du Colombier 
849a747e4fSDavid du Colombier 	char		*cmdname;	/* ptr to name of thread */
859a747e4fSDavid du Colombier 
869a747e4fSDavid du Colombier 	int		inrendez;
879a747e4fSDavid du Colombier 	Thread		*rendhash;	/* Trgrp linked list */
8874f16c81SDavid du Colombier 	void*		rendtag;	/* rendezvous tag */
8974f16c81SDavid du Colombier 	void*		rendval;	/* rendezvous value */
909a747e4fSDavid du Colombier 	int		rendbreak;	/* rendezvous has been taken */
919a747e4fSDavid du Colombier 
929a747e4fSDavid du Colombier 	Chanstate	chan;		/* which channel operation is current */
939a747e4fSDavid du Colombier 	Alt		*alt;		/* pointer to current alt structure (debugging) */
949a747e4fSDavid du Colombier 
957fd46167SDavid du Colombier 	void*	udata[NPRIV];	/* User per-thread data pointer */
967dd7cddfSDavid du Colombier };
977dd7cddfSDavid du Colombier 
989a747e4fSDavid du Colombier struct Execargs
999a747e4fSDavid du Colombier {
1009a747e4fSDavid du Colombier 	char		*prog;
1019a747e4fSDavid du Colombier 	char		**args;
1029a747e4fSDavid du Colombier 	int		fd[2];
1039a747e4fSDavid du Colombier };
1049a747e4fSDavid du Colombier 
105*e7469f7cSDavid du Colombier struct Execjob
106*e7469f7cSDavid du Colombier {
107*e7469f7cSDavid du Colombier 	int *fd;
108*e7469f7cSDavid du Colombier 	char *cmd;
109*e7469f7cSDavid du Colombier 	char **argv;
110*e7469f7cSDavid du Colombier 	Channel *c;
111*e7469f7cSDavid du Colombier };
112*e7469f7cSDavid du Colombier 
1139a747e4fSDavid du Colombier struct Proc
1149a747e4fSDavid du Colombier {
1157dd7cddfSDavid du Colombier 	Lock		lock;
1169a747e4fSDavid du Colombier 	jmp_buf		sched;			/* for context switches */
1179a747e4fSDavid du Colombier 	int		pid;			/* process id */
1189a747e4fSDavid du Colombier 	int		splhi;			/* delay notes */
1199a747e4fSDavid du Colombier 	Thread		*thread;		/* running thread */
1207dd7cddfSDavid du Colombier 
1219a747e4fSDavid du Colombier 	int		needexec;
1229a747e4fSDavid du Colombier 	Execargs	exec;			/* exec argument */
1239a747e4fSDavid du Colombier 	Proc		*newproc;		/* fork argument */
1249a747e4fSDavid du Colombier 	char		exitstr[ERRMAX];	/* exit status */
1257dd7cddfSDavid du Colombier 
1269a747e4fSDavid du Colombier 	int		rforkflag;
1277dd7cddfSDavid du Colombier 	int		nthreads;
1289a747e4fSDavid du Colombier 	Tqueue		threads;		/* All threads of this proc */
1299a747e4fSDavid du Colombier 	Tqueue		ready;			/* Runnable threads */
1309a747e4fSDavid du Colombier 	Lock		readylock;
1317dd7cddfSDavid du Colombier 
1329a747e4fSDavid du Colombier 	char		printbuf[Printsize];
1339a747e4fSDavid du Colombier 	int		blocked;		/* In a rendezvous */
1349a747e4fSDavid du Colombier 	int		pending;		/* delayed note pending */
1359a747e4fSDavid du Colombier 	int		nonotes;		/*  delay notes */
1369a747e4fSDavid du Colombier 	uint		nextID;			/* ID of most recently created thread */
1379a747e4fSDavid du Colombier 	Proc		*next;			/* linked list of Procs */
1387dd7cddfSDavid du Colombier 
1399a747e4fSDavid du Colombier 	void		*arg;			/* passed between shared and unshared stk */
1409a747e4fSDavid du Colombier 	char		str[ERRMAX];		/* used by threadexits to avoid malloc */
1417dd7cddfSDavid du Colombier 
142d1be6b08SDavid du Colombier 	void*		wdata;			/* Lib(worker) per-proc data pointer */
1439a747e4fSDavid du Colombier 	void*		udata;			/* User per-proc data pointer */
144dc5a79c1SDavid du Colombier 	char		threadint;		/* tag for threadexitsall() */
1457dd7cddfSDavid du Colombier };
1467dd7cddfSDavid du Colombier 
1479a747e4fSDavid du Colombier struct Pqueue {		/* Proc queue */
1487dd7cddfSDavid du Colombier 	Lock		lock;
1497dd7cddfSDavid du Colombier 	Proc		*head;
1509a747e4fSDavid du Colombier 	Proc		**tail;
1517dd7cddfSDavid du Colombier };
1527dd7cddfSDavid du Colombier 
1533ff48bf5SDavid du Colombier struct Ioproc
1543ff48bf5SDavid du Colombier {
1557fd46167SDavid du Colombier 	int tid;
1567fd46167SDavid du Colombier 	Channel *c, *creply;
1573ff48bf5SDavid du Colombier 	int inuse;
1583ff48bf5SDavid du Colombier 	long (*op)(va_list*);
1593ff48bf5SDavid du Colombier 	va_list arg;
1603ff48bf5SDavid du Colombier 	long ret;
1613ff48bf5SDavid du Colombier 	char err[ERRMAX];
1623ff48bf5SDavid du Colombier 	Ioproc *next;
1633ff48bf5SDavid du Colombier };
1643ff48bf5SDavid du Colombier 
1659a747e4fSDavid du Colombier void	_freeproc(Proc*);
1669a747e4fSDavid du Colombier void	_freethread(Thread*);
1679a747e4fSDavid du Colombier Proc*	_newproc(void(*)(void*), void*, uint, char*, int, int);
1689a747e4fSDavid du Colombier int	_procsplhi(void);
1699a747e4fSDavid du Colombier void	_procsplx(int);
1709a747e4fSDavid du Colombier void	_sched(void);
1719a747e4fSDavid du Colombier int	_schedexec(Execargs*);
1729a747e4fSDavid du Colombier void	_schedexecwait(void);
1739a747e4fSDavid du Colombier void	_schedexit(Proc*);
1749a747e4fSDavid du Colombier int	_schedfork(Proc*);
1759a747e4fSDavid du Colombier void	_schedinit(void*);
1769a747e4fSDavid du Colombier void	_systhreadinit(void);
1779a747e4fSDavid du Colombier void	_threadassert(char*);
1789a747e4fSDavid du Colombier void	_threadbreakrendez(void);
1799a747e4fSDavid du Colombier void	_threaddebug(ulong, char*, ...);
1809a747e4fSDavid du Colombier void	_threadexitsall(char*);
1819a747e4fSDavid du Colombier void	_threadflagrendez(Thread*);
1829a747e4fSDavid du Colombier Proc*	_threadgetproc(void);
1839a747e4fSDavid du Colombier void	_threadsetproc(Proc*);
1849a747e4fSDavid du Colombier void	_threadinitstack(Thread*, void(*)(void*), void*);
1859a747e4fSDavid du Colombier void*	_threadmalloc(long, int);
1869a747e4fSDavid du Colombier void	_threadnote(void*, char*);
1879a747e4fSDavid du Colombier void	_threadready(Thread*);
18874f16c81SDavid du Colombier void*	_threadrendezvous(void*, void*);
1899a747e4fSDavid du Colombier void	_threadsignal(void);
1909a747e4fSDavid du Colombier void	_threadsysfatal(char*, va_list);
191d1be6b08SDavid du Colombier void**	_workerdata(void);
192853458f3SDavid du Colombier void	_xinc(long*);
193853458f3SDavid du Colombier long	_xdec(long*);
1949a747e4fSDavid du Colombier 
1959a747e4fSDavid du Colombier extern int			_threaddebuglevel;
1969a747e4fSDavid du Colombier extern char*		_threadexitsallstatus;
1979a747e4fSDavid du Colombier extern Pqueue		_threadpq;
1989a747e4fSDavid du Colombier extern Channel*	_threadwaitchan;
1999a747e4fSDavid du Colombier extern Rgrp		_threadrgrp;
2009a747e4fSDavid du Colombier 
2019a747e4fSDavid du Colombier #define DBGAPPL	(1 << 0)
2029a747e4fSDavid du Colombier #define DBGSCHED	(1 << 16)
2039a747e4fSDavid du Colombier #define DBGCHAN	(1 << 17)
2049a747e4fSDavid du Colombier #define DBGREND	(1 << 18)
2059a747e4fSDavid du Colombier /* #define DBGKILL	(1 << 19) */
2069a747e4fSDavid du Colombier #define DBGNOTE	(1 << 20)
2079a747e4fSDavid du Colombier #define DBGEXEC	(1 << 21)
2083ff48bf5SDavid du Colombier 
2093ff48bf5SDavid du Colombier #define ioproc_arg(io, type)	(va_arg((io)->arg, type))
210