/*
 * threads.h
 *
 * $Source: /usr0/ecc/nectar/src/cab/threads/RCS/threads.h,v $
 *
 * $Header: threads.h,v 1.3 88/05/09 16:02:55 ecc Locked $
 *
 * The threads package provides a lightweight process mechanism
 * for concurrency, mutex objects for mutual exclusion, and
 * condition objects for synchronization.
 */


#ifndef	_THREADS_
#define	_THREADS_

#include <setjmp.h>

#include <nectar_sys.h>


IMPORT _setjmp(), _longjmp();

/*
 * Mutex objects.
 */

typedef struct Mutex {
	int lock;
} *Mutex_t;

#define	MUTEX_INITIALIZER	{ 0 }

#define	Mutex_Alloc()		NEW0(struct Mutex)
#define	Mutex_Init(m)		((m)->lock = 0)
#define	Mutex_Clear(m)		/* nop */
#define	Mutex_Free(m)		do { Mutex_Clear(m); DISPOSE(m); } while (0)

#define	Mutex_Lock(m)		if (!((m)->lock == 0 && Mutex_Try_Lock(m))) \
					Mutex_Wait_Lock(m); \
				else

EXPORT boolean_t
Mutex_Try_Lock ARGS ((Mutex_t m));	/* nonblocking */

PUBLIC void
Mutex_Wait_Lock ARGS ((Mutex_t m));	/* blocking */

EXPORT void
Mutex_Unlock ARGS ((Mutex_t m));


/*
 * Queues.
 *
 * Queue structures are used in the current threads implementation
 * but this is subject to change.  Clients should not depend on them.
 */

typedef struct Queue_item {
	struct Queue_item *next;
} *Queue_item_t;

#define	NO_QUEUE_ITEM		((Queue_item_t) 0)

typedef struct Queue {
	Queue_item_t head;
	Queue_item_t tail;
} *Queue_t;

#define	QUEUE_INITIALIZER	{ NO_QUEUE_ITEM, NO_QUEUE_ITEM }

#define	Queue_Alloc()	NEW0(struct Queue)
#define	Queue_Free(q)	DISPOSE(q)

#define	Queue_Init(q)	((q)->head = (q)->tail = NO_QUEUE_ITEM)

#define	QUEUE_ENQ(q, x) \
	do { \
		(x)->next = 0; \
		if ((q)->tail == 0) \
			(q)->head = (Queue_item_t) (x); \
		else \
			(q)->tail->next = (Queue_item_t) (x); \
		(q)->tail = (Queue_item_t) (x); \
	} while (0)

#define	QUEUE_PREQ(q, x) \
	do { \
		if ((q)->tail == 0) \
			(q)->tail = (Queue_item_t) (x); \
		((Queue_item_t) (x))->next = (q)->head; \
		(q)->head = (Queue_item_t) (x); \
	} while (0)

#define	QUEUE_HEAD(q, t, x)	((x) = (t) ((q)->head))

#define	QUEUE_DEQ(q, t, x)	if (((x) = (t) ((q)->head)) != 0 && \
				    ((q)->head = (Queue_item_t) ((x)->next)) == 0) \
					(q)->tail = 0; \
				else

#define	QUEUE_MAP(q, t, f) { \
	register Queue_item_t __X, __NEXT; \
	for (__X = (q)->head; __X != 0; __X = __NEXT) { \
		__NEXT = __X->next; \
		(*(f))((t) __X); \
	} \
}


/*
 * Condition variables.
 */

typedef struct Condition {
	struct Queue queue;
} *Condition_t;

#define	CONDITION_INITIALIZER		{ QUEUE_INITIALIZER }

#define	Condition_Alloc()		NEW0(struct Condition)
#define	Condition_Init(c)		Queue_Init(&(c)->queue)
#define	Condition_Clear(c)		Condition_Broadcast(c)
#define	Condition_Free(c)		do { Condition_Clear(c); DISPOSE(c); } while (0)

#define	Condition_Signal(c)		if ((c)->queue.head) \
						condition_Signal(c); \
					else

#define	Condition_Broadcast(c)		if ((c)->queue.head) \
						condition_Broadcast(c); \
					else

PUBLIC void
condition_Signal ARGS ((Condition_t c));

PUBLIC void
condition_Broadcast ARGS ((Condition_t c));

EXPORT void
Condition_Wait ARGS ((Condition_t c, Mutex_t m));


/*
 * Threads.
 */

typedef pointer_t (*Thread_fn_t) ARGS ((pointer_t arg));

typedef struct Thread {
	struct Thread *next;
	struct Mutex lock;
	struct Condition done;
	int state;
	jmp_buf catch;
	Thread_fn_t func;
	pointer_t arg;
	pointer_t result;
	string_t name;
	pointer_t data;
} *Thread_t;

#define	NO_THREAD	((Thread_t) 0)

/*
 * Threads package initialization.
 */
EXPORT void
Thread_Init ARGS (());

EXPORT Thread_t
Thread_Fork ARGS ((Thread_fn_t func, pointer_t arg));

EXPORT void
Thread_Detach ARGS ((Thread_t t));

EXPORT pointer_t
Thread_Join ARGS ((Thread_t t));

EXPORT void
Thread_Yield ARGS (());

EXPORT void
Thread_Exit ARGS ((pointer_t result));

/*
 * This structure must agree with struct proc in internals.h
 */
typedef struct Thread_base {
	struct Thread_base *next;
	Thread_t incarnation;
} *Thread_base_t;

PUBLIC int
thread_Sp ARGS (());

PUBLIC int thread_stack_mask;

#define	thread_Self()		(* (Thread_base_t *) (thread_Sp() & thread_stack_mask))
#define	thread_Assoc(id, t)	(((Thread_base_t) (id))->incarnation = (t))
#define	Thread_Self()		(thread_Self()->incarnation)

EXPORT void
Thread_Set_Name ARGS ((Thread_t t, string_t name));

EXPORT string_t
Thread_Name ARGS ((Thread_t t));

EXPORT int
Thread_Count();

EXPORT void
Thread_Set_Limit ARGS ((int n));

EXPORT int
Thread_Limit();

EXPORT void
Thread_Set_Level ARGS ((int n));

EXPORT int
Thread_Level();

#define	Thread_Set_Data(t, x)	((t)->data = (x))
#define	Thread_Data(t)		((t)->data)

EXPORT boolean_t Thread_debug;

#endif	_THREADS_
