/*	Copyright  (c)	Günter Woigk  1990-2000
  					mailto:kio@little-bat.de

 	This program is distributed in the hope that it will be useful,
 	but WITHOUT ANY WARRANTY; without even the implied warranty of
 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

 	Permission to use, copy, modify, distribute, and sell this software and
 	its documentation for any purpose is hereby granted without fee, provided
 	that the above copyright notice appear in all copies and that both that
 	copyright notice and this permission notice appear in supporting
 	documentation, and that the name of the copyright holder not be used
 	in advertising or publicity pertaining to distribution of the software
 	without specific, written prior permission.  The copyright holder makes no
 	representations about the suitability of this software for any purpose.
 	It is provided "as is" without express or implied warranty.

 	THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 	INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 	EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 	CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 	DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 	TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 	PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef _disp_h_
#define _disp_h_

#include "kio/kio.h"

#ifndef SEMA_BOOST
#define SEMA_BOOST 1
#endif

#ifndef MINSTACKFREE
#define MINSTACKFREE 20000	// check~2k, log~8k, requester~20k, debugger~20k, none~1k
#endif

#ifndef TICKER_HEARTBEAT
#define TICKER_HEARTBEAT (XXXSAFE?1:0)
#endif


class 			Sema;				// semaphor
class 			Irpt;				// interrupt
class 			Twsp;				// thread workspace
typedef	Twsp* 	Tid;				// thread identifier
typedef	void  (*ThreadProc)(void*);	// thread entry callback functions


/* ----	duration constants [msec] ------------------------------------
*/
enum
{	mssec			= 1000,			// one second	= 1000 ms
	msmin			= mssec*60,		// one minute	= 60 seconds
	mshour			= msmin*60,		// one hour		= 60 minutes
	msday			= mshour*24		// one day		= 24 hours
};


/* ----	bits in disp_flag and Twsp::state ----------------------------
*/
enum								// disp_flag:				Twsp.state:
{									// ----------------			-----------------
	timeshed		= 0x80000000,	// timer expired			sheduled for timer
	irptshed		= 0x40000000, 	// async. interrupt			sheduled for interrupt
	semashed		= 0x20000000, 	//							waiting for semaphor
	suspended		= 0x10000000,	//							thread is suspended
	running			= 0x08000000	// 							thread willing to run
};


/* ----	global data --------------------------------------------------
		please use the accessor methods!
*/
extern	int		disp_ok;			// 0/1/2: dispatcher up and running ?

extern	long	disp_flag;			// the central dispatcher flags

extern	long	Tx1000;				// Alarm counter up to 0 [msec]
extern	long	Sx1000;				// Next alarm time [msec]
extern	long	TxDay;				// System clock at 00:00 (adjusted daily)

extern	Tid 	t_running;			// linked list of all running threads sorted by priority
extern	Tid		t_root;				// main application thread (Twsp = application stack+heap)

extern	ulong	sysLoad[33];		// systerm load sorted by log(2) of prio
extern	ulong	idleCount;			// idle time
extern	int		idleFlag;			// count idle time instead of current thread's prio
extern	Irpt	idleIrpt;			// triggered when idle time is detected


/*=====	DISPATCHER USER FUNCTIONS ===================================
*/
inline	long	DispFlag			( )			{ return disp_flag; }
inline	void	SetDispFlag			( long m )	{ disp_flag |= m;   }	// set bits according to mask
inline	void	ClearDispFlag		( long m )	{ disp_flag &= ~m;  }	// clear bits according to mask

inline	Tid		RootTid				( )			{ return t_root; }
inline	Tid		MyTid				( )			{ return t_running; }

inline	long	SystemTime			( )			{ return Tx1000 + Sx1000; }
inline	long	Midnight			( )			{ return TxDay; }
inline	long	TimeOfDay			( )			{ return SystemTime() - TxDay; }

extern 	Tid		GetTid				( cstr name );
extern 	bool 	IsValidTid			( Tid );

extern	int 	NumThreads 			( long mask = running|timeshed|suspended );
inline	int 	NumThreadsRunning 	( )			{ return NumThreads(running);	}
inline	int 	NumThreadsTimeShed	( )			{ return NumThreads(timeshed);	}
inline	int 	NumThreadsSuspended	( )			{ return NumThreads(suspended);	}
inline	int 	NumThreadsIrptShed	( )			{ return NumThreads(irptshed);	}
inline	int 	NumThreadsSemaShed	( )			{ return NumThreads(semashed);	}


#include "twsp.h"
#include "irpt.h"
#include "sema.h"


extern	void	StartDispatcher	( );			// start dispatcher
extern	bool	Disp			( );			// dispatcher test: call Disp() frequently!

#define			DISP()			( (XXSAFE || disp_flag) && Disp() )
#define			XDISP()			(  XSAFE                && DISP() )
#define			XXDISP()		(  XXSAFE               && DISP() )
#define			XXXDISP()		(  XXXSAFE              && DISP() )

inline	bool	DispOk			( )						{ return disp_ok==2;	 }

inline	void	Suspend			(       )				{ MyTid()->Suspend();	 }
inline	void	Suspend			( Tid t )				{       t->Suspend();	 }
extern	void	Suspend			( cstr name );

inline	void	Resume			( Tid t )				{       t->Resume();	 }
extern	void	Resume			( cstr name );

extern	Tid		Split			( ThreadProc, void* data, ulong prio, ulong size, cstr name );

inline	void	Termi			(       )				{ MyTid()->Termi();		 }
inline	void	Termi			( Tid t )				{       t->Termi();		 }
extern	void	Termi			( cstr name );


inline	void	Wait			(        long dur )		{ MyTid()->Wait(dur);	 }
inline	void	Wait			( Tid t, long dur )		{       t->Wait(dur);	 }

inline	void	Shedule			(        long clk )		{ MyTid()->Shedule(clk); }
inline	void	Shedule			( Tid t, long clk )		{       t->Shedule(clk); }

inline	void	ChangePrio		(        ulong n )		{ MyTid()->ChangePrio(n); }
inline	void	ChangePrio		( Tid t, ulong n )		{       t->ChangePrio(n); }

inline	void	Clear			( Irpt& i )				{ i.Clear();   	 	}
inline	void	Clear			( Irpt& i, int n )		{ i.Clear(n);  	 	}
inline	void	Trigger			( Irpt& i, int n=1 )	{ i.Trigger(n);	 	} 
inline	void	AsyncTrigger	( Irpt& i, int n=1 )	{ i.AsyncTrigger(n);} 
inline	void	Shedule			( Irpt&i )				{ i.Shedule();		}
inline	void	Shedule			( Irpt&i,long dur )		{ i.Shedule(dur); 	}


inline	void	Clear			( Sema& s )				{ s.Clear(); 		}
inline	void	Request	 		( Sema& s, int n=1 )	{ s.Request(n);	 	}
inline	void	Request	 		( Sema& s, int n,long d){ s.Request(n,d); 	}
inline	void 	Release 		( Sema& s, int n=1 ) 	{ s.Release(n); 	}

inline	size_t	StackFree		( )						{ return MyTid()->StackFree(); }
inline	void	CheckStack		( )						{ TRAP(StackFree()<minStackFree); }

#endif
















