diff options
author | jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> | 1997-12-12 04:53:20 +0000 |
---|---|---|
committer | jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> | 1997-12-12 04:53:20 +0000 |
commit | 732992fad81a5d42283b07fd9442441acf685b5a (patch) | |
tree | b1e33498c494a6a7e60f2adbf6b766688bf20d7a /gcc/libgcc2.c | |
parent | b35797d55be1fdfacd475669c1c78ce9c74513db (diff) | |
download | gcc-732992fad81a5d42283b07fd9442441acf685b5a.tar.gz |
Thu Dec 11 20:42:18 1997 Teemu Torma <tot@trema.com>
Thread-safe EH support for pthreads, DCE threads and Solaris threads.
* integrate.c (expand_inline_function): If the inline fn uses eh
context, make sure that the current fn has one.
* toplev.c (rest_of_compilation): Call emit_eh_context.
* except.c (use_eh_context): New fn.
(get_eh_context_once): New fn.
(call_get_eh_context): New fn.
(emit_eh_context): New fn.
(get_eh_context): Call either get_eh_context_once or
call_get_eh_context, depending on what we have.
(get_dynamic_handler_chain): Call get_eh_context_once.
* except.h: Prototypes for fns above.
* optabs.c (get_eh_context_libfunc): Removed.
(init_optabs): Don't initialize it.
* expr.h (get_eh_context_libfunc): Removed.
* rtl.h, rtl.c: New reg_note REG_EH_CONTEXT.
* config/pa/pa.h (CPP_SPEC): Support for -threads.
* config/pa/pa-hpux10.h (LIB_SPEC): Ditto.
* config/pa/t-pa (MULTILIB_OPTIONS, MULTILIB_DIRNAMES):
New multilib for -threads.
* config/sparc/t-sol2: Added multilibs for -threads and
made -pthreads alias to it.
* config/sparc/sol2.h (CPP_SPEC, LIB_SPEC):
Added -threads and -pthreads options.
* libgcc-thr.h: New file.
* libgcc2.c: (__get_cpp_eh_context): Removed.
(struct cpp_eh_context): Removed.
(struct eh_context): Replaced cpp_eh_context with generic language
specific pointer.
(__get_eh_info): New function.
(__throw): Check eh_context::info.
(__sjthrow): Ditto.
* libgcc2.c: Include libgcc-thr.h.
(new_eh_context, __get_eh_context,
eh_pthread_initialize, eh_context_initialize, eh_context_static,
eh_context_specific, eh_context_free): New functions.
(get_eh_context, eh_context_key): New variables.
(__sjthrow, __sjpopnthrow, __eh_pcnthrow, __throw): Use
get_eh_context to get the context.
(longjmp): Move the declaration inside
#ifdef DONT_USE_BUILTIN_SETJMP.
* frame.c: Include libgcc-thr.h.
(object_mutex): Mutex to protect the object list.
(find_fde, __register_frame, __register_frame_table,
__deregister_frame): Hold the lock while accessing objects.
* except.h (get_eh_context): Declare.
* except.c (current_function_ehc): Define.
(current_function_dhc, current_function_dcc): Removed.
(get_eh_context): New function.
(get_dynamic_handler_chain): Use get_eh_context.
(get_saved_pc_ref): Ditto.
(get_dynamic_cleanup_chain): Removed references to
current_function_dcc.
(save_eh_status, restore_eh_status): Save and restore
current_function_ehc instead.
* optabs.c (get_eh_context_libfunc): New variable.
(init_optabs): Initialize it.
* expr.h: Declare get_eh_context_libfunc.
* function.h (struct function): Replaced dhc and dcc with ehc.
* except.c (get_saved_pc_ref): New functions.
(eh_saved_pc_rtx, eh_saved_pc): Deleted.
(expand_internal_throw_indirect): Use get_saved_pc_ref() instead
of eh_saved_pc.
(end_eh_unwinder): Likewise.
(init_eh): Remove initialization of eh_saved_pc.
* optabs.c (get_saved_pc_libfunc): New variable.
(init_optabs): Initialize it.
* expr.h: Declare get_saved_pc_libfunc.
* except.h (eh_saved_pc_rtx): Deleted.
(get_saved_pc_ref): Declared.
From Scott Snyder <snyder@d0sgif.fnal.gov>:
* libgcc2.c (__get_saved_pc): New.
(__eh_type, __eh_pc): Deleted.
(__eh_pcnthrow): Use __get_saved_pc() instead of __eh_pc.
(__get_dynamic_handler_chain): Move __dynamic_handler_chain inside
this fcn.
cp/:
Thu Dec 11 20:43:33 1997 Teemu Torma <tot@trema.com>
* decl.c (ptr_ptr_type_node): Define.
(init_decl_processing): Initialize it.
* cp-tree.h: Declare it.
* exception.cc (__cp_exception_info): Use __get_eh_info.
(__cp_push_exception): Ditto.
(__cp_pop_exception): Ditto.
From Scott Snyder <snyder@d0sgif.fnal.gov>:
* except.c (expand_builtin_throw): Use get_saved_pc_ref instead of
saved_pc.
(init_exception_processing): Removed saved_pc initialization.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@17052 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/libgcc2.c')
-rw-r--r-- | gcc/libgcc2.c | 206 |
1 files changed, 176 insertions, 30 deletions
diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c index ad51863e912..1ad63013a15 100644 --- a/gcc/libgcc2.c +++ b/gcc/libgcc2.c @@ -2962,11 +2962,9 @@ int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */ #ifdef L_eh -/* Shared exception handling support routines. */ +#include "libgcc-thr.h" -/* Language-specific information about the active exception(s). If there - are no active exceptions, it is set to 0. */ -void *__eh_info; +/* Shared exception handling support routines. */ void __default_terminate () @@ -2999,41 +2997,190 @@ __empty () { } +/* EH context structure. */ + +struct eh_context +{ + void **dynamic_handler_chain; + void *saved_pc; +#ifndef DWARF2_UNWIND_INFO + void *buf[2]; +#endif + /* This is language dependent part of the eh context. */ + void *info; +}; + +/* This is a safeguard for dynamic handler chain. */ + +static void *top_elt[2]; + +/* Allocate and return a new EH context structure. */ + +extern void __throw (); + +static void * +new_eh_context () +{ + struct eh_context *eh = (struct eh_context *) malloc (sizeof *eh); + if (! eh) + __terminate (); + + memset (eh, 0, sizeof *eh); + + eh->dynamic_handler_chain = top_elt; +#ifndef DWARF2_UNWIND_INFO + eh->buf[0] = &eh->saved_pc; + eh->buf[1] = &__throw; +#endif + + return eh; +} + +#if __GTHREADS +static __gthread_key_t eh_context_key; + +/* Destructor for struct eh_context. */ +static void +eh_context_free (void *ptr) +{ + if (ptr) + free (ptr); +} +#endif + +/* Pointer to function to return EH context. */ + +static struct eh_context *eh_context_initialize (); +static struct eh_context *eh_context_static (); +#if __GTHREADS +static struct eh_context *eh_context_specific (); +#endif + +static struct eh_context *(*get_eh_context) () = &eh_context_initialize; + +/* Routine to get EH context. + This one will simply call the function pointer. */ + +void * +__get_eh_context () +{ + return (void *) (*get_eh_context) (); +} + +/* Get and set the language specific info pointer. */ + +void ** +__get_eh_info () +{ + struct eh_context *eh = (*get_eh_context) (); + return (void **) &eh->info; +} + +#if __GTHREADS +static void +eh_threads_initialize () +{ + /* Try to create the key. If it fails, revert to static method, + otherwise start using thread specific EH contexts. */ + if (__gthread_key_create (&eh_context_key, &eh_context_free) == 0) + get_eh_context = &eh_context_specific; + else + get_eh_context = &eh_context_static; +} +#endif /* no __GTHREADS */ + +/* Initialize EH context. + This will be called only once, since we change GET_EH_CONTEXT + pointer to another routine. */ + +static struct eh_context * +eh_context_initialize () +{ +#if __GTHREADS + + static __gthread_once_t once = __GTHREAD_ONCE_INIT; + __gthread_once (&once, eh_threads_initialize); + +#else /* no __GTHREADS */ + + /* Use static version of EH context. */ + get_eh_context = &eh_context_static; + +#endif /* no __GTHREADS */ + + return (*get_eh_context) (); +} + +/* Return a static EH context. */ + +static struct eh_context * +eh_context_static () +{ + static struct eh_context *eh; + if (! eh) + eh = new_eh_context (); + return eh; +} + +#if __GTHREADS +/* Return a thread specific EH context. */ + +static struct eh_context * +eh_context_specific () +{ + struct eh_context *eh; + eh = (struct eh_context *) __gthread_getspecific (eh_context_key); + if (! eh) + { + eh = new_eh_context (); + if (__gthread_setspecific (eh_context_key, (void *) eh) != 0) + __terminate (); + } + + return eh; +} +#endif __GTHREADS + /* Support routines for setjmp/longjmp exception handling. */ /* Calls to __sjthrow are generated by the compiler when an exception is raised when using the setjmp/longjmp exception handling codegen method. */ +#ifdef DONT_USE_BUILTIN_SETJMP extern void longjmp (void *, int); - -static void *top_elt[2]; -void **__dynamic_handler_chain = top_elt; +#endif /* Routine to get the head of the current thread's dynamic handler chain - use for exception handling. - - TODO: make thread safe. */ + use for exception handling. */ void *** __get_dynamic_handler_chain () { - return &__dynamic_handler_chain; + struct eh_context *eh = (*get_eh_context) (); + return (void ***) &eh->dynamic_handler_chain; +} + +void ** +__get_saved_pc () +{ + struct eh_context *eh = (*get_eh_context) (); + return (void **) &eh->saved_pc; } /* This is used to throw an exception when the setjmp/longjmp codegen method is used for exception handling. - We call __terminate if there are no handlers left (we know this - when the dynamic handler chain is top_elt). Otherwise we run the - cleanup actions off the dynamic cleanup stack, and pop the top of - the dynamic handler chain, and use longjmp to transfer back to the - associated handler. */ + We call __terminate if there are no handlers left. Otherwise we run the + cleanup actions off the dynamic cleanup stack, and pop the top of the + dynamic handler chain, and use longjmp to transfer back to the associated + handler. */ void __sjthrow () { - void ***dhc = __get_dynamic_handler_chain (); + struct eh_context *eh = (*get_eh_context) (); + void ***dhc = &eh->dynamic_handler_chain; void *jmpbuf; void (*func)(void *, int); void *arg; @@ -3081,7 +3228,7 @@ __sjthrow () /* We must call terminate if we try and rethrow an exception, when there is no exception currently active and when there are no handlers left. */ - if (! __eh_info || (*dhc) == top_elt) + if (! eh->info || (*dhc) == top_elt) __terminate (); /* Find the jmpbuf associated with the top element of the dynamic @@ -3108,7 +3255,8 @@ __sjthrow () void __sjpopnthrow () { - void ***dhc = __get_dynamic_handler_chain (); + struct eh_context *eh = (*get_eh_context) (); + void ***dhc = &eh->dynamic_handler_chain; void *jmpbuf; void (*func)(void *, int); void *arg; @@ -3288,11 +3436,8 @@ __throw () /* See expand_builtin_throw for details. */ void **__eh_pcnthrow () { - static void *buf[2] = { - &__eh_pc, - &__throw - }; - return buf; + struct eh_context *eh = (*get_eh_context) (); + return &eh->buf[0]; } #if #machine(i386) @@ -3499,7 +3644,8 @@ in_reg_window (int reg, frame_state *udata) void __throw () { - void *pc, *handler, *retaddr, *__eh_pc; + struct eh_context *eh = (*get_eh_context) (); + void *saved_pc, *pc, *handler, *retaddr; frame_state ustruct, ustruct2; frame_state *udata = &ustruct; frame_state *sub_udata = &ustruct2; @@ -3509,7 +3655,7 @@ __throw () /* This is required for C++ semantics. We must call terminate if we try and rethrow an exception, when there is no exception currently active. */ - if (! __eh_info) + if (! eh->info) __terminate (); /* Start at our stack frame. */ @@ -3534,8 +3680,8 @@ label: __builtin_unwind_init (); /* Now reset pc to the right throw point. */ - __eh_pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1; - pc = __eh_pc; + pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1; + saved_pc = pc; handler = 0; for (;;) @@ -3567,7 +3713,7 @@ label: if (! handler) __terminate (); - if (pc == __eh_pc) + if (pc == saved_pc) /* We found a handler in the throw context, no need to unwind. */ udata = my_udata; else @@ -3582,7 +3728,7 @@ label: void *handler_pc = pc; /* Start from the throw context again. */ - pc = __eh_pc; + pc = saved_pc; memcpy (udata, my_udata, sizeof (*udata)); while (pc != handler_pc) |