#if defined(WIN32)
#include <winnt-pdo.h>
#include <windows.h>
#include <objc/zone.h> #endif
#if defined(KERNEL)
#import <mach/mach_types.h>
#import <kernserv/prototypes.h>
#import <kern/lock.h>
#else
#import <stdlib.h>
#endif
#import <stdio.h>
#include <unistd.h>
#if defined(_POSIX_THREADS)
#include <pthread.h>
#else
#import <mach/cthreads.h>
#endif
#import <mach/boolean.h>
#import <objc/objc.h>
#import <objc/error.h>
#if defined(NeXT_PDO)
#import <pdo.h>
#endif
#if defined(__MACH__)
#import <string.h>
#endif
typedef void AltProc(void *context, int code, const void *data1, const void *data2);
NXHandler *_NXAddAltHandler (AltProc *proc, void *context);
void _NXRemoveAltHandler (NXHandler *handler);
void _NXLogError(const char *format, ...);
#if defined(KERNEL)
#import <mach/machine/simple_lock.h>
#if defined(hppa)
#define SIMPLE_LOCK_INITIALIZER { 1, 1, 1, 1 }
#else
#define SIMPLE_LOCK_INITIALIZER { 1 }
#endif
#define LOCK_T simple_lock_data_t
#define LOCK_INITIALIZER SIMPLE_LOCK_INITIALIZER
#define LOCK(x) simple_lock(&(x))
#define UNLOCK(x) simple_unlock(&(x))
#define LOCK_ALLOC simple_lock_alloc
#define cthread_t mach_port_t
#define cthread_self() current_thread()
int _setjmp(jmp_buf env) { return setjmp(env); }
void _longjmp(jmp_buf env, int val) { longjmp(env, val); }
NXUncaughtExceptionHandler *_NXUncaughtExceptionHandler;
#elif defined(__MACH__)
#if defined(_POSIX_THREADS)
#define LOCK_T pthread_mutex_t
#define LOCK_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#define LOCK(x) pthread_mutex_lock(&x)
#define UNLOCK(x) pthread_mutex_unlock(&x)
#define cthread_t pthread_t
#define cthread_self() pthread_self()
#else
#define LOCK_T struct mutex
#define LOCK_INITIALIZER MUTEX_INITIALIZER
#define LOCK(x) mutex_lock(&x)
#define UNLOCK(x) mutex_unlock(&x)
#define cthread_t mach_port_t
extern void _set_cthread_free_callout (void (*) (void));
static void _NXClearExceptionStack (void);
#endif
#elif defined(WIN32)
#define LOCK_T long
#define LOCK_INITIALIZER 0
#define LOCK(x) mutex_lock(&x)
#define UNLOCK(x) mutex_unlock(&x)
#define cthread_t int
#define _setjmp setjmp
#define _longjmp longjmp
#elif defined(__svr4__) || defined(hpux)
#define LOCK_T mutex_t
#define LOCK_INITIALIZER NULL
#define LOCK(x) mutex_lock(x)
#define UNLOCK(x) mutex_unlock(x)
#define LOCK_ALLOC mutex_alloc
#endif // KERNEL
#if defined(NeXT_PDO)
extern _setjmp(jmp_buf env);
extern void _longjmp(jmp_buf env, int val);
NXUncaughtExceptionHandler *_NXUncaughtExceptionHandler;
#endif
typedef struct {
struct _NXHandler *next;
AltProc *proc;
void *context;
} AltHandler;
typedef struct _ErrorBuffer {
struct _ErrorBuffer *next;
char data[0];
} ErrorBuffer;
static ErrorBuffer *ErrorBufferChain = NULL;
static LOCK_T ErrorDataLock = LOCK_INITIALIZER;
typedef struct xxx {
NXHandler *handlerStack;
AltHandler *altHandlers;
int altHandlersAlloced;
int altHandlersUsed;
cthread_t thread;
struct xxx *next;
} ExceptionHandlerStack;
static AltHandler BaseAltHandlers[16] = { {0} };
static ExceptionHandlerStack Base =
{
NULL,
BaseAltHandlers,
sizeof (BaseAltHandlers) / sizeof (BaseAltHandlers[0]),
0,
0,
NULL
};
static LOCK_T Lock = LOCK_INITIALIZER;
static ExceptionHandlerStack *addme (cthread_t self)
{
ExceptionHandlerStack *stack;
#if defined(KERNEL) || defined(__svr4__) || defined(hpux)
if (!Lock)
Lock = LOCK_ALLOC (); #endif
LOCK (Lock);
#if defined(KERNEL)
for (stack = &Base; stack; stack = stack->next)
if (stack->thread == 0) {
stack->thread = self;
UNLOCK (Lock);
return stack;
}
#else // not KERNEL
if (Base.thread == 0) {
Base.thread = self;
UNLOCK (Lock);
return &Base;
}
#if defined(__MACH__) && !defined(_POSIX_THREADS)
_set_cthread_free_callout (&_NXClearExceptionStack);
#endif
#endif // KERNEL
stack = calloc (sizeof (ExceptionHandlerStack), 1);
stack->thread = self;
stack->next = Base.next;
Base.next = stack;
UNLOCK (Lock);
return stack;
}
#if !defined(BUG67896)
static inline
#endif
ExceptionHandlerStack *findme (void)
{
ExceptionHandlerStack *stack;
cthread_t self = (cthread_t)cthread_self ();
for (stack = &Base; stack; stack = stack->next)
if (stack->thread == self)
return stack;
return addme (self);
}
#ifdef KERNEL
void
_threadFreeExceptionStack(
thread_t thread
)
{
ExceptionHandlerStack *stack;
for (stack = &Base; stack; stack = stack->next)
if (stack->thread == thread)
break;
if (stack)
{
stack->handlerStack = 0; stack->altHandlersUsed = 0; stack->thread = 0;
}
}
#elif defined(__MACH__) && !defined(_POSIX_THREADS)
static void _NXClearExceptionStack (void)
{
ExceptionHandlerStack *stack;
cthread_t self = (cthread_t)cthread_self ();
for (stack = &Base; stack; stack = stack->next)
if (stack->thread == self)
break;
if (stack)
{
stack->handlerStack = 0; stack->altHandlersUsed = 0; }
}
#endif KERNEL
#define IS_ALT(ptr) ((arith_t)(ptr) % 2)
#define NEXT_HANDLER(ptr) \
(IS_ALT(ptr) ? ALT_CODE_TO_PTR(ptr)->next : ((NXHandler *)ptr)->next)
#define ALT_PTR_TO_CODE(ptr) (((ptr) - me->altHandlers) * 2 + 1)
#define ALT_CODE_TO_PTR(code) (me->altHandlers + ((arith_t)(code) - 1) / 2)
static void trickyRemoveHandler (NXHandler *handler, int removingAlt)
{
AltHandler *altNode;
NXHandler *node;
NXHandler **nodePtr;
ExceptionHandlerStack *me = findme ();
node = me->handlerStack;
while (node != handler && node)
{
#if hppa
if (IS_ALT (node) || (void *) node < (void *) &altNode)
node = NEXT_HANDLER (node);
else
#else
if (IS_ALT (node) || (void *) node > (void *) &altNode)
node = NEXT_HANDLER (node);
else
#endif
{
_NXLogError ("Exception handlers were not properly removed.");
#if defined(WIN32)
(void)RaiseException(0xdead, EXCEPTION_NONCONTINUABLE, 0, NULL);
#else
(void)abort ();
#endif
}
}
if (node)
{
if (!removingAlt)
_NXLogError ("Exception handlers were not properly removed.");
nodePtr = &me->handlerStack;
do
{
node = *nodePtr;
if (IS_ALT(node))
{
altNode = ALT_CODE_TO_PTR(node);
if (removingAlt)
{
if (node == handler)
*nodePtr = altNode->next;
else
nodePtr = &altNode->next;
}
else
{
if (node != handler)
(*altNode->proc)(altNode->context, 1, 0, 0);
me->altHandlersUsed = altNode - me->altHandlers;
*nodePtr = altNode->next;
}
}
else
{
if (removingAlt)
nodePtr = &node->next;
else
*nodePtr = node->next;
}
}
while (node != handler);
}
else
{
#ifdef KERNEL
;
#else
_NXLogError ("Attempt to remove unrecognized exception handler.");
#endif
}
}
__private_extern__
NXHandler *_NXAddAltHandler (AltProc *proc, void *context)
{
AltHandler *new;
ExceptionHandlerStack *me = findme ();
if (me->altHandlersUsed == me->altHandlersAlloced) {
if (me->altHandlers == BaseAltHandlers) {
me->altHandlers = malloc (++me->altHandlersAlloced *
sizeof(AltHandler));
bcopy (BaseAltHandlers, me->altHandlers, sizeof (BaseAltHandlers));
} else {
volatile AltHandler *tempAlt = realloc (me->altHandlers, ++me->altHandlersAlloced *
sizeof(AltHandler));
me->altHandlers = (AltHandler*)tempAlt;
}
}
new = me->altHandlers + me->altHandlersUsed++;
new->next = me->handlerStack;
me->handlerStack = (NXHandler *) ALT_PTR_TO_CODE (new);
new->proc = proc;
new->context = context;
return me->handlerStack;
}
__private_extern__
void _NXRemoveAltHandler (NXHandler *handler)
{
ExceptionHandlerStack *me;
for (me = &Base; me; me = me->next)
if (me->handlerStack == handler)
{
AltHandler *altNode = ALT_CODE_TO_PTR (handler);
me->altHandlersUsed = altNode - me->altHandlers;
me->handlerStack = altNode->next;
return;
}
trickyRemoveHandler (handler, TRUE);
}
__private_extern__
void _NXAddHandler (NXHandler *handler)
{
ExceptionHandlerStack *me = findme ();
handler->next = me->handlerStack;
me->handlerStack = handler;
handler->code = 0;
}
__private_extern__
void _NXRemoveHandler (NXHandler *handler)
{
ExceptionHandlerStack *me;
for (me = &Base; me; me = me->next)
if (me->handlerStack == handler)
{
me->handlerStack = me->handlerStack->next;
return;
}
trickyRemoveHandler (handler, FALSE);
}
__private_extern__
volatile void NXDefaultExceptionRaiser(int code, const void *data1, const void *data2)
{
NXHandler *destination;
AltHandler *altDest;
ExceptionHandlerStack *me = findme ();
while (1) {
destination = me->handlerStack;
if (!destination) {
if (_NXUncaughtExceptionHandler)
(*_NXUncaughtExceptionHandler)(code, data1, data2);
else {
#ifndef KERNEL
_NXLogError("Uncaught exception #%d\n", code);
#endif
}
#ifdef KERNEL
panic("Uncaught exception");
#else
#if defined(WIN32)
(void)RaiseException(0xdead, EXCEPTION_NONCONTINUABLE, 0, NULL);
#else
exit(-1);
#endif
#endif
} else if (IS_ALT(destination)) {
altDest = ALT_CODE_TO_PTR(destination);
me->handlerStack = altDest->next;
me->altHandlersUsed = altDest - me->altHandlers;
(*altDest->proc)(altDest->context, code, data1, data2);
} else {
destination->code = code;
destination->data1 = data1;
destination->data2 = data2;
me->handlerStack = destination->next;
_longjmp(destination->jumpState, 1);
}
}
}
static NXExceptionRaiser *ExceptionRaiser = &NXDefaultExceptionRaiser;
__private_extern__
void NXSetExceptionRaiser(NXExceptionRaiser *proc)
{
ExceptionRaiser = proc;
}
__private_extern__
NXExceptionRaiser *NXGetExceptionRaiser (void)
{
return ExceptionRaiser;
}
__private_extern__
#if defined(__GNUC__)
#if !defined(__STRICT_ANSI__)
#if !defined(NeXT_PDO)
__volatile
#endif
#endif
#endif
void _NXRaiseError(int code, const void *data1, const void *data2)
{
(void)(*ExceptionRaiser)(code, data1, data2);
#if defined(WIN32)
(void)RaiseException(0xdead, EXCEPTION_NONCONTINUABLE, 0, NULL); #else
abort(); #endif
}
__private_extern__
void NXAllocErrorData(int size, void **data)
{
ErrorBuffer *buffer;
#if defined(KERNEL) || defined(__svr4__) || defined(hpux)
if (!ErrorDataLock) {
ErrorDataLock = LOCK_ALLOC(); }
#endif
buffer = malloc (sizeof (ErrorBuffer) + size);
*data = &buffer -> data;
LOCK (ErrorDataLock);
buffer->next = ErrorBufferChain;
ErrorBufferChain = buffer;
UNLOCK (ErrorDataLock);
}
__private_extern__
void NXResetErrorData(void)
{
ErrorBuffer *chain, *next;
#if defined(KERNEL) || defined(__svr4__) || defined(hpux)
if (!ErrorDataLock)
return;
#endif
LOCK (ErrorDataLock);
chain = ErrorBufferChain;
ErrorBufferChain = NULL;
UNLOCK (ErrorDataLock);
while (chain)
{
next = chain->next;
free (chain);
chain = next;
}
}