summaryrefslogtreecommitdiff
path: root/gcc/libgcc2.c
diff options
context:
space:
mode:
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>1997-12-12 04:53:20 +0000
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>1997-12-12 04:53:20 +0000
commit732992fad81a5d42283b07fd9442441acf685b5a (patch)
treeb1e33498c494a6a7e60f2adbf6b766688bf20d7a /gcc/libgcc2.c
parentb35797d55be1fdfacd475669c1c78ce9c74513db (diff)
downloadgcc-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.c206
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)