/*
 * @DEC_COPYRIGHT@
 */
/*
 * HISTORY
 * $Log:	preempt.h,v $
 * Revision 4.3.2.2  92/02/14  14:13:46  Ronald_Widyono
 * 	"Fix circular include file problem"
 * 
 * Revision 4.3.1.2  92/02/13  12:29:14  Ronald_Widyono
 * 	Remove the funneled code test from the preemption_point and
 * 	preemption_point_safe macros.  Add an external reference to the slock_count[]
 * 	array.  Remove the inclusion of kern/thread.h and kern/lock.h.
 * 
 * Revision 4.3  91/11/26  11:13:08  devbld_zk3
 * 	Baselevel AG_BL0
 * 
 * Revision 4.2.2.2  91/10/25  14:49:49  William_Burns
 * 	Merge from ODE/TIN: revision 3.1.9.2
 * 	date: 91/10/22 20:06:41;  author: devrcs;  state: Exp;  lines added/del: 6/6
 * 	sccs rev: 3.3;  orig date: 91/10/08 14:53:59;  orig author: plong
 * 	  Realtime extension
 * 	[91/10/25  12:51:24  William_Burns]
 * 
 * Revision 4.2  91/09/19  23:04:28  devbld
 * 	Adding ODE Headers
 * 
 * $EndLog$
 */
/*	
 *	@(#)$RCSfile: preempt.h,v $ $Revision: 4.3.2.2 $ (DEC) $Date: 92/02/14 14:13:46 $
 */ 
/*
 */
/*
 *	File:	preempt.h
 *	Author:	Ron Widyono
 *
 *	Preemption point macros.
 *
 *	Revision History:
 *
 * 14-May-91	Ron Widyono
 *	Remove sleep lock restriction on preemption.
 *
 * 5-May-91	Ron Widyono
 *	Optimize.  Incorporate run-time option for kernel preemption
 *	(rt_preempt_enabled).  Count preemption points within macro.
 *
 */

#ifndef _SYS_PREEMPT_H_
#define _SYS_PREEMPT_H_

#include <rt_preempt.h>
#include <rt_preempt_debug.h>

#include <kern/ast.h>

extern int		slock_count[];
extern boolean_t	iplis0();
extern void		do_preemption();
#if	RT_PREEMPT_DEBUG
extern int		rt_preempt_pp;
#endif

/* The following macro represents a preemption point.  If an AST has been   */
/* requested and the conditions are appropriate for a context switch, then  */
/* the AST request is cancelled, and thread_block() is called to allow the  */
/* context switch to occur.  An AST can also be requested for other reasons.*/
/* If there is no context switch, the AST is allowed to fire, and those     */
/* other request(s) are serviced.  If there is a context switch, then the   */
/* AST request must be restored upon return from the thread block.	    */
#if	!RT_PREEMPT_DEBUG
#define preemption_point(preemption_counter)			\
MACRO_BEGIN							\
	if (ast_needed(cpu_number())) {				\
		do_preemption();				\
	}							\
MACRO_END
#else
#define preemption_point(preemption_counter)			\
MACRO_BEGIN							\
	if (ast_needed(cpu_number())) {				\
		rt_preempt_pp++;				\
		do_preemption(&preemption_counter);	\
	}							\
MACRO_END
#endif

/* The following macro partially determines whether this is a "safe" place */
/* for a context switch to take place.  "Safe" means that no simple locks  */
/* have been taken, the IPL is at the minimum value, and the current thread*/
/* is not being funneled (bound) to the master CPU.  The last test is de-  */
/* ferred to the do_preemption() routine to avoid a circular include pro-  */
/* blem.  The preemption request test (ast_needed) is incorporated here to */
/* optimize for performance.						   */
#define PREEMPTION_OK						\
	(ast_needed(cpu_number()) &&				\
	 !(slock_count[cpu_number()]) &&			\
	 iplis0() /* &&						\
	 ((thread)->unix_lock == -1)*/)

/* This version of the preemption point macro checks first that it is */
/* running in a "safe" place as defined by the PREEMPTION_OK macro.   */
#if	!RT_PREEMPT_DEBUG
#define preemption_point_safe(preemption_counter) {		\
          if (PREEMPTION_OK) {					\
	    do_preemption();					\
	  }							\
	}
#else	/* !RT_PREEMPT_DEBUG */
#define preemption_point_safe(preemption_counter) {		\
	  rt_preempt_pp++;					\
          if (PREEMPTION_OK) {					\
	    do_preemption(&preemption_counter);			\
	  }							\
	}
#endif	/* !RT_PREEMPT_DEBUG */

#endif	/* _SYS_PREEMPT_H_ */
