Annotation of objc/except.c, revision 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.