Annotation of objc/except.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.0 (the 'License').  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License."
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: #ifdef SHLIB
                     25: #include "shlib.h"
                     26: #endif
                     27: /*
                     28:     except.c
                     29: 
                     30:     This file implements the exception raising scheme.
                     31:        It is thread safe, although Alt nodes may not behave
                     32:        as expected.
                     33: 
                     34:     Copyright (c) 1988, 1991 NeXT, Inc. as an unpublished work.
                     35:     All rights reserved.
                     36: */
                     37: 
                     38: #ifdef KERNEL
                     39: #import <mach/mach_types.h>
                     40: #import <kernserv/prototypes.h>
                     41: #else /* KERNEL */
                     42: #import <mach/cthreads.h>
                     43: #import <stdio.h>
                     44: #endif /* KERNEL */
                     45: 
                     46: #import "error.h"
                     47: #ifndef        KERNEL
                     48: #import <stdlib.h>
                     49: #endif
                     50: 
                     51: extern void _NXLogError (const char *format, ...);
                     52: 
                     53: #ifdef KERNEL
                     54: 
                     55: #import <mach/machine/simple_lock.h>
                     56: 
                     57: #ifdef hppa
                     58: #define SIMPLE_LOCK_INITIALIZER { 1, 1, 1, 1 }
                     59: #else
                     60: #define SIMPLE_LOCK_INITIALIZER { 1 }
                     61: #endif
                     62: 
                     63: #define LOCK_T                 simple_lock_data_t
                     64: #define LOCK_INITIALIZER SIMPLE_LOCK_INITIALIZER
                     65: #define LOCK(x)                        simple_lock(&(x))
                     66: #define UNLOCK(x)              simple_unlock(&(x))
                     67: 
                     68: #define cthread_t      thread_t
                     69: #define cthread_self() current_thread()
                     70: 
                     71: #else  /* KERNEL */
                     72: 
                     73: #define        LOCK_T                          struct mutex
                     74: #define LOCK_INITIALIZER       MUTEX_INITIALIZER
                     75: #define LOCK(x)                                mutex_lock(&x)
                     76: #define UNLOCK(x)                      mutex_unlock(&x)
                     77: 
                     78: #endif /* KERNEL */
                     79: 
                     80: #ifdef KERNEL
                     81: //int _setjmp(jmp_buf env) { return setjmp(env); }
                     82: //void _longjmp(jmp_buf env, int val) { longjmp(env, val); }
                     83: #define _setjmp(env) { return setjmp(env); }
                     84: #define _longjmp(env, val) { longjmp(env, val); }
                     85: 
                     86: NXUncaughtExceptionHandler *_NXUncaughtExceptionHandler;
                     87: 
                     88: #endif /* KERNEL */
                     89: 
                     90: typedef void AltProc(void *context, int code, const void *data1, const void *data2);
                     91: 
                     92: /*  These nodes represent handlers that are called as normal procedures
                     93:     instead of longjmp'ed to.  When these procs return, the next handler
                     94:     in the chain is processed.
                     95:  */
                     96: typedef struct {               /* an alternative node in the handler chain */
                     97:     struct _NXHandler *next;           /* ptr to next handler */
                     98:     AltProc *proc;                     /* proc to call */
                     99:     void *context;                     /* blind data for client */
                    100: } AltHandler;
                    101: 
                    102: static int ErrorBufferSize = 0;
                    103: static NXExceptionRaiser *ExceptionRaiser = &NXDefaultExceptionRaiser;
                    104: 
                    105:  /* Multiple thread support.
                    106:        Basic strategy is to collect globals into a struct; singly link them
                    107:        (probably not worth it put them in a hashtable) using the cthread id
                    108:        as a key.  Upon use, look up proper stack of handlers...
                    109:  */
                    110: 
                    111: typedef struct xxx {
                    112:        NXHandler *handlerStack;        /* start of handler chain */
                    113:        AltHandler *altHandlers;
                    114:        int altHandlersAlloced;
                    115:        int altHandlersUsed;
                    116:        cthread_t       thread;                 /* key */
                    117:        struct xxx      *next;                  /* link */
                    118: } ExceptionHandlerStack;
                    119: 
                    120: /* Allocate the handler stack for the first thread statically so that
                    121:    we don't keep an extra page in the heap hot (the libsys data is
                    122:    already hot).  Also statically allocate a small number of altHandlers.
                    123:    This should be the maximum typical depth of lockFocus'es. */
                    124: 
                    125: static AltHandler BaseAltHandlers[16] = { 0 };
                    126: 
                    127: static ExceptionHandlerStack Base =
                    128: {
                    129:   NULL,
                    130:   BaseAltHandlers,
                    131:   sizeof (BaseAltHandlers) / sizeof (BaseAltHandlers[0]),
                    132:   0,
                    133:   0,
                    134:   NULL
                    135: };
                    136: 
                    137: static LOCK_T Lock = LOCK_INITIALIZER;
                    138: 
                    139: #ifndef        KERNEL
                    140: static void _NXClearExceptionStack (void);
                    141: extern void _set_cthread_free_callout (void (*) (void));
                    142: #endif KERNEL
                    143: 
                    144: static ExceptionHandlerStack *addme (cthread_t self)
                    145: {
                    146:   ExceptionHandlerStack *stack;
                    147:   
                    148:   LOCK (Lock);                 // lookup is thread safe; addition isn't
                    149:   
                    150: #ifdef KERNEL
                    151:   for (stack = &Base; stack; stack = stack->next)
                    152:     if (stack->thread == 0) {
                    153:       stack->thread = self;
                    154:       UNLOCK (Lock);
                    155:       return stack;
                    156:     }
                    157: #else  KERNEL
                    158:   if (Base.thread == 0)                // try statically allocated stack
                    159:     {
                    160:       Base.thread = self;
                    161:       UNLOCK (Lock);
                    162:       return &Base;
                    163:     }
                    164:   
                    165:   /* Pass exception handler cleanup routine to cthread package.  */
                    166:   _set_cthread_free_callout (&_NXClearExceptionStack);
                    167: #endif KERNEL
                    168:   
                    169:   stack = calloc (sizeof (ExceptionHandlerStack), 1);
                    170:   stack->thread = self;
                    171:   stack->next = Base.next;
                    172:   Base.next = stack;           // insert atomically
                    173:   
                    174:   UNLOCK (Lock);
                    175:   
                    176:   return stack;
                    177: }
                    178: 
                    179: 
                    180: /*
                    181:        Get callers thread & find | allocate a stack.  Allocation is only
                    182:        proper for some usages, but we don't check for them...
                    183:        Also, these structs are not recovered upon thread death. XXX
                    184: */
                    185: static inline ExceptionHandlerStack *findme (void)
                    186: {
                    187:   ExceptionHandlerStack *stack;
                    188:   cthread_t self = cthread_self ();
                    189:   
                    190:   for (stack = &Base; stack; stack = stack->next)
                    191:     if (stack->thread == self)
                    192:       return stack;
                    193:   
                    194:   return addme (self);
                    195: }
                    196: 
                    197: #ifdef KERNEL
                    198: /*
                    199:  * Call back from thread_deallocate()
                    200:  * to indicate that a thread is being
                    201:  * destroyed.  Kernel thread ids aren't
                    202:  * reused the way that cthread ids are,
                    203:  * so we have to nuke the value in the
                    204:  * structure.
                    205:  *
                    206:  * XXX Should free data structures here.
                    207:  */
                    208: void
                    209: _threadFreeExceptionStack(
                    210:     thread_t           thread
                    211: )
                    212: {
                    213:   ExceptionHandlerStack *stack;
                    214: 
                    215:   // Don't allocate a stack for this thread if it doesn't already have one.
                    216:   for (stack = &Base; stack; stack = stack->next)
                    217:     if (stack->thread == thread)
                    218:       break;
                    219: 
                    220:   if (stack)
                    221:     {
                    222:       stack->handlerStack = 0;          // reset the handler chain
                    223:       stack->altHandlersUsed = 0;       // reset the alt handler count
                    224:       stack->thread = 0;
                    225:     }
                    226: }
                    227: #else  KERNEL          
                    228: /* cthreads will reuse a stack and a cthread_id.
                    229:  * We provide this call-in to clean up matters
                    230:  */
                    231: static void _NXClearExceptionStack (void)
                    232: {
                    233:   ExceptionHandlerStack *stack;
                    234:   cthread_t self = cthread_self ();
                    235:   
                    236:   // Don't allocate a stack for this thread if it doesn't already have one.
                    237:   for (stack = &Base; stack; stack = stack->next)
                    238:     if (stack->thread == self)
                    239:       break;
                    240: 
                    241:   if (stack)
                    242:     {
                    243:       stack->handlerStack = 0;          // reset the handler chain
                    244:       stack->altHandlersUsed = 0;       // reset the alt handler count
                    245:     }
                    246: }
                    247: #endif KERNEL
                    248: 
                    249: #define IS_ALT(ptr)                    ((int)(ptr) % 2)
                    250: #define NEXT_HANDLER(ptr)              \
                    251:        (IS_ALT(ptr) ? ALT_CODE_TO_PTR(ptr)->next : ((NXHandler *)ptr)->next)
                    252: #define ALT_PTR_TO_CODE(ptr)           (((ptr) - me->altHandlers) * 2 + 1)
                    253: #define ALT_CODE_TO_PTR(code)          (me->altHandlers + ((int)(code) - 1) / 2)
                    254: 
                    255: 
                    256: /* if the node passed in isnt on top of the stack, something's fishy */
                    257: 
                    258: static void trickyRemoveHandler (NXHandler *handler, int removingAlt)
                    259: {
                    260:   AltHandler *altNode;
                    261:   NXHandler *node;
                    262:   NXHandler **nodePtr;
                    263:   ExceptionHandlerStack *me = findme ();
                    264:   
                    265:   /* try to find the node anywhere on the stack */
                    266:   node = me->handlerStack;
                    267:   while (node != handler && node)
                    268:     {
                    269:       /* Watch for attempts to remove handlers which are outside the
                    270:         active portion of the stack.  This happens when you return
                    271:         from an NX_DURING context without removing the handler.
                    272:         This code assumes the stack grows downward. */
                    273: #if hppa
                    274:        /* stack grows upward */
                    275:       if (IS_ALT (node) || (void *) node < (void *) &altNode)
                    276:        node = NEXT_HANDLER (node);
                    277:       else
                    278: #else
                    279:       if (IS_ALT (node) || (void *) node > (void *) &altNode)
                    280:        node = NEXT_HANDLER (node);
                    281:       else
                    282: #endif
                    283:        {
                    284:          _NXLogError ("Exception handlers were not properly removed.");
                    285:          abort ();
                    286:        }
                    287:     }
                    288:   
                    289:   if (node)
                    290:     {
                    291:       /* 
                    292:       * Clean off the stack up to the out of place node.  If we are trying
                    293:       * to remove an non-alt handler, we pop eveything off the stack
                    294:       * including that handler, calling any alt procs along the way.  If
                    295:       * we are removing an alt handler, we leave all the non-alt handlers
                    296:       * alone as we clean off the stack, but pop off all the alt handlers
                    297:       * we find, including the node we were asked to remove.
                    298:       */
                    299:       if (!removingAlt)
                    300:        _NXLogError ("Exception handlers were not properly removed.");
                    301:       
                    302:       nodePtr = &me->handlerStack;
                    303:       do
                    304:        {
                    305:          node = *nodePtr;
                    306:          if (IS_ALT(node))
                    307:            {
                    308:              altNode = ALT_CODE_TO_PTR(node);
                    309:              if (removingAlt)
                    310:                {
                    311:                  if (node == handler)
                    312:                    *nodePtr = altNode->next;   /* del matching node */
                    313:                  else
                    314:                    nodePtr = &altNode->next;   /* skip node */
                    315:                }
                    316:              else
                    317:                {
                    318:                  if (node != handler)
                    319:                    (*altNode->proc)(altNode->context, 1, 0, 0);
                    320:                  me->altHandlersUsed = altNode - me->altHandlers;
                    321:                  *nodePtr = altNode->next;     /* del any alt node */
                    322:                }
                    323:            }
                    324:          else
                    325:            {
                    326:              if (removingAlt)
                    327:                nodePtr = &node->next;          /* skip node */
                    328:              else
                    329:                *nodePtr = node->next;          /* nuke non-alt node */
                    330:            }
                    331:        }
                    332:       while (node != handler);
                    333:     }
                    334:   else
                    335:     {
                    336: #ifdef KERNEL
                    337:       ;
                    338: #else /* KERNEL */
                    339:       _NXLogError ("Attempt to remove unrecognized exception handler.");
                    340: #endif /* KERNEL */
                    341:     }
                    342: }
                    343: 
                    344: 
                    345: NXHandler *_NXAddAltHandler (AltProc *proc, void *context)
                    346: {
                    347:   AltHandler *new;
                    348:   ExceptionHandlerStack *me = findme ();
                    349: 
                    350:   if (me->altHandlersUsed == me->altHandlersAlloced)
                    351:     {
                    352:       if (me->altHandlers == BaseAltHandlers)
                    353:        {
                    354:          me->altHandlers = malloc (++me->altHandlersAlloced *
                    355:                                    sizeof(AltHandler));
                    356:          bcopy (BaseAltHandlers, me->altHandlers, sizeof (BaseAltHandlers));
                    357:        }
                    358:       else
                    359:        me->altHandlers = realloc (me->altHandlers, ++me->altHandlersAlloced *
                    360:                                                    sizeof(AltHandler));
                    361:     }
                    362:   
                    363:   new = me->altHandlers + me->altHandlersUsed++;
                    364:   new->next = me->handlerStack;
                    365:   me->handlerStack = (NXHandler *) ALT_PTR_TO_CODE (new);
                    366:   new->proc = proc;
                    367:   new->context = context;
                    368:   return me->handlerStack;
                    369: }
                    370: 
                    371: 
                    372: void _NXRemoveAltHandler (NXHandler *handler)
                    373: {
                    374:   ExceptionHandlerStack *me;
                    375:   
                    376:   for (me = &Base; me; me = me->next)
                    377:     if (me->handlerStack == handler)
                    378:       {
                    379:        AltHandler *altNode = ALT_CODE_TO_PTR (handler);
                    380:        
                    381:        me->altHandlersUsed = altNode - me->altHandlers;
                    382:        me->handlerStack = altNode->next;
                    383:        return;
                    384:       }
                    385:   
                    386:   trickyRemoveHandler (handler, TRUE);
                    387: }
                    388: 
                    389: 
                    390: void _NXAddHandler (NXHandler *handler)
                    391: {
                    392:   ExceptionHandlerStack *me = findme ();
                    393:   
                    394:   handler->next = me->handlerStack;
                    395:   me->handlerStack = handler;
                    396:   handler->code = 0;
                    397: }
                    398: 
                    399: 
                    400: void _NXRemoveHandler (NXHandler *handler)
                    401: {
                    402:   ExceptionHandlerStack *me;
                    403:   
                    404:   for (me = &Base; me; me = me->next)
                    405:     if (me->handlerStack == handler)
                    406:       {
                    407:         me->handlerStack = me->handlerStack->next;
                    408:        return;
                    409:       }
                    410:   
                    411:   trickyRemoveHandler (handler, FALSE);
                    412: }
                    413: 
                    414: 
                    415: void NXSetExceptionRaiser(NXExceptionRaiser *proc)
                    416: {
                    417:     ExceptionRaiser = proc;
                    418: }
                    419: 
                    420: 
                    421: NXExceptionRaiser *NXGetExceptionRaiser (void)
                    422: {
                    423:     return ExceptionRaiser;
                    424: }
                    425: 
                    426: volatile void _NXRaiseError(int code, const void *data1, const void *data2)
                    427: {
                    428:     (*ExceptionRaiser)(code, data1, data2);
                    429:     abort ();  /* we should never get here! */
                    430: }
                    431: 
                    432: 
                    433: /* forwards the error to the next handler */
                    434: volatile void NXDefaultExceptionRaiser(int code, const void *data1, const void *data2)
                    435: {
                    436:     NXHandler *destination;
                    437:     AltHandler *altDest;
                    438:        ExceptionHandlerStack *me = findme ();
                    439: 
                    440:     while (1) {
                    441:                destination = me->handlerStack;
                    442:                if (!destination) {
                    443:                        if (_NXUncaughtExceptionHandler)
                    444:                                (*_NXUncaughtExceptionHandler)(code, data1, data2);
                    445:                        else {
                    446: #ifndef KERNEL
                    447:                                        _NXLogError("Uncaught exception #%d\n", code);
                    448: #endif /* not KERNEL */
                    449:                        }
                    450: #ifdef KERNEL
                    451:                                panic("Uncaught exception");
                    452: #else /* KERNEL */
                    453:                                exit(-1);
                    454: #endif /* KERNEL */
                    455:                } else if (IS_ALT(destination)) {
                    456:                        altDest = ALT_CODE_TO_PTR(destination);
                    457:                        me->handlerStack = altDest->next;
                    458:                        me->altHandlersUsed = altDest - me->altHandlers;
                    459:                        (*altDest->proc)(altDest->context, code, data1, data2);
                    460:                } else {
                    461:                        destination->code = code;
                    462:                        destination->data1 = data1;
                    463:                        destination->data2 = data2;
                    464:                        me->handlerStack = destination->next;
                    465:                        _longjmp(destination->jumpState, 1);
                    466:                }
                    467:     }
                    468: }
                    469: 
                    470: 
                    471: static char *ErrorBuffer = NULL;
                    472: static int ErrorBufferOffset = 0;
                    473: 
                    474: /* stack allocates some space from the error buffer */
                    475: void NXAllocErrorData(int size, void **data)
                    476: {
                    477:     int goalSize;
                    478:        static LOCK_T mylock = LOCK_INITIALIZER;
                    479:        
                    480:        LOCK (mylock);
                    481:     goalSize = (ErrorBufferOffset + size + 7) & ~7;
                    482:     if (goalSize > ErrorBufferSize) {
                    483:                ErrorBuffer = realloc(ErrorBuffer, (unsigned)goalSize);
                    484:                ErrorBufferSize = goalSize;
                    485:     }
                    486:     *data = ErrorBuffer + ErrorBufferOffset;
                    487:     ErrorBufferOffset = goalSize;
                    488:        UNLOCK (mylock);
                    489: }
                    490: 
                    491: 
                    492: void NXResetErrorData(void)
                    493: {
                    494:     ErrorBufferOffset = 0;             // multiple threads users must cooperate XXX
                    495: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.