/*
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$
*/