/* @(#) process.h 1.1 94/10/31 Copyr 1987 Sun Micro */
/* Copyright (C) 1987. Sun Microsystems, Inc. */

#ifndef _lwp_process_h
#define _lwp_process_h

/*
 * Which queue or state a thread belongs to (if not on any queue)
 * A thread never belongs to more than one queue.
 */
typedef enum lwp_state_t {
	RS_UNBLOCKED	=0,	/* Runnable (__RunQ) */
	RS_SEND		=1,	/* Blocked on a send (__SendQ) */
	RS_RECEIVE	=2,	/* Blocked on a receive (__ReceiveQ) */
	RS_SLEEP	=3,	/* Sleeping for finite time (__SleepQ) */
	RS_MONITOR	=4,	/* Blocked on a monitor (__MonitorQ) */
	RS_CONDVAR	=5,	/* Blocked on a condition var (__CondvarQ) */
	RS_SUSPEND	=6,	/* Suspended (__SuspendQ) */
	RS_ZOMBIE	=7,	/* Dead but memory kept around until msg reply */
	RS_JOIN		=8,	/* Blocked on a join */
	RS_UNINIT	=9,	/* Not on any queue, uninitialized */
} lwp_state_t;

/*
 * Context block for lightweight process.
 */
typedef struct lwp_t {
	struct lwp_t *lwp_next;		/* list of processes blocked together */
	object_type_t lwp_type;		/* type (agt/lwp) (MUST BE 2'nd) */
	machstate_t lwp_machstate;	/* machine-dependent state */
	qheader_t lwp_ctx;		/* special context save/restore actions */
	bool_t lwp_full;		/* TRUE if rti resume, else coroutine */
	bool_t lwp_suspended;		/* TRUE if to be suspended */
	enum lwp_state_t lwp_run;	/* which queue holds the process */
	enum lwp_err_t lwp_lwperrno;	/* errors in primitives */
	qheader_t lwp_messages;		/* list of unreceived messages */
	caddr_t lwp_blockedon; 		/* entity waited upon */
	struct monitor_t *lwp_curmon;	/* currently-held monitor */
	int lwp_monlevel;		/* nesting level of reentrant monitor */
	qheader_t lwp_exchandles;	/* stack of exception handlers */
	qheader_t lwp_joinq;		/* threads awaiting this thread's death */
	int lwp_prio;			/* scheduling priority, higher favored */
	int lwp_flags;			/* LWPSUSPEND|LWPSERVER|LWPNOLASTRITES */
	int lwp_stack;			/* stack arg, passed to LASTRITES agt */
	int lwp_lock;			/* for validity checks */
	int lwp_cancel;			/* for kernel: TRUE if unwanted */
	caddr_t lwp_ref;		/* o.s. reference key (owner proc) */
} lwp_t;

#define	LWPNULL ((lwp_t *) 0)
#define	NOBODY	CHARNULL	/* lwp_blockedon: not waiting on any object */

/*
 * Manipulate client error setting/clearing
 */
#define	SET_ERROR(proc, err)	{					\
	if ((proc != LWPNULL)) {					\
		(proc)->lwp_lwperrno = err;				\
	}								\
}

#define	IS_ERROR()							\
	__Curproc ? (__Curproc->lwp_lwperrno != LE_NOERROR) :		\
		(panic("Curproc is null"), 0)

#define	CLR_ERROR()	{						\
	if ((__Curproc != LWPNULL)) {					\
		__Curproc->lwp_lwperrno = LE_NOERROR;			\
	}								\
}

#define	NUGPRIO		0	/* idle priority (no other lwp this low) */

/*
 * Conditionally give up the processor if "prio" warrants it.
 * Always UNLOCKED when it returns, either via WAIT or UNLOCK.
 */
#define	YIELD_CPU(prio) {				\
	if (prio > __Curproc->lwp_prio) {		\
		WAIT();					\
	}						\
}

/*
 * Remove the specified process from the run
 * queue and set it's new state:
 * which queue it will be blocked on and which object can unblock it
 * (if applicable).
 */
#define	BLOCK(pro, state, waiton)	{				\
	REMX_ITEM(&__RunQ[pro->lwp_prio], pro);				\
	pro->lwp_run = state;						\
	pro->lwp_blockedon = (caddr_t)waiton;				\
	__Nrunnable--;							\
}

/*
 * Put a process back on the run queue. lwp_run prevents
 * a wakeup from unblocking an unblocked process.
 * Do this AFTER deueueing from whatever queue the process was on before.
 * If the (blocked) process is suspended, we now alter its status
 * to the suspended state (and __HighPrio remains the same since no new
 * runnable process was added).
 */
#define	UNBLOCK(dest) {								\
	if ((dest)->lwp_run != RS_UNBLOCKED) {					\
		if ((dest)->lwp_suspended) {					\
			INS_QUEUE(&__SuspendQ, dest);				\
			(dest)->lwp_run = RS_SUSPEND;				\
		} else {							\
			INS_QUEUE(&__RunQ[dest->lwp_prio], dest);		\
			(dest)->lwp_run = RS_UNBLOCKED;				\
		}								\
		(dest)->lwp_blockedon = NOBODY;					\
	}									\
	__Nrunnable++;								\
}

extern qheader_t __SuspendQ;	/* Queue of suspended processes */
extern int __LwpRunCnt;		/* Number of lwp's in the system */
extern int __Nrunnable;		/* number of runnable threads */
extern void __freeproc();	/* free lwp resources */
extern void __init_lwp();	/* initialize lwp library */

#endif /*!_lwp_process_h*/
