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