/*ident	"@(#)cls4:incl-master/const-headers/task.h	1.1" */
/*******************************************************************************
 
C++ source for the C++ Language System, Release 3.0.  This product
is a new release of the original cfront developed in the computer
science research center of AT&T Bell Laboratories.

Copyright (c) 1991 AT&T and UNIX System Laboratories, Inc.
Copyright (c) 1984, 1989, 1990 AT&T.  All Rights Reserved.

THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE of AT&T and UNIX System
Laboratories, Inc.  The copyright notice above does not evidence
any actual or intended publication of such source code.

*******************************************************************************/

#ifndef TASKH
#define TASKH

/*	HEADER FILE FOR THE TASK SYSTEM		*/

#include <signal.h>
#include <stdio.h>

#ifdef uts
#define SIZE		2048
#else
#define	SIZE		750
#endif

class object;
class sched;	/* : public object */
class timer;	/* : public sched  */
class task;	/* : public sched  */
class qhead;	/* : public object */
class qtail;	/* : public object */
class team;

#if defined(_SHARED_ONLY)
#define	DEFAULT_MODE	SHARED
#else
#define	DEFAULT_MODE	DEDICATED
#endif

/* loc on stack */
#define UNTOUCHED	052525

/* error codes */
#define task_error_messages						\
macro_start								\
macro(0,E_ERROR,"")							\
macro(1,E_OLINK,"object::delete(): has chain")				\
macro(2,E_ONEXT,"object::delete(): on chain")				\
macro(3,E_GETEMPTY,"qhead::get(): empty")				\
macro(4,E_PUTOBJ,"qtail::put(): object on other queue")			\
macro(5,E_PUTFULL,"qtail::put(): full")					\
macro(6,E_BACKOBJ,"qhead::putback(): object on other queue")		\
macro(7,E_BACKFULL,"qhead::putback(): full")				\
macro(8,E_SETCLOCK,"sched::setclock(): clock!=0")			\
macro(9,E_CLOCKIDLE,"sched::schedule(): clock_task not idle")		\
macro(10,E_RESTERM,"sched::insert(): cannot schedule terminated sched")	\
macro(11,E_RESRUN,"sched::schedule(): running")				\
macro(12,E_NEGTIME,"sched::schedule(): clock<0")			\
macro(13,E_RESOBJ,"sched::schedule(): task or timer on other queue")	\
macro(14,E_HISTO,"histogram::histogram(): bad arguments")		\
macro(15,E_STACK,"task::restore() or task::task(): stack overflow")	\
macro(16,E_STORE,"new: free store exhausted")				\
macro(17,E_TASKMODE,"task::task(): bad mode")				\
macro(18,E_TASKDEL,"task::~task(): not terminated")			\
macro(19,E_TASKPRE,"task::preempt(): not running")			\
macro(20,E_TIMERDEL,"timer::~timer(): not terminated")			\
macro(21,E_SCHTIME,"sched::schedule(): runchain corrupted: bad time")	\
macro(22,E_SCHOBJ,"sched object used directly (not as base)")		\
macro(23,E_QDEL,"queue::~queue(): not empty")				\
macro(24,E_RESULT,"task::result(): thistask->result()")			\
macro(25,E_WAIT,"task::wait(): wait for self")				\
macro(26,E_FUNCS,"FrameLayout::FrameLayout(): function start")		\
macro(27,E_FRAMES,"FrameLayout::FrameLayout(): frame size")		\
macro(28,E_REGMASK,"task::fudge_return(): unexpected register mask")	\
macro(29,E_FUDGE_SIZE,"task::fudge_return(): frame too big")		\
macro(30,E_NO_HNDLR,"sigFunc - no handler for signal")			\
macro(31,E_BADSIG,"illegal signal number")				\
macro(32,E_LOSTHNDLR,"Interrupt_handler::~Interrupt_handler(): signal handler not on chain")			\
macro_end(E_LOSTHNDLR)
#define macro_start
#define macro(num,name,string) const name = num ;
#define macro_end(last_name) const MAXERR = last_name;
task_error_messages
#undef macro_start
#undef macro
#undef macro_end


typedef int (*PFIO)(int,object*);
typedef void (*PFV)();

/* print flags, used as arguments to class print functions */
#define CHAIN		1
#define VERBOSE		2
#define STACK		4

/* DATA STRUCTURES */
/*
	object --> olink --> olink ...
	   |         |         |
	  ...        V         V
	   |        task      task
	   V
	object --> ...
*/

class olink
/*	the building block for chains of task pointers */
{
friend object;
	olink*	l_next;
	task*	l_task;
		olink(task* t, olink* l) { l_task=t; l_next=l; };
};

class object
{
friend sched;
friend task;
public:
	enum objtype { OBJECT, TIMER, TASK, QHEAD, QTAIL, INTHANDLER };
private:
	olink*	o_link;
	static task*	thxstxsk;
public:
	object*	o_next;
	virtual objtype	o_type()	{ return OBJECT; }

		object()	{ o_link=0; o_next=0; }
	virtual	~object();

	void	remember(task*);	// save for alert
	void	forget(task*);	// remove all occurrences of task from chain
	void	alert();	// prepare IDLE tasks for scheduling
	virtual int	pending();  // TRUE if this object should be waited for
	virtual	void	print(int, int =0); // 1st arg VERBOSE, CHAIN, or STACK
	static int	task_error(int, object*);
				// the central error function
	int	task_error(int);	// obsolete; use static version
	static task*	this_task()	{ return thxstxsk; }
	static	PFIO	error_fct;	// user-supplied error function
};

// fake compatibility with previous version
#define thistask (object::this_task())

void _print_error(int);

class sched : public object {	// only instances of subclasses are used
friend timer;
friend task;
friend object;
friend void _print_error(int n);
friend SIG_FUNC_TYP sigFunc;
public:
	enum statetype { IDLE=1, RUNNING=2, TERMINATED=4 };
private:
	static int	keep_waiting_count;
	static sched*	runchain;    // list of ready-to-run scheds (by s_time)
	static sched*	priority_sched;	// if non-zero, sched to run next
	static	long	clxck;
	static int	exit_status;
	long	s_time;		/* time to sched; result after cancel() */
	statetype	s_state;	/* IDLE, RUNNING, TERMINATED */
	void	schedule();	/* sched clock_task or front of runchain */
	virtual	void	resume();
	void	insert(long,object*); /* sched for long time units, t_alert=obj */
	void	remove();	/* remove from runchain & make IDLE */

protected:
		sched() : s_time(0), s_state(IDLE) {}
public:

	static void	setclock(long);
	static long	get_clock() { return clxck; }
	static sched*	get_run_chain() { return runchain; }
	static int	get_exit_status() { return exit_status; }
	static void	set_exit_status( int i ) { exit_status = i; }
	sched*	get_priority_sched() { return priority_sched; }
	static	task*	clock_task;	// awoken at each clock tick
	long	rdtime()	{ return s_time; };
	statetype	rdstate()	{ return s_state; };
	int	pending()	{ return s_state != TERMINATED; }
	int	keep_waiting()	{ return keep_waiting_count++; }
	int	dont_wait()	{ return keep_waiting_count--; }

	void	cancel(int);
	int	result();
	virtual void	setwho(object* t);  // who alerted me
	void	print(int, int =0);
	static	PFV	exit_fct;	// user-supplied exit function
};
// for compatibility with pre-2.0 releases,
// but conflicts with time.h
//#define clock (sched::get_clock())
inline void	setclock(long i) { sched::setclock(i); }

// for compatibility with pre-2.0 releases
#define run_chain (sched::get_run_chain())

class timer : public sched {
	void	resume();
public:
		timer(long);
		~timer();
	void	reset(long);
	object::objtype	o_type()	{ return TIMER; }
	void	setwho(object*)	{ }  // do nothing
	void	print(int, int =0);
};

extern _hwm;
class task : public sched {
friend sched;
public:
	enum modetype { DEDICATED=1, SHARED=2 };
private:
	static task*	txsk_chxin;   /* list of all tasks */
	static team*	team_to_delete;	// delete this team after task switch
	void	restore(task*, int =0);	/* switch to new task */
	int	curr_hwm();	/* "high water mark" */
				/*     (how high stack has risen) */
	int	swap_stack(int*,int*); /* initialize child stack */
	void	fudge_return(int*);	//used in starting new tasks
	void	copy_share();	// used in starting shared tasks
	void	get_size();	// ditto -- saves size of active stack
	void	resume();
	/* simple check for stack overflow--not used for main task */
	void	settrap();
	void	checktrap();
	/* WARNING: t_framep, th, and t_ap are manipulated as offsets from
	 * task by swap(); those, and t_basep, t_size, and t_savearea are
	 * manipulated as offsets by sswap().
	 * Do not insert new data members before these.
	 */
	int*	t_framep;	// fp for this task when suspended
	void*	th;		/* fudge return from swap */
	int*	t_ap; 		/* arg pointer for this task when suspended */
	int*	t_basep;	// addr of stack when running 
	int	t_size;		/* size of active stack (used for SHARED)
				 * holds hwm after cancel() */
	int*	t_savearea;	// addr of stack when not running (SHARED only)
	int	t_trap;		// used for stack overflow check
	team*	t_team;		/* stack and info for sharing */

	modetype	t_mode;		/* DEDICATED/SHARED stack */
	int	t_stacksize;

	object*	t_alert;	/* object that inserted you */
protected:
		task(char* name=0, modetype mode=DEFAULT_MODE, int stacksize=SIZE);
public:
		~task();

	object::objtype	o_type()	{ return TASK; }
	task*	t_next;		/* insertion in "task_chain" */
	char*	t_name;

	static task*	get_task_chain() { return txsk_chxin; }
	int	waitvec(object**);
	int	waitlist(object* ...);
	void	wait(object* ob);

	void	delay(long);
	long	preempt();
	void	sleep(object* t =0);	// t is remembered
	void	resultis(int);
	void	cancel(int);
	void	setwho(object* t)	{ t_alert = t; }
	void	print(int, int =0);
	object*	who_alerted_me()	{ return t_alert; }
};
// for compatibility
#define task_chain (task::get_task_chain())

// an Interrupt_handler supplies an interrupt routine that runs when the
// interrupt occurs (real time).  Also the Interrupt_handler can be waited for.
class Interrupt_handler : public object {
friend	class Interrupt_alerter;
friend SIG_FUNC_TYP sigFunc;
	int	id;		// signal or interrupt number
	int	got_interrupt;  // an interrupt has been received
				// but not alerted
	Interrupt_handler	*old;	// previous handler for this signal
	virtual void	interrupt();	// runs at real time
public:
		Interrupt_handler(int sig_num);
		~Interrupt_handler();
	object::objtype	o_type()	{ return INTHANDLER; }
	int	pending();	// FALSE once after interrupt
};


/* QUEUE MANIPULATION (see queue.c) */
/*
	qhead <--> oqueue <--> qtail   (qhead, qtail independent)
	oqueue ->> circular queue of objects
*/

/* qh_modes */
enum qmodetype { EMODE, WMODE, ZMODE };

class oqueue
{
friend qhead;
friend qtail;
	int	q_max;
	int	q_count;
	object*	q_ptr;
	qhead*	q_head;
	qtail*	q_tail;

		oqueue(int m)	{ q_max=m; q_count=0; q_head=0; q_tail=0; };
		~oqueue()	{ (q_count)?object::task_error(E_QDEL,0):0; };

	void	print(int);
};

class qhead : public object
{
friend qtail;
	qmodetype	qh_mode;	/* EMODE,WMODE,ZMODE */
	oqueue*		qh_queue;
public:
			qhead(qmodetype = WMODE, int = 10000);
			~qhead();

	object::objtype		o_type()	{ return QHEAD; }
	object*		get();
	int		putback(object*);

	int		rdcount()	{ return qh_queue->q_count; }
	int		rdmax()		{ return qh_queue->q_max; }
	qmodetype	rdmode()	{ return qh_mode; }
	qtail*		tail();

	qhead*		cut();
	void		splice(qtail*);

	void		setmode(qmodetype m)	{ qh_mode = m; };
	void		setmax(int m)	{ qh_queue->q_max = m; };
	int		pending()	{ return rdcount() == 0; }
	void		print(int, int =0);
};

class qtail : public object
{
friend qhead;
	qmodetype	qt_mode;
	oqueue*		qt_queue;
public:
			qtail(qmodetype = WMODE, int = 10000);
			~qtail();

	object::objtype		o_type()	{ return QTAIL; }
	int		put(object*);

	int		rdspace()	
			{ return qt_queue->q_max - qt_queue->q_count; };
	int		rdmax()		{ return qt_queue->q_max; };
	qmodetype	rdmode()	{ return qt_mode; };

	qtail*		cut();
	void 		splice(qhead*);

	qhead*		head();

	void		setmode(qmodetype m)	{ qt_mode = m; };
	void		setmax(int m)	{ qt_queue->q_max = m; };
	int		pending()	{ return rdspace() == 0; }

	void		print(int, int =0);
};


struct histogram
/*
	"nbin" bins covering the range [l:r] uniformly
	nbin*binsize == r-l
*/
{
	int	l, r;
	int	binsize;
	int	nbin;
	int*	h;
	long	sum;
	long	sqsum;
		histogram(int=16, int=0, int=16);

	void	add(int);
	void	print();
};

/*	the result of randint() is always >= 0	*/

#define DRAW (randx = randx*1103515245 + 12345)
#define ABS(x)	(x&0x7fffffff)
#define MASK(x) ABS(x)

class randint
/*	uniform distribution in the interval [0,MAXINT_AS_FLOAT] */
{
	long	randx;
public:
		randint(long s = 0)	{ randx=s; }
	void	seed(long s)	{ randx=s; }
	int	draw()		{ return MASK(DRAW); }
	float	fdraw();
};

class urand : public randint
/*	uniform distribution in the interval [low,high]	*/
{
public:
	int	low, high;
		urand(int l, int h)	{ low=l; high=h; }
	int	draw();
};

class erand : public randint
/*	exponential distribution random number generator */
{
public:
	int	mean;
		erand(int m) { mean=m; };
	int	draw();
};

// This task will alert Interrupt_handler objects.
class Interrupt_alerter : public task {
public:
		Interrupt_alerter();
		~Interrupt_alerter() { cancel (0); }
};

extern Interrupt_alerter	interrupt_alerter;

#endif
