/*
Copyright (c) 1993 Xerox Corporation.  All rights reserved.
*/
/*
$Id$

$Date$
 *
 * PCR Threads Critical Section implementation details for inlining
 *
 */


#ifndef	←←PCR←ThCrSecInlines←h
#define ←←PCR←ThCrSecInlines←h 1

#include <config/PCR←StdDefs.h>
#include <th/PCR←Th.h>
#include <th/PCR←ThCurr.h>

/*
    Per-thread state
*/

#define PCR←ThCrSec←sysCrSecNest(td)	((td)->td←←sysCrSecNest) --> OOPS <--
#define PCR←ThCrSec←deferredAction(td)	((td)->td←←deferredAction) --> OOPS <--
#define PCR←ThCrSec←mustCheckSigs(td)	((td)->td←←mustCheckSigs) --> OOPS <--

/*
    Global state
*/
extern PCR←Bool volatile PCR←ThCrSec←mustYield;


/*
    Implementation:

    - host signal handler entered while in critical section
      (atomically) sets
          deferredAction = mustYield = true
      to request thread switch as soon as possible.

    - code running in critical section sets
          deferredAction(t) = mustCheckSigs(t) = true
      after doing anything that might make it necessary for t
      to handle a signal.

    So the requirement is: if we need to switch or check signals
    the next time we leave all nested critical sections, then
    deferredAction is true or else we're already committed to
    doing the action.  Code that sets deferredAction and mustXXXX
    is done in critical sections and appears atomic to testers.

    - on thread switch (which is necessarily done within a
      critical section), we set
          deferredAction = mustCheckSigs;
          mustYield = false;
          and then do the thread switch

    - on critical section exit, if deferredAction is false, we don't
      need to do anything.

    - on critical section exit, if deferredAction is true, we do the
      following loop:

          for(;;) {
              deferredAction = false;
              if( mustYield ) {
                  nest += 1;
                  switch(NIL); (* clears mustYield *)
                  nest -= 1;
              } else if( mustCheckSigs ) {
                  nest += 1;
                  PCR←ThPvt←HandleSigs(...); (* clears mustCheckSigs *)
                  nest -= 1;
              } else {
                  break;
              }
          }

      
*/

/*
 * CrSec procs
 */


extern void
PCR←ThCrSec←←ExitSysCleanup();
/*
    Do any deferred actions (call after leaving an un-nested sys
      critical section).
*/




/*
    Enter a critical section.
*/

#define PCR←ThCrSec←←TSDEnterSys(tsd) \
	{ (tsd)->tsd←sysCrSecNest += 1; }

#define PCR←ThCrSec←TSDEnterSys(tsd)	PCR←ThCrSec←←TSDEnterSys(tsd)

#define PCR←ThCrSec←←EnterSys() \
	PCR←ThCrSec←←TSDEnterSys(PCR←ThCurr←GetSlotData())

#define PCR←Th←DEBUGCrSec
#ifndef PCR←Th←DEBUGCrSec
#define PCR←ThCrSec←EnterSys()	PCR←ThCrSec←←EnterSys()
#endif



/*
    Leave a sys critical section, and if not nested do any
      deferred actions.
*/

#define PCR←ThCrSec←←TSDExitSys(tsd) \
    { if( (--((tsd)->tsd←sysCrSecNest)) <= 0 ) {\
        if( (tsd)->tsd←deferredAction ) PCR←ThCrSec←←ExitSysCleanup(); \
    } }

#define PCR←ThCrSec←TSDExitSys(tsd)	PCR←ThCrSec←←TSDExitSys(tsd)

#define PCR←ThCrSec←←ExitSys() \
    PCR←ThCrSec←←TSDExitSys(PCR←ThCurr←GetSlotData())

#define PCR←ThCrSec←ExitSys()		PCR←ThCrSec←←ExitSys()



/*
    Test whether currently in a critical section.
*/

#define PCR←ThCrSec←←TSDInSysCrSec(tsd) \
	((tsd)->tsd←sysCrSecNest > 0)

#define PCR←ThCrSec←TSDInSysCrSec(tsd)	PCR←ThCrSec←←TSDInSysCrSec(tsd)

#define PCR←ThCrSec←←InSysCrSec() \
	PCR←ThCrSec←←TSDInSysCrSec(PCR←ThCurr←GetSlotData())

#define PCR←ThCrSec←InSysCrSec()	PCR←ThCrSec←←InSysCrSec()



/*
    Test whether in a nested critical section.
*/

#define PCR←ThCrSec←←TSDInSysCrSecs(tsd) \
	((tsd)->tsd←sysCrSecNest > 1)

#define PCR←ThCrSec←TSDInSysCrSecs(tsd)	PCR←ThCrSec←←TSDInSysCrSecs(tsd)

#define PCR←ThCrSec←←InSysCrSecs() \
	PCR←ThCrSec←←TSDInSysCrSecs(PCR←ThCurr←GetSlotData())

#define PCR←ThCrSec←InSysCrSecs()	PCR←ThCrSec←←InSysCrSecs()


/*
    Arrange to check for arrival of signals
      the next time we leave a sys critical section.
*/

#define PCR←ThCrSec←←TSDMustCheckSigs(tsd) {\
	(tsd)->tsd←mustCheckSigs = PCR←Bool←true; \
	(tsd)->tsd←deferredAction = PCR←Bool←true; }

#define PCR←ThCrSec←TSDMustCheckSigs(tsd) \
	PCR←ThCrSec←←TSDMustCheckSigs(tsd)

#define PCR←ThCrSec←←MustCheckSigs() \
	PCR←ThCrSec←←TSDMustCheckSigs(PCR←ThCurr←GetSlotData())

#define PCR←ThCrSec←MustCheckSigs()	PCR←ThCrSec←←MustCheckSigs()



/*
    Arrange for a reschedule (preemption)
      the next time we leave a sys critical section.
*/

#define PCR←ThCrSec←←TSDMustYield(tsd) {\
	PCR←ThCrSec←mustYield = PCR←Bool←true; \
	(tsd)->tsd←deferredAction = PCR←Bool←true; }

#define PCR←ThCrSec←TSDMustYield(tsd)	PCR←ThCrSec←←TSDMustYield(tsd)

#define PCR←ThCrSec←←MustYield() \
	PCR←ThCrSec←←TSDMustYield(PCR←ThCurr←GetSlotData())

#define PCR←ThCrSec←MustYield()		PCR←ThCrSec←←MustYield()



/*
 * LibCrSec procs
 */


#define PCR←ThCrSec←EnterLib PCR←ThCrSec←EnterSys

#define PCR←ThCrSec←ExitLib PCR←ThCrSec←ExitSys

#define PCR←ThCrSec←InLibCrSec PCR←ThCrSec←InSysCrSec

#define PCR←ThCrSec←InLibCrSecs PCR←ThCrSec←InSysCrSecs


#endif /* ! ←←PCR←ThCrSecInlines←h */

/*
$Log$
*/