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

$Date$
 *
 * Public definitions for PCR UnwindProtection
 *
 */


#ifndef	←←PCR←ThUWProt←h
#define ←←PCR←ThUWProt←h 1

#include <config/PCR←StdTypes.h>
#include <setjmp.h>

extern const PCR←Any PCR←ThUWProt←id←LONGJMP;
extern const PCR←Any PCR←ThUWProt←id←EXIT;
extern const PCR←Any PCR←ThUWProt←id←LEAVE;

typedef struct PCR←ThUWProt←ExitArgsRep {
    int ea←code;
    PCR←Any ea←val;
} PCR←ThUWProt←ExitArgs;

typedef void
PCR←ThUWProt←Handler(PCR←Any id, PCR←Any arg, void *data);
/*
    Called (with signals disabled and id == PCR←ThUWProt←id←LONGJMP) by any
      call to longjmp()/siglongjmp() that would unwind past the frame from
      which the handler was installed (i.e. that would remove the frame).
    Called (with all signals blocked and id == PCR←ThUWProt←id←EXIT) by any
      call to exit().  In this case arg is a (PCR←ThUWProt←ExitArgs *)
      value containing the args to exit.
    Called (with all signals blocked and id == PCR←ThUWProt←id←LEAVE) by
      any call to PCR←ThUWProt←Leave(), below.
    Called (with all signals blocked and id the address of some unique object)
      by PCR←ThUWProt←Unwind(), below.
    If an unwind handler itself calls longjmp/siglongjmp or exit, or if it
      enables signals and the signal handler does so, the handler will
      *not* be reentered recursively.
    NOTE: Frames are in general associated with C procedures, *not* C blocks.
      The use of (sig)setjmp and UnwindProtect in the same C procedure
      is almost guaranteed not to work right, and is discouraged.  Nested
      uses of PCR←ThUWProt←ENTER - PCR←ThUWProt←LEAVE pairs are okay.
*/



typedef volatile struct PCR←ThUWProt←HandlerRecordRep
        PCR←ThUWProt←HandlerRecord;

typedef PCR←ThUWProt←HandlerRecord * PCR←ThUWProt←HandlerRecordPtr;

struct PCR←ThUWProt←HandlerRecordRep {
    /* private */
    PCR←ThUWProt←HandlerRecordPtr uwphr←←next;
    /* public */
    PCR←ThUWProt←Handler * uwphr←proc;
    void * uwphr←data;
};
/*
    Unwind-protect handler record.
    This *must* be an automatic variable in the frame being protected.
    The safest thing to do is to use the macros
      PCR←ThUWProt←ENTER / PCR←ThUWProt←CANCEL / PCR←ThUWProt←LEAVE
    defined below.
*/



extern void 
PCR←ThUWProt←←Enter(PCR←ThUWProt←HandlerRecordPtr uwphr);
/*
    Enter an extent unwind-protected by <handler,data>.
*/

#define PCR←ThUWProt←Enter(uwphrp,p,d) { \
    (uwphrp)->uwphr←proc = (p); (uwphrp)->uwphr←data = ((void *)(d)); \
    PCR←ThUWProt←←Enter(uwphrp); }

#define PCR←ThUWProt←ENTER(p,d) { PCR←ThUWProt←HandlerRecord ←←uwphr; \
        PCR←ThUWProt←Enter(&←←uwphr,(p),(d))


extern void 
PCR←ThUWProt←Cancel();
/*
    Leave an unwind-protected extent
      without calling the handler proc.
*/

#define PCR←ThUWProt←CANCEL() { PCR←ThUWProt←Cancel(); }}

extern void 
PCR←ThUWProt←Leave();
/*
    Leave an unwind-protected extent,
      calling the handler with id == PCR←ThUWProt←id←LEAVE.
*/

#define PCR←ThUWProt←LEAVE() { PCR←ThUWProt←Leave(); }}


extern void
PCR←ThUWProt←Unwind(PCR←Any id, PCR←Any arg);
/*
    Walk the stack, calling all unwind handlers with the specified id,
      (which should not be one of the PCR←ThUWProt←id←XXX consts above)
      and the specified arg.
    If all the handlers return, this terminates the thread. 
*/


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

/*
$Log$
*/