/*
 * @DEC_COPYRIGHT@
 */
/*
 * HISTORY
 * $Log:	exc_handling.h,v $
 * Revision 4.2.2.2  92/02/12  15:54:22  William_Burns
 * 	Merge from ODE/TIN: revision 3.1.9.2
 * 	date: 92/02/05 13:55:43;  author: devrcs;  state: Exp;  lines added/del: 13/137
 * 	sccs rev: 3.2;  orig date: 92/01/20 16:22:22;  orig author: scales
 * 	Bugfixes for MUP
 * 	[92/02/11  12:13:16  William_Burns]
 * 
 * Revision 4.2  91/09/20  04:59:35  devbld
 * 	Adding ODE Headers
 * 
 * $EndLog$
 */
/*
 *	@(#)$RCSfile: exc_handling.h,v $ $Revision: 4.2.2.2 $ (DEC) $Date: 92/02/12 15:54:22 $
 */
/*
 *  FACILITY:
 *
 *	DECthreads exception services
 *
 *  FILENAME:
 *
 * 	EXC_HANDLING.H
 *
 *  ABSTRACT:
 *
 *	Header file for exception handling in C
 *
 *  AUTHORS:
 *
 *	Eric Roberts
 *
 *  CREATION DATE:
 *
 *	15 March 1989
 *
 *  MODIFIED BY:
 *
 *	Dave Butenhof
 *	Bob Conti
 *	Paul Curtin
 *	Webb Scales
 */


#ifndef EXC_HANDLING
# define EXC_HANDLING	1

/*
 *  INCLUDE FILES
 */

#define _EXC__CC	1
#define _EXC__VAXC	2
#define _EXC__DECC	3
#define _EXC__CFRONT	4
#define _EXC__GCC	5

/*
 * Test for C++ compilers before C compilers because Glockenspiel C++ also
 * defines symbols for the VAX C compiler and this could be the case for
 * other C++/C compiler combinations
 */
#ifndef _EXC_COMPILER_
# if defined(__cplusplus)		/* test for other C++ compilers first */
#  define _EXC_COMPILER_	_EXC__CFRONT
# elif defined(vaxc) || defined(VAXC) || defined(__vaxc) || defined(__VAXC)
#  define _EXC_COMPILER_	_EXC__VAXC
# elif defined(__decc) || defined(__DECC)
#  define _EXC_COMPILER_	_EXC__DECC
# elif defined(__GNUC__)
#  define _EXC_COMPILER_	_EXC__GCC
# else
#  define _EXC_COMPILER_	_EXC__CC
# endif
#endif

/*
 * Name of the hardware platform
 */
#define	_EXC__MIPS	1
#define	_EXC__VAX	2
#define _EXC__M68K	3
#define _EXC__HPPA	4
#define _EXC__IBMR2     5

#ifndef	_EXC_HARDWARE_
# if defined(vax) || defined (VAX) || defined(__vax) || defined(__VAX)
#  define	_EXC_HARDWARE_	_EXC__VAX
# endif
# if defined(mips) || defined(MIPS) || defined(__mips) || defined(__MIPS) || defined(__MIPSEL__) || defined(__mips__)
#  define	_EXC_HARDWARE_	_EXC__MIPS
# endif
# if defined(m68k) || defined(m68000) || defined(_ISP__M68K) || defined(M68000) || defined(mc68000) 
#  define	_EXC_HARDWARE_	_EXC__M68K
# endif
# if defined(hp9000s300) || defined(__hp9000s300)
#  define	_EXC_HARDWARE_	_EXC__M68K
# endif
# if defined(__hppa0)
#  define	_EXC_HARDWARE_	_EXC__HPPA
# endif
# if defined(_IBMR2)
#  define _EXC_HARDWARE_ _EXC__IBMR2
# endif
# ifndef _EXC_HARDWARE_
   !!!Error: _EXC_HARDWARE_ not set
# endif
#endif

#define _EXC__UNIX	1
#define _EXC__VMS	2

#ifndef	_EXC_OS_
# if defined(unix) || defined(__unix) || defined(__unix__) || defined(_AIX) || defined(__OSF__) || defined(__osf__)
#  define	_EXC_OS_	_EXC__UNIX
# endif
# if defined(vms) || defined(__vms) || defined(VMS) || defined(__VMS) || defined(__vms__)
#  define	_EXC_OS_	_EXC__VMS
# endif
# ifndef _EXC_OS_
   !!!Error: _EXC_OS_ not set
# endif
#endif

/*
 * Combined platform (OS + hardware)
 */
#define	_EXC__MIPS_UNIX	1
#define	_EXC__VAX_VMS	2
#define _EXC__VAX_UNIX	3
#define _EXC__M68K_UNIX	4
#define _EXC__HPPA_UNIX	5
#define _EXC__IBMR2_UNIX 6

#ifndef	_EXC_PLATFORM_
# if _EXC_OS_ == _EXC__UNIX
#  if _EXC_HARDWARE_ == _EXC__MIPS
#   define _EXC_PLATFORM_	_EXC__MIPS_UNIX
#  endif
#  if _EXC_HARDWARE_ == _EXC__VAX
#   define _EXC_PLATFORM_	_EXC__VAX_UNIX
#  endif
#  if _EXC_HARDWARE_ == _EXC__M68K
#   define _EXC_PLATFORM_	_EXC__M68K_UNIX
#  endif
#  if _EXC_HARDWARE_ == _EXC__HPPA
#   define _EXC_PLATFORM_	_EXC__HPPA_UNIX
#  endif
#  if _EXC_HARDWARE_ == _EXC__IBMR2
#   define _EXC_PLATFORM_	_EXC__IBMR2_UNIX
#  endif
# endif
# if (_EXC_OS_ == _EXC__VMS) && (_EXC_HARDWARE_ == _EXC__VAX)
#  define _EXC_PLATFORM_	_EXC__VAX_VMS
# endif
# ifndef _EXC_PLATFORM_
   !!!Error: _EXC_PLATFORM_ not set
# endif
#endif

/*
 * Name of the software vendor (alphabetical order :-) )
 */
#define _EXC__APOLLO	1
#define _EXC__DIGITAL	2
#define _EXC__HP        3
#define _EXC__IBM       4
#define _EXC__OSF	5
#define _EXC__SUN       6

#ifndef _EXC_VENDOR_
# ifdef apollo
#  define	_EXC_VENDOR_	_EXC__APOLLO
# endif
# if _EXC_OS_ == _EXC__VMS
#  define	_EXC_VENDOR_	_EXC__DIGITAL
# endif
# if defined(ultrix) || defined(__ULTRIX) || defined (__ultrix)
#  define	_EXC_VENDOR_	_EXC__DIGITAL
# endif
# if defined(hpux) || defined(__hpux)
#  define	_EXC_VENDOR_	_EXC__HP
# endif
# ifdef _IBMR2
#  define 	_EXC_VENDOR_	_EXC__IBM
# endif
# ifdef sun
#  define	_EXC_VENDOR_	_EXC__SUN
# endif
# if (defined (__OSF__) || defined (__osf__)) && !defined (_EXC_VENDOR_)
#  define	_EXC_VENDOR_	_EXC__OSF
# endif
# ifndef _EXC_VENDOR_
   !!!Error: _EXC_VENDOR_ not set
# endif
#endif

/*
 * This controls whether ANSI C function prototypes are used for EXC
 * interfaces.
 */
#ifndef	_EXC_PROTO_
# ifdef __STDC__
#  define _EXC_PROTO_		1
# endif
# if _EXC_COMPILER_ == _EXC__DECC
#  define _EXC_PROTO_		1
# endif
# if _EXC_COMPILER_ == _EXC__GCC
#  define _EXC_PROTO_		1
# endif
# if _EXC_COMPILER_ == _EXC__CFRONT
#  define _EXC_PROTO_		1
# endif
# if _EXC_COMPILER_ == _EXC__VAXC
#  define _EXC_PROTO_		1
# endif
# if (_EXC_VENDOR_ == _EXC__DIGITAL) && (_EXC_HARDWARE_ == _EXC__MIPS)
#  define _EXC_PROTO_		1
# endif
# if _EXC_VENDOR_ == _EXC__APOLLO
#  define _EXC_PROTO_		1
# endif
# if (_EXC_VENDOR_ == _EXC__HP) && (_EXC_HARDWARE_ == _EXC__HPPA)
#  define _EXC_PROTO_		1
# endif
# if _EXC_HARDWARE_ == _EXC__IBMR2
#  define _EXC_PROTO_		1
# endif
/* Otherwise, _EXC_PROTO_ is undefined, which means do not use prototypes. */
#endif

#ifndef	_EXC_VOLATILE_
# if _EXC_PLATFORM_ == _EXC__VAX_UNIX
#  if _EXC_COMPILER_ == _EXC__CC
#   define _EXC_VOLATILE_
#   define _EXC_VOLATILE_FLAG_		0
#  endif
# endif
# if _EXC_VENDOR_ == _EXC__SUN
#  define _EXC_VOLATILE_
#  define _EXC_VOLATILE_FLAG_		0
# endif
#ifndef	_EXC_VOLATILE_
#  define _EXC_VOLATILE_  		volatile
#  define _EXC_VOLATILE_FLAG_		1
# endif
#endif

#ifndef _EXC_IMPORT_
# if _EXC_OS_ == _EXC__VMS
#  define _EXC_IMPORT_ globalref
# else
#  define _EXC_IMPORT_ extern
# endif
#endif

#ifdef _EXC_PROTO_
#define _EXC_PROTOTYPE_(arg)	arg
#else
#define _EXC_PROTOTYPE_(arg)	()
#endif

#define _EXC__OS_AIX	1
#define _EXC__OS_OSF	2
#define _EXC__OS_BSD	3
#define _EXC__OS_SYSV	4

#ifndef _EXC_OSIMPL_
# if defined (__OSF__) || defined (__osf__)
#  define _EXC_OSIMPL_		_EXC__OS_OSF
# else
#  if _EXC_VENDOR_ == _EXC__IBM
#   define _EXC_OSIMPL_		_EXC__OS_AIX
#  else
#   if _EXC_VENDOR_ == _EXC__SUN
#    define _EXC_OSIMPL_	_EXC__OS_SYSV
#   else
#    define _EXC_OSIMPL_	_EXC__OS_BSD
#   endif
#  endif
# endif
#endif

/*
 * NOTE: on U*IX systems, these status codes must be kept unique from
 * "Enums".  We do this arbitrarily by setting some high order bits which
 * happen to be the same as we use on VMS. Apollo systems use different
 * error numbering scheme, and override this.
 */
#if _EXC_VENDOR_ == _EXC__APOLLO
# define _EXC_STATUS_(val, sev) ((exc_t_int)(0x030c0000 + (val)))
#endif
#if _EXC_PLATFORM_ == _EXC__VAX_VMS
# define _EXC_STATUS_(val, sev) \
	((exc_t_int)(00020100000 | ((val) << 3) | (sev)))
#endif
#ifndef _EXC_STATUS_
# define _EXC_STATUS_(val, sev) \
	((exc_t_int)(00020100000 | ((val) << 3) | (sev)))
#endif

#ifdef apollo
# if _EXC_APOLLO_DONT_INCLUDE_BASE_
#  ifndef _EXC_APOLLO_STATUS_DEFINED_
#   define _EXC_APOLLO_STATUS_DEFINED_ 1
typedef struct {long all;} status_$t;
#  endif
# else
#  include <apollo/base.h>
#  include <apollo/error.h>
# endif
# include <apollo/pfm.h>
#else
# include <setjmp.h>
#endif

/*
 * Define a symbol that specifies whether exception handling should use the
 * standard setjmp() and longjmp() functions, or the alternate _setjmp() and
 * _longjmp().  The latter are faster, as they don't save/restore the signal
 * mask (and therefore require no kernel calls).  However, _setjmp() and
 * _longjmp() are not standard, and therefore may not be available
 * everywhere. Also, there may be some platforms where failing to save signal
 * state could break exception handling. For both reasons, we enable use of
 * the optimized functions only where we know for sure they are both
 * available and appropriate.
 */
#ifndef _EXC_BAR_JMP_
# if (_EXC_VENDOR_ == _EXC__DIGITAL) && (_EXC_OS_ == _EXC__UNIX)
#  define _EXC_BAR_JMP_	1
# endif
# if !defined(_EXC_BAR_JMP_) && _EXC_OSIMPL_ == _EXC__OS_OSF
#  define _EXC_BAR_JMP_	1
# endif
# ifndef _EXC_BAR_JMP_
#  define _EXC_BAR_JMP_	0
# endif
#endif

#if _EXC_BAR_JMP_
extern int _setjmp ();
extern void _longjmp ();
# define exc_setjmp(__env)		_setjmp ((__env))
# define exc_longjmp(__env,__val)	_longjmp((__env),(__val))
#else
# define exc_setjmp(__env)		setjmp ((__env))
# define exc_longjmp(__env,__val)	longjmp((__env),(__val))
#endif

#if _EXC_OS_ == _EXC__VMS
# if _EXC_COMPILER_ == _EXC__VAXC
#  include <exc_handling_vms.h>
# else
   extern char *exc_fetch_fp (void);
# endif
#endif

/*
 * Define all of the status codes used by DECthreads.
 *
 * For VMS, these must remain in synch with the CMA_MESSAGE.GNM message file.
 *
 * These values cannot be altered after they have shipped in some DECthreads
 * release.
 */

/*
 * EXC facility messages
 */
#define exc_s_exception         _EXC_STATUS_(1, 4)
#define exc_s_exccop            _EXC_STATUS_(2, 4)
#define exc_s_uninitexc         _EXC_STATUS_(3, 4)

/*
 * These should be set to match with underlying system exception codes on
 * platforms where that is appropriate (e.g., ss$_ codes on VAX/VMS).
 */
#if _EXC_PLATFORM_ == _EXC__VAX_VMS
/*
 * A few of these codes are somewhat imaginary, since VAX/VMS doesn't support
 * condition codes that very closely approximate the sense of some UNIX
 * signals.  SIGTRAP, SIGIOT, and SIGEMT have no clear parallels, and the
 * values chosen are fairly arbitrary.  For two others, we chose what seemed
 * close equivalents: SIGPIPE becomes "no mailbox", and SIGXFSZ becomes "disk
 * quota exceeded".
 */
# define exc_s_illaddr		12	/* ss$_accvio */
# define exc_s_exquota		28	/* ss$_exquota */
# define exc_s_insfmem		292	/* ss$_insfmem */
# define exc_s_nopriv		36	/* ss$_nopriv */
# define exc_s_normal		1	/* ss$_normal */
# define exc_s_illinstr		1084	/* ss$_opcdec */
# define exc_s_resaddr		1100	/* ss$_radrmod */
# define exc_s_privinst		1084	/* ss$_opcdec */
# define exc_s_resoper		1108	/* ss$_roprand */
# define exc_s_SIGTRAP		1044	/* ss$_break */
# define exc_s_SIGIOT		44	/* ss$_abort */
# define exc_s_SIGEMT		1068	/* ss$_compat */
# define exc_s_aritherr		1164	/* ss$_fltovf */
# define exc_s_SIGSYS		20	/* ss$_badparam */
# define exc_s_SIGPIPE		628	/* ss$_nombx */
# define exc_s_excpu		8364	/* ss$_excputim */
# define exc_s_exfilsiz		1004	/* ss$_exdiskquota */
# define exc_s_intovf		1148	/* ss$_intovf */
# define exc_s_intdiv		1156	/* ss$_intdiv */
# define exc_s_fltovf		1164	/* ss$_fltovf */
# define exc_s_fltdiv		1172	/* ss$_fltdiv */
# define exc_s_fltund		1180	/* ss$_fltund */
# define exc_s_decovf		1188	/* ss$_decovf */
# define exc_s_subrng		1196	/* ss$_subrng */
#else
# define exc_s_illaddr		_EXC_STATUS_(5, 4)
# define exc_s_exquota		_EXC_STATUS_(6, 4)
# define exc_s_insfmem		_EXC_STATUS_(7, 4)
# define exc_s_nopriv		_EXC_STATUS_(8, 4)
# define exc_s_normal		_EXC_STATUS_(9, 1)
# define exc_s_illinstr		_EXC_STATUS_(10, 4)
# define exc_s_resaddr		_EXC_STATUS_(11, 4)
# define exc_s_privinst		_EXC_STATUS_(12, 4)
# define exc_s_resoper		_EXC_STATUS_(13, 4)
# define exc_s_SIGTRAP		_EXC_STATUS_(14, 4)
# define exc_s_SIGIOT		_EXC_STATUS_(15, 4)
# define exc_s_SIGEMT		_EXC_STATUS_(16, 4)
# define exc_s_aritherr		_EXC_STATUS_(17, 4)
# define exc_s_SIGSYS		_EXC_STATUS_(18, 4)
# define exc_s_SIGPIPE		_EXC_STATUS_(19, 4)
# define exc_s_excpu		_EXC_STATUS_(20, 4)
# define exc_s_exfilsiz		_EXC_STATUS_(21, 4)
# define exc_s_intovf		_EXC_STATUS_(22, 4)
# define exc_s_intdiv		_EXC_STATUS_(23, 4)
# define exc_s_fltovf		_EXC_STATUS_(24, 4)
# define exc_s_fltdiv		_EXC_STATUS_(25, 4)
# define exc_s_fltund		_EXC_STATUS_(26, 4)
# define exc_s_decovf		_EXC_STATUS_(27, 4)
# define exc_s_subrng		_EXC_STATUS_(28, 4)
#endif

/*
 * Define alias names
 */
#define exc_s_accvio		exc_s_illaddr
#define exc_s_SIGILL		exc_s_illinstr
#define exc_s_SIGFPE		exc_s_aritherr
#define exc_s_SIGBUS		exc_s_illaddr
#define exc_s_SIGSEGV		exc_s_illaddr
#define exc_s_SIGXCPU		exc_s_excpu
#define exc_s_SIGXFSZ		exc_s_exfilsiz

/*
 * DECthreads facility (CMA) messages
 */
#define cma_s_alerted           _EXC_STATUS_(48, 4)
#define cma_s_assertion         _EXC_STATUS_(49, 4)
#define cma_s_badparam          _EXC_STATUS_(50, 4)
#define cma_s_bugcheck          _EXC_STATUS_(51, 4)
#define cma_s_exit_thread       _EXC_STATUS_(52, 4)
#define cma_s_existence         _EXC_STATUS_(53, 4)
#define cma_s_in_use            _EXC_STATUS_(54, 4)
#define cma_s_use_error         _EXC_STATUS_(55, 4)
#define cma_s_wrongmutex	_EXC_STATUS_(56, 4)
#define cma_s_stackovf          _EXC_STATUS_(57, 4)
#define cma_s_nostackmem        _EXC_STATUS_(58, 4)
#define cma_s_notcmastack       _EXC_STATUS_(59, 4)
#define cma_s_timed_out         _EXC_STATUS_(60, 4)
#define cma_s_unimp             _EXC_STATUS_(61, 4)
#define cma_s_inialrpro         _EXC_STATUS_(62, 4)
#define cma_s_defer_q_full      _EXC_STATUS_(63, 4)
#define cma_s_signal_q_full	_EXC_STATUS_(64, 4)
#define cma_s_alert_nesting	_EXC_STATUS_(65, 4)

/*
 * Synonyms for convenience
 */
#define cma_s_normal		exc_s_normal

/*
 * TYPEDEFS
 */

/*
 * Constants for the kind of an exception object.
 *
 * There are *currently* only two kinds.  In the address-kind, the identity
 * of an exception object is its address; in the value-kind, the
 * identity of an exception object is an integer, typically, 
 * a system-defined-status-value. These coded kinds also
 * serve as sentinels to help detect uninitialized exceptions.
 */
typedef enum EXC_T_KIND {
    exc_c_kind_address	= 0x02130455,  
    exc_c_kind_status	= 0x02130456
    }			exc_t_kind;

/*
 * Internal contents of an exception object.
 */
typedef int exc_t_int;
typedef char *exc_t_address;
typedef struct EXC_T_KIND_ADDRESS {
    exc_t_kind		kind;
    exc_t_address	address;
    exc_t_int		filler[6];
    } exc_t_kind_address;
typedef struct EXC_T_KIND_STATUS {
    exc_t_kind		kind;
    exc_t_int		status;
    exc_t_int		filler[6];
    } exc_t_kind_status;
typedef union EXC_T_EXCEPTION	{
    exc_t_kind		kind;
    exc_t_kind_status	status_kind;
    exc_t_kind_address	address_kind;
    } EXCEPTION;

/*
 * Constants for the state of handling in the current TRY clause.
 * 
 * The state is "none" when no exception has been raised, "active" when
 * one has been raised but has not yet been caught by a CATCH clause, and
 * "handled" after the exception has been caught by some CATCH clause.
 */
typedef enum EXC_T_STATE {
    exc_c_active	= 0, /* This must be the 0 state, see pop_ctx */
    exc_c_none		= 1,
    exc_c_handled	= 2,
    exc_c_popped	= 3
    }			exc_t_state;

/*
 * Structure of a context block.
 *
 * A context block is allocated in the current stack frame for each
 * TRY clause.  These context blocks are linked to form a stack of
 * all current TRY blocks in the current thread.  Each context block
 * contains a jump buffer for use by setjmp and longjmp.  
 *
 */
typedef struct EXC_T_CONTEXT {
#if _EXC_VENDOR_ == _EXC__APOLLO
    status_$t		st;
    pfm_$cleanup_rec	crec;
#else
  jmp_buf		jmp;		/* Jump buffer */
#endif
  _EXC_VOLATILE_ struct EXC_T_CONTEXT
			*link;		/* Link to context block stack */
  EXCEPTION		cur_exception;	/* Copy of the current exception */
  exc_t_state		exc_state;	/* State of handling for this TRY */
#if _EXC_OS_ == _EXC__VMS
  exc_t_address		current_frame;	/* Address of current stack frame */
#endif
  exc_t_int		filler[6];
  } exc_t_context;

/*
 *  GLOBAL DATA
 */

extern void exc_push_ctx _EXC_PROTOTYPE_ ((	/* Push a context block */
	_EXC_VOLATILE_	exc_t_context *cb));
extern void exc_pop_ctx _EXC_PROTOTYPE_ ((	/* Pop a context block */
	_EXC_VOLATILE_	exc_t_context *cb));
extern void exc_raise _EXC_PROTOTYPE_ ((	/* Raise an exception */
	EXCEPTION *exc));
extern void exc_raise_status _EXC_PROTOTYPE_ ((	/* Raise a status as exception*/
	exc_t_int	status));
extern void exc_report _EXC_PROTOTYPE_ ((	/* Report an exception */
	EXCEPTION *exc));
/*
 * The following function allows a client to declare that asynchronous
 * terminating signals should be handled by the exception package and result
 * in a cancel (alert) against a specified thread. The prototype is
 *
 *	void exc_handle_async_signals (
 *		sigset_t	*sigset,
 * 		pthread_t	*thread);
 *
 * On some platforms, DECthreads has to "fake" the definition of sigset_t,
 * and we also want the thread parameter to accept either a CMA interface
 * handle or a P1003.4a interface handle (which are interchangeable). To
 * avoid difficulties in the declaration, I'm going to "cheat" a little by
 * not using a prototype at all.
 */
extern void exc_handle_async_signals ();

#if _EXC_VENDOR_ == _EXC__APOLLO
void exc_catch_prologue (/* exc_t_context *ctx */ );	/* Get ready to handle exception */
#endif
#if _EXC_OS_ == _EXC__VMS
extern int  exc_handler (/* sargs, margs*/);	/* System condition handler */
#endif

/*
 * Define the exception values that go with the above status codes
 *
 * NOTE: it does not make sense to turn all of the above into 
 * exceptions as some are never raised as exceptions.  Those are:
 *	cma_s_normal	-- never signalled
 *	cma_s_exception	-- internal to the implementation of exceptions
 * 	cma_s_exccop	-- internal to the implementation of exceptions
 *	cma_s_timed_out -- returned as status value from timed condition wait
 */

_EXC_IMPORT_ EXCEPTION
    exc_e_uninitexc,
    exc_e_illaddr,
    exc_e_exquota,
    exc_e_insfmem,
    exc_e_nopriv,
    exc_e_illinstr,
    exc_e_resaddr,
    exc_e_privinst,
    exc_e_resoper,
    exc_e_SIGTRAP,
    exc_e_SIGIOT,
    exc_e_SIGEMT,
    exc_e_aritherr,
    exc_e_SIGSYS,
    exc_e_SIGPIPE,
    exc_e_excpu,
    exc_e_exfilsiz,
    exc_e_intovf,
    exc_e_intdiv,
    exc_e_fltovf,
    exc_e_fltdiv,
    exc_e_fltund,
    exc_e_decovf,
    exc_e_subrng,
    cma_e_alerted,
    cma_e_assertion,
    cma_e_badparam,
    cma_e_bugcheck,
    cma_e_exit_thread,
    cma_e_existence,
    cma_e_in_use,
    cma_e_use_error,
    cma_e_wrongmutex,
    cma_e_stackovf,
    cma_e_nostackmem,
    cma_e_notcmastack,
    cma_e_unimp,
    cma_e_inialrpro,
    cma_e_defer_q_full,
    cma_e_signal_q_full,
    cma_e_alert_nesting;

/*
 * Define aliased exceptions
 */
#define exc_e_accvio		exc_e_illaddr
#define exc_e_SIGILL		exc_e_illinstr
#define exc_e_SIGFPE		exc_e_aritherr
#define exc_e_SIGBUS		exc_e_illaddr
#define exc_e_SIGSEGV		exc_e_illaddr
#define exc_e_SIGXCPU		exc_e_excpu
#define exc_e_SIGXFSZ		exc_e_exfilsiz

/*
 * The following are pthread exception names.
 */

#define exc_uninitexc_e		exc_e_uninitexc
#define exc_illaddr_e		exc_e_illaddr
#define exc_exquota_e		exc_e_exquota
#define exc_insfmem_e		exc_e_insfmem
#define exc_nopriv_e		exc_e_nopriv
#define exc_illinstr_e		exc_e_illinstr
#define exc_resaddr_e		exc_e_resaddr
#define exc_privinst_e		exc_e_privinst
#define exc_resoper_e		exc_e_resoper
#define exc_SIGTRAP_e		exc_e_SIGTRAP
#define exc_SIGIOT_e		exc_e_SIGIOT
#define exc_SIGEMT_e		exc_e_SIGEMT
#define exc_aritherr_e		exc_e_aritherr
#define exc_SIGSYS_e		exc_e_SIGSYS
#define exc_SIGPIPE_e		exc_e_SIGPIPE
#define exc_excpu_e		exc_e_excpu
#define exc_exfilsiz_e		exc_e_exfilsiz
#define exc_intovf_e		exc_e_intovf
#define exc_intdiv_e		exc_e_intdiv
#define exc_fltovf_e		exc_e_fltovf
#define exc_fltdiv_e		exc_e_fltdiv
#define exc_fltund_e		exc_e_fltund
#define exc_decovf_e		exc_e_decovf
#define exc_subrng_e		exc_e_subrng

#define pthread_cancel_e	cma_e_alerted
#define pthread_assertion_e	cma_e_assertion
#define pthread_badparam_e	cma_e_badparam
#define pthread_bugcheck_e	cma_e_bugcheck
#define pthread_exit_thread_e	cma_e_exit_thread
#define pthread_existence_e	cma_e_existence
#define pthread_in_use_e	cma_e_in_use
#define pthread_use_error_e	cma_e_use_error
#define pthread_wrongmutex_e	cma_e_wrongmutex
#define pthread_stackovf_e	cma_e_stackovf
#define pthread_nostackmem_e	cma_e_nostackmem
#define pthread_notstack_e	cma_e_notcmastack
#define pthread_unimp_e		cma_e_unimp
#define pthread_inialrpro_e	cma_e_inialrpro
#define pthread_defer_q_full_e	cma_e_defer_q_full
#define pthread_signal_q_full_e	cma_e_signal_q_full

#define exc_accvio_e		exc_e_accvio
#define exc_SIGILL_e		exc_e_SIGILL
#define exc_SIGFPE_e		exc_e_SIGFPE
#define exc_SIGBUS_e		exc_e_SIGBUS
#define exc_SIGSEGV_e		exc_e_SIGSEGV
#define	exc_SIGXCPU_e		exc_e_SIGXCPU
#define exc_SIGXFSZ_e		exc_e_SIGXFSZ

/*
 * CONSTANTS AND MACROS
 */

/*
 * Define "keyword" to initialize an exception.
 * Note: all exceptions *must* be initialized using this macro.
 */
#define EXCEPTION_INIT(e)   (	\
    (e).address_kind.address = (exc_t_address)&(e),	\
    (e).address_kind.kind = exc_c_kind_address)

/*
 * Define "routine" to equivalence an exception to an integer
 * (typically a system-defined status value).
 */
#define exc_set_status(e,s) ( \
    (e)->status_kind.status = (s), \
    (e)->status_kind.kind = exc_c_kind_status)

/*
 * Define "routine" to return the status of an exception. Returns 0 if status
 * kind (and value of status in *s), or -1 if not status kind.
 */
#define exc_get_status(e,s) ( \
    (e)->kind == exc_c_kind_status ? \
	(*(s) = (e)->status_kind.status, 0) : \
	-1)

/*
 * Define "routine" to determine if two exceptions match.
 */
#define exc_matches(e1,e2) \
    ((e1)->kind == (e2)->kind && \
    (e1)->address_kind.address == (e2)->address_kind.address)

/*
 * Define "statement" for clients to use to raise an exception.
 */
#define RAISE(e) exc_raise(&(e))

#if _EXC_OS_ == _EXC__VMS
#define exc_establish() {\
	exc_ctx.current_frame = ((exc_t_address)exc_fetch_fp());\
	VAXC$ESTABLISH(exc_handler);}
#else
#define exc_establish()
#endif

/* 
 * Start a new TRY block, which may contain exception handlers
 * 
 *   Allocate a context block on the stack to remember the current
 *   exception. Push it on the context block stack.  Initialize
 *   this context block to indicate that no exception is active. Do a SETJMP
 *   to snapshot this environment (or return to it).  Then, start
 *   a block of statements to be guarded by the TRY clause.
 *   This block will be ended by one of the following: a CATCH, CATCH_ALL,
 *   or the ENDTRY macros.
 */
#ifdef apollo
# define TRY \
    { \
        _EXC_VOLATILE_ exc_t_context exc_ctx; \
	exc_push_ctx (&exc_ctx); \
        exc_ctx.st = pfm_$cleanup((pfm_$cleanup_rec *)&exc_ctx.crec); \
        if (exc_ctx.st.all != pfm_$cleanup_set) \
            exc_catch_prologue(&exc_ctx); \
        if (exc_ctx.st.all == pfm_$cleanup_set) {
/*		{ user's block of code goes here } 	*/
#else
# define TRY \
    { \
	_EXC_VOLATILE_ exc_t_context exc_ctx; \
	exc_push_ctx (&exc_ctx);\
	exc_establish ();\
        if (!exc_setjmp (exc_ctx.jmp)) {
/*		{ user's block of code goes here } 	*/
#endif

/* 
 * Define an CATCH(e) clause (or exception handler).
 *
 *   First, end the prior block.  Then, check if the current exception
 *   matches what the user is trying to catch with the CATCH clause.
 *   If there is a match, a variable is declared to support lexical
 *   nesting of RERAISE statements, and the state of the current
 *   exception is changed to "handled".
 */
#define CATCH(e) \
            } \
            else if (exc_matches(&exc_ctx.cur_exception, &(e))) { \
		EXCEPTION *THIS_CATCH = (EXCEPTION *)&exc_ctx.cur_exception;\
		exc_ctx.exc_state = exc_c_handled;
/*		{ user's block of code goes here } 	*/

/* 
 * Define an CATCH_ALL clause (or "catchall" handler).
 *
 *   First, end the prior block.  Then, unconditionally,
 *   let execution enter into the catchall code.  As with a normal
 *   catch, a variable is declared to support lexical
 *   nesting of RERAISE statements, and the state of the current
 *   exception is changed to "handled".
 */
#define CATCH_ALL \
            } \
            else { \
		EXCEPTION *THIS_CATCH = (EXCEPTION *)&exc_ctx.cur_exception;\
		exc_ctx.exc_state = exc_c_handled;
/*		{ user's block of code goes here } 	*/

/* 
 * Define a RERAISE statement.
 * 
 *   This "statement" is valid only if lexically nested in
 *   a CATCH or CATCH_ALL clause. Reraise the current lexically visible 
 *   exception (the declaration of THIS_CATCH must be visible otherwise 
 *   a compilation error results).
 */
#define RERAISE exc_raise(THIS_CATCH)

/* 
 * Define a FINALLY clause
 *
 *   This "keyword" starts a FINALLY clause.  It must appear before
 *   an ENDTRY.  A FINALLY clause will be entered after normal exit
 *   of the TRY block, or if an unhandled exception tries to propagate
 *   out of the TRY block.  
 *
 *   Unlike Modula 3's TRY clause, we do not expend overhead trying to
 *   enforce that FINALLY be mutually exclusive with CATCH clauses.  Currently, 
 *   if they are used together, then control will drop into a FINALLY clause 
 *   under the following conditions:
 *	o normal exit from TRY, 
 *	o an exception is raised and no CATCH is present (recommended usage) 
 *	o CATCH's are present but none matches the exception.
 *	o CATCH's are present and one matches the exception, but it
 *	  does not raise any exception.  
 *   That is, FINALLY is always entered after TRY unless a CATCH clause raises 
 *   (or re-raises) an exception.
 *
 *			** WARNING **
 *   You should *avoid* using FINALLY with CATCH clauses, that is, use it 
 *   only as TRY {} FINALLY {} ENDTRY.  Source code that combines CATCHes
 *   with FINALLY in the same TRY clause is considered "unsupported"
 *   -- that is, such code may be broken by a future version of this
 *   package.  
 *
 *   There are several reasons this restriction is necessary:
 *	o FINALLY may be added to C++ and its combination with CATCH
 *	  clauses may have different semantics than implemented by these macros.
 *	o The restriction is consistant with the same restriction in Modula 3
 *	o It allows the use of the 2-phase or "debugging" implementation 
 *	  technique of the SRC exception package for these same macros.
 */
#ifdef apollo
# define FINALLY   } \
	if (exc_ctx.exc_state == exc_c_none) { \
            status_$t st; \
            pfm_$rls_cleanup((pfm_$cleanup_rec *)&exc_ctx.crec, &st); \
            /*??? check st? */ \
	    exc_pop_ctx (&exc_ctx); \
	    } \
	{
/*		{ user's block of code goes here } 	*/
#else
# define FINALLY   } \
	if (exc_ctx.exc_state == exc_c_none) \
	    exc_pop_ctx (&exc_ctx);\
	{
/*		{ user's block of code goes here } 	*/
#endif

/* 
 * End the whole TRY clause
 */
#ifdef apollo
# define ENDTRY \
	} \
	if (exc_ctx.exc_state == exc_c_none || exc_ctx.exc_state == exc_c_active) { \
            status_$t st; \
            pfm_$rls_cleanup((pfm_$cleanup_rec *)&exc_ctx.crec, &st); \
            /*??? check st? */ \
	    exc_pop_ctx (&exc_ctx); \
	    } \
    }
#else
# define ENDTRY \
	} \
	if (exc_ctx.exc_state == exc_c_none || exc_ctx.exc_state == exc_c_active) \
	    exc_pop_ctx (&exc_ctx); \
    }
#endif


/* 
 * POSIX style synonyms for external names
 */

#define	    exc_kind_t		exc_t_kind
#define	    exc_int_t		exc_t_int
#define	    exc_address_t	exc_t_address
#define	    exc_state_t		exc_t_state
#define	    exc_context_t	exc_t_context

/* 
 * External constants
 */

#define	    exc_kind_address_c	    exc_c_kind_address  
#define	    exc_kind_status_c	    exc_c_kind_status   
#define	    exc_kind_extended_c	    exc_c_kind_extended
#define	    exc_active_c	    exc_c_active
#define	    exc_none_c		    exc_c_none
#define	    exc_handled_c	    exc_c_handled
#define	    exc_popped_c	    exc_c_popped

#endif
