xref: /plan9/sys/src/libthread/threadimpl.h (revision 853458f38e7eb3a48cfa3a36aefdb799375e398a)
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;
279a747e4fSDavid du Colombier typedef struct Proc		Proc;
289a747e4fSDavid du Colombier 
299a747e4fSDavid du Colombier /* must match list in sched.c */
309a747e4fSDavid du Colombier typedef enum
319a747e4fSDavid du Colombier {
329a747e4fSDavid du Colombier 	Dead,
337dd7cddfSDavid du Colombier 	Running,
349a747e4fSDavid du Colombier 	Ready,
357dd7cddfSDavid du Colombier 	Rendezvous,
367dd7cddfSDavid du Colombier } State;
377dd7cddfSDavid du Colombier 
389a747e4fSDavid du Colombier typedef enum
399a747e4fSDavid du Colombier {
409a747e4fSDavid du Colombier 	Channone,
419a747e4fSDavid du Colombier 	Chanalt,
429a747e4fSDavid du Colombier 	Chansend,
439a747e4fSDavid du Colombier 	Chanrecv,
449a747e4fSDavid du Colombier } Chanstate;
457dd7cddfSDavid du Colombier 
469a747e4fSDavid du Colombier enum
479a747e4fSDavid du Colombier {
489a747e4fSDavid du Colombier 	RENDHASH = 13,
499a747e4fSDavid du Colombier 	Printsize = 2048,
507fd46167SDavid du Colombier 	NPRIV = 8,
517dd7cddfSDavid du Colombier };
527dd7cddfSDavid du Colombier 
539a747e4fSDavid du Colombier struct Rgrp
549a747e4fSDavid du Colombier {
557dd7cddfSDavid du Colombier 	Lock		lock;
569a747e4fSDavid du Colombier 	Thread	*hash[RENDHASH];
579a747e4fSDavid du Colombier };
589a747e4fSDavid du Colombier 
599a747e4fSDavid du Colombier struct Tqueue		/* Thread queue */
609a747e4fSDavid du Colombier {
619a747e4fSDavid du Colombier 	int		asleep;
627dd7cddfSDavid du Colombier 	Thread	*head;
639a747e4fSDavid du Colombier 	Thread	**tail;
647dd7cddfSDavid du Colombier };
657dd7cddfSDavid du Colombier 
669a747e4fSDavid du Colombier struct Thread
679a747e4fSDavid du Colombier {
689a747e4fSDavid du Colombier 	Lock		lock;		/* protects thread data structure */
699a747e4fSDavid du Colombier 	jmp_buf		sched;		/* for context switches */
709a747e4fSDavid du Colombier 	int		id;		/* thread id */
719a747e4fSDavid du Colombier 	int 		grp;		/* thread group */
729a747e4fSDavid du Colombier 	int		moribund;	/* thread needs to die */
739a747e4fSDavid du Colombier 	State		state;		/* run state */
749a747e4fSDavid du Colombier 	State		nextstate;	/* next run state */
759a747e4fSDavid du Colombier 	uchar		*stk;		/* top of stack (lowest address of stack) */
769a747e4fSDavid du Colombier 	uint		stksize;	/* stack size */
779a747e4fSDavid du Colombier 	Thread		*next;		/* next on ready queue */
7880ee5cbfSDavid du Colombier 
799a747e4fSDavid du Colombier 	Proc		*proc;		/* proc of this thread */
809a747e4fSDavid du Colombier 	Thread		*nextt;		/* next on list of threads in this proc*/
819a747e4fSDavid du Colombier 	int		ret;		/* return value for Exec, Fork */
829a747e4fSDavid du Colombier 
839a747e4fSDavid du Colombier 	char		*cmdname;	/* ptr to name of thread */
849a747e4fSDavid du Colombier 
859a747e4fSDavid du Colombier 	int		inrendez;
869a747e4fSDavid du Colombier 	Thread		*rendhash;	/* Trgrp linked list */
8774f16c81SDavid du Colombier 	void*		rendtag;	/* rendezvous tag */
8874f16c81SDavid du Colombier 	void*		rendval;	/* rendezvous value */
899a747e4fSDavid du Colombier 	int		rendbreak;	/* rendezvous has been taken */
909a747e4fSDavid du Colombier 
919a747e4fSDavid du Colombier 	Chanstate	chan;		/* which channel operation is current */
929a747e4fSDavid du Colombier 	Alt		*alt;		/* pointer to current alt structure (debugging) */
939a747e4fSDavid du Colombier 
947fd46167SDavid du Colombier 	void*	udata[NPRIV];	/* User per-thread data pointer */
957dd7cddfSDavid du Colombier };
967dd7cddfSDavid du Colombier 
979a747e4fSDavid du Colombier struct Execargs
989a747e4fSDavid du Colombier {
999a747e4fSDavid du Colombier 	char		*prog;
1009a747e4fSDavid du Colombier 	char		**args;
1019a747e4fSDavid du Colombier 	int		fd[2];
1029a747e4fSDavid du Colombier };
1039a747e4fSDavid du Colombier 
1049a747e4fSDavid du Colombier struct Proc
1059a747e4fSDavid du Colombier {
1067dd7cddfSDavid du Colombier 	Lock		lock;
1079a747e4fSDavid du Colombier 	jmp_buf		sched;			/* for context switches */
1089a747e4fSDavid du Colombier 	int		pid;			/* process id */
1099a747e4fSDavid du Colombier 	int		splhi;			/* delay notes */
1109a747e4fSDavid du Colombier 	Thread		*thread;		/* running thread */
1117dd7cddfSDavid du Colombier 
1129a747e4fSDavid du Colombier 	int		needexec;
1139a747e4fSDavid du Colombier 	Execargs	exec;			/* exec argument */
1149a747e4fSDavid du Colombier 	Proc		*newproc;		/* fork argument */
1159a747e4fSDavid du Colombier 	char		exitstr[ERRMAX];	/* exit status */
1167dd7cddfSDavid du Colombier 
1179a747e4fSDavid du Colombier 	int		rforkflag;
1187dd7cddfSDavid du Colombier 	int		nthreads;
1199a747e4fSDavid du Colombier 	Tqueue		threads;		/* All threads of this proc */
1209a747e4fSDavid du Colombier 	Tqueue		ready;			/* Runnable threads */
1219a747e4fSDavid du Colombier 	Lock		readylock;
1227dd7cddfSDavid du Colombier 
1239a747e4fSDavid du Colombier 	char		printbuf[Printsize];
1249a747e4fSDavid du Colombier 	int		blocked;		/* In a rendezvous */
1259a747e4fSDavid du Colombier 	int		pending;		/* delayed note pending */
1269a747e4fSDavid du Colombier 	int		nonotes;		/*  delay notes */
1279a747e4fSDavid du Colombier 	uint		nextID;			/* ID of most recently created thread */
1289a747e4fSDavid du Colombier 	Proc		*next;			/* linked list of Procs */
1297dd7cddfSDavid du Colombier 
1309a747e4fSDavid du Colombier 	void		*arg;			/* passed between shared and unshared stk */
1319a747e4fSDavid du Colombier 	char		str[ERRMAX];		/* used by threadexits to avoid malloc */
1327dd7cddfSDavid du Colombier 
133d1be6b08SDavid du Colombier 	void*		wdata;			/* Lib(worker) per-proc data pointer */
1349a747e4fSDavid du Colombier 	void*		udata;			/* User per-proc data pointer */
135dc5a79c1SDavid du Colombier 	char		threadint;		/* tag for threadexitsall() */
1367dd7cddfSDavid du Colombier };
1377dd7cddfSDavid du Colombier 
1389a747e4fSDavid du Colombier struct Pqueue {		/* Proc queue */
1397dd7cddfSDavid du Colombier 	Lock		lock;
1407dd7cddfSDavid du Colombier 	Proc		*head;
1419a747e4fSDavid du Colombier 	Proc		**tail;
1427dd7cddfSDavid du Colombier };
1437dd7cddfSDavid du Colombier 
1443ff48bf5SDavid du Colombier struct Ioproc
1453ff48bf5SDavid du Colombier {
1467fd46167SDavid du Colombier 	int tid;
1477fd46167SDavid du Colombier 	Channel *c, *creply;
1483ff48bf5SDavid du Colombier 	int inuse;
1493ff48bf5SDavid du Colombier 	long (*op)(va_list*);
1503ff48bf5SDavid du Colombier 	va_list arg;
1513ff48bf5SDavid du Colombier 	long ret;
1523ff48bf5SDavid du Colombier 	char err[ERRMAX];
1533ff48bf5SDavid du Colombier 	Ioproc *next;
1543ff48bf5SDavid du Colombier };
1553ff48bf5SDavid du Colombier 
1569a747e4fSDavid du Colombier void	_freeproc(Proc*);
1579a747e4fSDavid du Colombier void	_freethread(Thread*);
1589a747e4fSDavid du Colombier Proc*	_newproc(void(*)(void*), void*, uint, char*, int, int);
1599a747e4fSDavid du Colombier int	_procsplhi(void);
1609a747e4fSDavid du Colombier void	_procsplx(int);
1619a747e4fSDavid du Colombier void	_sched(void);
1629a747e4fSDavid du Colombier int	_schedexec(Execargs*);
1639a747e4fSDavid du Colombier void	_schedexecwait(void);
1649a747e4fSDavid du Colombier void	_schedexit(Proc*);
1659a747e4fSDavid du Colombier int	_schedfork(Proc*);
1669a747e4fSDavid du Colombier void	_schedinit(void*);
1679a747e4fSDavid du Colombier void	_systhreadinit(void);
1689a747e4fSDavid du Colombier void	_threadassert(char*);
1699a747e4fSDavid du Colombier void	_threadbreakrendez(void);
1709a747e4fSDavid du Colombier void	_threaddebug(ulong, char*, ...);
1719a747e4fSDavid du Colombier void	_threadexitsall(char*);
1729a747e4fSDavid du Colombier void	_threadflagrendez(Thread*);
1739a747e4fSDavid du Colombier Proc*	_threadgetproc(void);
1749a747e4fSDavid du Colombier void	_threadsetproc(Proc*);
1759a747e4fSDavid du Colombier void	_threadinitstack(Thread*, void(*)(void*), void*);
1769a747e4fSDavid du Colombier void*	_threadmalloc(long, int);
1779a747e4fSDavid du Colombier void	_threadnote(void*, char*);
1789a747e4fSDavid du Colombier void	_threadready(Thread*);
17974f16c81SDavid du Colombier void*	_threadrendezvous(void*, void*);
1809a747e4fSDavid du Colombier void	_threadsignal(void);
1819a747e4fSDavid du Colombier void	_threadsysfatal(char*, va_list);
182d1be6b08SDavid du Colombier void**	_workerdata(void);
183*853458f3SDavid du Colombier void	_xinc(long*);
184*853458f3SDavid du Colombier long	_xdec(long*);
1859a747e4fSDavid du Colombier 
1869a747e4fSDavid du Colombier extern int			_threaddebuglevel;
1879a747e4fSDavid du Colombier extern char*		_threadexitsallstatus;
1889a747e4fSDavid du Colombier extern Pqueue		_threadpq;
1899a747e4fSDavid du Colombier extern Channel*	_threadwaitchan;
1909a747e4fSDavid du Colombier extern Rgrp		_threadrgrp;
1919a747e4fSDavid du Colombier 
1929a747e4fSDavid du Colombier #define DBGAPPL	(1 << 0)
1939a747e4fSDavid du Colombier #define DBGSCHED	(1 << 16)
1949a747e4fSDavid du Colombier #define DBGCHAN	(1 << 17)
1959a747e4fSDavid du Colombier #define DBGREND	(1 << 18)
1969a747e4fSDavid du Colombier /* #define DBGKILL	(1 << 19) */
1979a747e4fSDavid du Colombier #define DBGNOTE	(1 << 20)
1989a747e4fSDavid du Colombier #define DBGEXEC	(1 << 21)
1993ff48bf5SDavid du Colombier 
2003ff48bf5SDavid du Colombier #define ioproc_arg(io, type)	(va_arg((io)->arg, type))
201