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

$Date$
 *
 * PCR threads dynamic environment manipulation
 *
 */

#ifndef	←←PCR←ThDynEnv←h
#define ←←PCR←ThDynEnv←h 1


#include <config/PCR←Arch.h>
#include <config/PCR←StdTypes.h>
#include <th/PCR←ThData.h> 


#define PCR←ThDynEnv←propIndex	0


typedef struct PCR←ThDynEnv←FrameRep *PCR←ThDynEnv←FramePtr;

typedef struct PCR←ThDynEnv←FrameRep {
    PCR←ThDynEnv←FramePtr df←link;
    PCR←Any df←key;
    PCR←Any df←data[1 /* really depends on key */];
} PCR←ThDynEnv←Frame;


extern PCR←ThDynEnv←FramePtr
PCR←ThDynEnv←Get(void);

#define PCR←ThDynEnv←←Get() ((PCR←ThDynEnv←FramePtr)(\
	PCR←ThData←Get()->td←←propData[PCR←ThDynEnv←propIndex]))
#ifndef PCR←ThDynEnv←NINLINE
#   define PCR←ThDynEnv←Get	PCR←ThDynEnv←←Get
#endif
/*
    Return the dynamic environment of the current thread.
*/


extern void
PCR←ThDynEnv←Set(PCR←ThDynEnv←FramePtr fp);

#define PCR←ThDynEnv←←Set(fp) { \
	PCR←ThData←Get()->td←←propData[PCR←ThDynEnv←propIndex] = \
		((void *)(fp)); }
#ifndef PCR←ThDynEnv←NINLINE
#   define PCR←ThDynEnv←Set	PCR←ThDynEnv←←Set
#endif

/*
    Set the dynamic environment of the current thread to fp.
*/


extern PCR←ThDynEnv←FramePtr
PCR←ThDynEnv←Lookup(PCR←Any key, PCR←ThDynEnv←FramePtr fp);
/*
    Return the first frame in de with the given key, or NIL if there
    is none.
*/


extern PCR←ThDynEnv←FramePtr
PCR←ThDynEnv←FirstCommonParent(
    PCR←ThDynEnv←FramePtr fp1,
    PCR←ThDynEnv←FramePtr fp2
);
/*
    Return the first frame that is a tail of both arguments, or
      NIL if there is none.
*/



typedef PCR←ERes
PCR←ThDynEnv←Unwinder(PCR←ThDynEnv←FramePtr fp, PCR←Any data);

extern PCR←ERes
PCR←ThDynEnv←Unwind(
    PCR←ThDynEnv←FramePtr target,
    PCR←Any key,
    PCR←ThDynEnv←Unwinder *unwinder,
    PCR←Any unwinderData
);
/*
    Target must be a tail of the current dynamic environment.
    This call has the same effect as PCR←ThDynEnv←Set except
    that (*unwinder)(f, unwinderData) is called for each frame f
    in the difference between the current dynamic environment and
    the target such that f matches key (i.e., (f->df←key == key)
    or (key == NIL)).  Before (*unwinder)(f, d) is called, the
    dynamic environment is set to what was in effect when
    the frame f was pushed.
	
    Returns EINVAL if target is not a tail of the current dynamic
    environment.

    If any of the unwinder calls returns an error, the unwinding
    terminates and that error is returned from the call to Unwind.

    NOTE that this call will not return at all if any of the unwinders
    that it calls does not do so.
*/


typedef PCR←ERes
PCR←ThDynEnv←Rewinder(PCR←ThDynEnv←FramePtr fp, PCR←Any data);

extern PCR←ERes
PCR←ThDynEnv←Rewind(
    PCR←ThDynEnv←FramePtr target,
    PCR←Any key,
    PCR←ThDynEnv←Rewinder *rewinder,
    PCR←Any rewinderData
);
/*
    The current dynamic environment must be a tail of target.
    This call has the same effect as PCR←ThDynEnv←Set except
    that (*rewinder)(f, rewinderData) is called for each frame f
    in the difference between target and the current dynamic
    environment such that f matches key (i.e., (f->df←key == key)
    or (key == NIL)).  Before (*rewinder)(f, d) is called, the
    dynamic environment is set to what was in effect when
    the frame f was pushed.
	
    Returns okay if the current dynamic environment is a tail of
    target, and EINVAL otherwise.
	
    NOTE that this call will not return at all if any of the rewinders
    that it calls does not do so.
*/



extern const PCR←Any PCR←ThDynEnv←unwindFrameKey;

typedef struct PCR←ThDynEnv←UnwindFrameRep *PCR←ThDynEnv←UnwindFramePtr;

typedef struct PCR←ThDynEnv←UnwindFrameRep {
    PCR←ThDynEnv←UnwindFramePtr uf←link;
    PCR←Any uf←key;
    void (*uf←unwinder)(PCR←Any data);
    PCR←Any uf←unwinderData;
    void (*uf←rewinder)(PCR←Any data);
    PCR←Any uf←rewinderData;
} PCR←ThDynEnv←UnwindFrame;



extern PCR←ThDynEnv←Unwinder PCR←ThDynEnv←UnwinderTo;
/*
    Assuming argument frame has type PCR←ThDynEnv←UnwindFrame,
      call its uf←unwinder.
*/

extern PCR←ERes
PCR←ThDynEnv←UnwindTo(PCR←ThDynEnv←UnwindFramePtr target);
/*
    return PCR←ThDynEnv←Unwind( target, PCR←ThDynEnv←unwindFrameKey,
            PCR←ThDynEnv←UnwinderTo, NIL );
*/


extern PCR←ThDynEnv←Rewinder PCR←ThDynEnv←RewinderTo;
/*
    Assuming argument frame has type PCR←ThDynEnv←UnwindFrame,
      call its uf←rewinder.
*/


extern PCR←ERes
PCR←ThDynEnv←RewindTo(PCR←ThDynEnv←UnwindFramePtr target);
/*
    return PCR←ThDynEnv←Unwind( target, PCR←ThDynEnv←unwindFrameKey,
            PCR←ThDynEnv←RewinderTo, NIL );
*/



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

/*
$Log$
*/