public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: MT safe exception diffs
       [not found] <199709291121.NAA11557.cygnus.egcs@baht.labs.trema.com>
@ 1997-09-30  0:26 ` Jason Merrill
  1997-09-30  0:43   ` Teemu Torma
  0 siblings, 1 reply; 6+ messages in thread
From: Jason Merrill @ 1997-09-30  0:26 UTC (permalink / raw)
  To: Teemu Torma; +Cc: egcs

Thanks.  A few comments:

The thread handling stuff needs to be independent of the EH code.  The EH
code should use a single interface to the various threads packages, and
the Objective-C frontend should use the same interface.  The current objc
thread code will probably be useful as a starting point.

eh_context::top_elt doesn't need to be thread-specific, as it is only used
as a null value.  For that matter, I don't know why we don't just use 0.
Mike?

eh_context::buf should be #ifndef DWARF2_UNWIND_INFO.

It would be nice, though certainly not necessary, to get support for nested
exceptions at the same time as thread safety.  The upshot will be that
instead of information for a single active exception you have a stack of them.

Jason

^ permalink raw reply	[flat|nested] 6+ messages in thread

* MT safe exception diffs
  1997-09-30  0:26 ` MT safe exception diffs Jason Merrill
@ 1997-09-30  0:43   ` Teemu Torma
  1997-10-07 22:59     ` Jason Merrill
  0 siblings, 1 reply; 6+ messages in thread
From: Teemu Torma @ 1997-09-30  0:43 UTC (permalink / raw)
  To: Jason Merrill; +Cc: egcs

    From:  Jason Merrill <jason@cygnus.com>
    Date:  30 Sep 1997 00:25:46 -0700

    The thread handling stuff needs to be independent of the EH code.  The EH
    code should use a single interface to the various threads packages, and
    the Objective-C frontend should use the same interface.  The current objc
    thread code will probably be useful as a starting point.

It would be nice, but in the case of sjlj-exceptions, EH context 
is needed even if nothing is thrown.  Adding few instructions more
makes it just slower.
    
Teemu


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: MT safe exception diffs
  1997-09-30  0:43   ` Teemu Torma
@ 1997-10-07 22:59     ` Jason Merrill
  0 siblings, 0 replies; 6+ messages in thread
From: Jason Merrill @ 1997-10-07 22:59 UTC (permalink / raw)
  To: Teemu Torma; +Cc: egcs

>>>>> Teemu Torma <tot@Trema.COM> writes:

>     From:  Jason Merrill <jason@cygnus.com>
>     Date:  30 Sep 1997 00:25:46 -0700

>     The thread handling stuff needs to be independent of the EH code.  The EH
>     code should use a single interface to the various threads packages, and
>     the Objective-C frontend should use the same interface.  The current objc
>     thread code will probably be useful as a starting point.

> It would be nice, but in the case of sjlj-exceptions, EH context 
> is needed even if nothing is thrown.  Adding few instructions more
> makes it just slower.
    
Then make them inline.

Jason

^ permalink raw reply	[flat|nested] 6+ messages in thread

* MT safe exception diffs
  1997-09-29  6:38 ` John Carr
@ 1997-09-29  7:43   ` Teemu Torma
  0 siblings, 0 replies; 6+ messages in thread
From: Teemu Torma @ 1997-09-29  7:43 UTC (permalink / raw)
  To: John Carr; +Cc: egcs

    From:  John Carr <jfc@MIT.EDU>
    Date:  Mon, 29 Sep 1997 09:38:18 EDT

    You only need one version of the exception library: Solaris threads
    and pthreads are compatible.  If libgcc uses threads and the program
    uses pthreads it will still work.  If you want to support Solaris 2.4
    you should use -lthreads in libgcc, otherwise use the one that has the
    features you want.
    
I am aware of that, but I implemented both ones to be able to test 
the pthreads interface.  

Teemu


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: MT safe exception diffs
  1997-09-29  4:22 Teemu Torma
@ 1997-09-29  6:38 ` John Carr
  1997-09-29  7:43   ` Teemu Torma
  0 siblings, 1 reply; 6+ messages in thread
From: John Carr @ 1997-09-29  6:38 UTC (permalink / raw)
  To: Teemu Torma; +Cc: egcs

> With these changes gcc is built on Solaris to use multilibs to
> compile both Solaris threads and pthreads versions of libgcc.

You only need one version of the exception library: Solaris threads
and pthreads are compatible.  If libgcc uses threads and the program
uses pthreads it will still work.  If you want to support Solaris 2.4
you should use -lthreads in libgcc, otherwise use the one that has the
features you want.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* MT safe exception diffs
@ 1997-09-29  4:22 Teemu Torma
  1997-09-29  6:38 ` John Carr
  0 siblings, 1 reply; 6+ messages in thread
From: Teemu Torma @ 1997-09-29  4:22 UTC (permalink / raw)
  To: egcs

Here are diffs against 970924 to implement -threads and -pthreads
options to get MT safe exceptions.  The diffs include Scott Snyder's
changes, since they do not apply cleanly to current snapshots.

I have tested this only on SPARC Solaris 2.5.1, with both libthread
and libpthread, with both sjlj-exceptions and drawf2-unwinding
exceptions, and all stress-testing seems to work just fine.

With these changes gcc is built on Solaris to use multilibs to
compile both Solaris threads and pthreads versions of libgcc.  I do
not know whether this is the most agreeable implementation, and as you
can see from the diffs that I tried also another approach where libgcc
contains dummy implementations of needed thread routines.  It works
nicely, but it is not possible to have LIB_SPEC to include threads
libraries, since libgcc is linked before LIB_SPEC.  To make this 
practical, there should be some other stubs library that is linked very
last.  Nice thing with this is that if one links with threads
libraries, it uses MT safe exceptions, otherwise not.  

Teemu

gcc/ChangeLog:

1997-09-29  Teemu Torma  <tot@trema.com>

	* config/sparc/t-sol2: Added multilibs for -threads and
	-pthreads. 
		
	* config/sparc/sol2.h (CPP_SPEC, LIB_SPEC):
	Added -threads and -pthreads options.

	* config/sparc/sol2.h: Added disabled definitions for
	_SOLARIS_THREADS and NEED_THREAD_STUBS.

1997-09-26  Teemu Torma  <tot@trema.com>

	* Makefile.in (LIB2FUNCS): Added _eh_mt_stubs.
		
	* libgcc2.c: Revised thread support for pthreads and Solaris
	threads.

	* libgcc2.c (new_eh_context, __get_eh_context,
	eh_pthread_initialize, eh_context_initialize, eh_context_static,
	eh_context_per_thread, 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.

	(pthread_key_create, pthread_setspecific,
	pthread_getspecific, pthread_once,
	thr_keycreate, thr_setspecific, thr_getspecific):
	New dummy functions to be compiled with -Deh_mt_stubs
	if NEED_THREAD_STUBS is defined.
		
	* except.c (get_dynamic_handler_chain): Use get_eh_context_libfunc
	to get EH context.
	(get_saved_pc_ref): Likewise.
	* optabs.c (get_eh_context_libfunc): New variable.
	(init_optabs): Initialize it.
	* expr.h: Declare get_eh_context_libfunc.

Thu Sep 11 17:13:11 1997  scott snyder  <snyder@d0sgif.fnal.gov>

	* libgcc2.c: Add pthread support for exceptions.

	* libgcc2.c (cpp_eh_context, __get_cpp_eh_context,
	__get_saved_pc): New.
	(__eh_type, __eh_pc): Deleted.
	(__sjthrow): Use __get_cpp_eh_context()->type instead of
	__eh_type.
	(__eh_pcnthrow): Use __get_saved_pc() instead of __eh_pc.
	(__get_dynamic_handler_chain): Move __dynamic_handler_chain inside
	this fcn.

	* 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.
 
gcc/cp/ChangeLog:

Thu Sep 11 17:14:24 1997  scott snyder  <snyder@d0sgif.fnal.gov>

	* exception.cc (uncaught_exception): Use __get_cpp_eh_context()
	instead of __eh_type and __eh_in_catch.

        * except.c (saved_in_catch, saved_cleanup, saved_throw_value,
	saved_throw_type): Deleted.
	(init_exception_processing): Remove their initializations.
	Initialize GetCPPEHContextRef and PFV_type_node.
	(GetCPPEHContextRef, PFV_type_nodebuild_saved_in_catch,
	build_saved_cleanup, build_saved_throw_value,
	build_saved_throw_type): New.
	(push_eh_cleanup): Use build_saved_* instead of saved_*.
	(expand_start_catch_block): Likewise.
	(expand_builtin_throw): Likewise.
	(expand_end_eh_spec): Likewise.
	(expand_throw): Likewise.


Index: Makefile.in
===================================================================
RCS file: /trema/cvs/gnu/egcs/gcc/Makefile.in,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -u -r1.1.1.1 -r1.2
--- Makefile.in	1997/09/26 09:56:45	1.1.1.1
+++ Makefile.in	1997/09/26 15:43:08	1.2
@@ -630,7 +630,7 @@
     _fixtfdi _fixunstfdi _floatditf \
     __gcc_bcmp _varargs __dummy _eprintf _op_new _op_vnew _new_handler \
     _op_delete _op_vdel _bb _shtab _clear_cache _trampoline __main _exit \
-    _ctors _eh  _pure
+    _ctors _eh _eh_mt_stubs _pure
 
 # The files that "belong" in CONFIG_H are deliberately omitted
 # because having them there would not be useful in actual practice.
Index: except.c
===================================================================
RCS file: /trema/cvs/gnu/egcs/gcc/except.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -u -r1.1.1.1 -r1.2
--- except.c	1997/09/26 09:56:55	1.1.1.1
+++ except.c	1997/09/26 15:43:09	1.2
@@ -498,11 +498,6 @@
 
 struct label_node *false_label_stack = NULL;
 
-/* The rtx and the tree for the saved PC value.  */
-
-rtx eh_saved_pc_rtx;
-tree eh_saved_pc;
-
 rtx expand_builtin_return_addr	PROTO((enum built_in_function, int, rtx));
 \f
 /* Various support routines to manipulate the various data structures
@@ -754,10 +749,14 @@
       emit_insns_before (insns, get_first_nonparm_insn ());
     }
 #else
+  rtx ehc;
   rtx dhc;
-  dhc = emit_library_call_value (get_dynamic_handler_chain_libfunc,
+
+  ehc = emit_library_call_value (get_eh_context_libfunc,
 				 NULL_RTX, 1,
 				 Pmode, 0);
+  /* dhc is at the beginnig of the returned structure. */
+  dhc = ehc;
   current_function_dhc = copy_to_reg (dhc);
 #endif
 
@@ -785,6 +784,27 @@
   return gen_rtx (MEM, Pmode, current_function_dcc);
 }
 
+/* Get a reference to the saved_pc variable.
+
+   FIXME: When get_dynamic_handler_chain() is fixed to only make the libcall
+          once per function, this should be fixed in the same way. */
+
+rtx
+get_saved_pc_ref ()
+{
+  rtx ehc, ehpc, current_function_ehpc;
+
+  /* Saved PC is the second word into the returned structure. */
+  ehc = emit_library_call_value (get_eh_context_libfunc,
+				 NULL_RTX, 1,
+				 Pmode, 0);
+  ehpc = plus_constant (ehc, GET_MODE_SIZE (Pmode));
+  current_function_ehpc = copy_to_reg (ehpc);
+
+  /* We don't want a copy of the ehpc, but rather, the single ehpc.  */
+  return gen_rtx (MEM, Pmode, current_function_ehpc);
+}
+
 /* Generate code to evaluate X and jump to LABEL if the value is nonzero.
    LABEL is an rtx of code CODE_LABEL, in this function.  */
 
@@ -1162,8 +1182,7 @@
 expand_internal_throw_indirect (context)
      rtx context;
 {
-  assemble_external (eh_saved_pc);
-  emit_move_insn (eh_saved_pc_rtx, context);
+  emit_move_insn (get_saved_pc_ref (), context);
   emit_throw ();
 }
 
@@ -1651,8 +1670,6 @@
   return;
 #else /* DWARF2_UNWIND_INFO */
 
-  assemble_external (eh_saved_pc);
-
   expr = make_node (RTL_EXPR);
   TREE_TYPE (expr) = void_type_node;
   RTL_EXPR_RTL (expr) = const0_rtx;
@@ -1670,7 +1687,7 @@
   return_val_rtx = eh_outer_context (return_val_rtx);
   return_val_rtx = expand_binop (Pmode, sub_optab, return_val_rtx, GEN_INT (1),
 				 NULL_RTX, 0, OPTAB_LIB_WIDEN);
-  emit_move_insn (eh_saved_pc_rtx, return_val_rtx);
+  emit_move_insn (get_saved_pc_ref (), return_val_rtx);
   
   /* Either set things up so we do a return directly to __throw, or
      we return here instead.  */
@@ -1928,12 +1945,6 @@
   /* Generate rtl to reference the variable in which the PC of the
      current context is saved.  */
   tree type = build_pointer_type (make_node (VOID_TYPE));
-
-  eh_saved_pc = build_decl (VAR_DECL, get_identifier ("__eh_pc"), type);
-  DECL_EXTERNAL (eh_saved_pc) = 1;
-  TREE_PUBLIC (eh_saved_pc) = 1;
-  make_decl_rtl (eh_saved_pc, NULL_PTR, 1);
-  eh_saved_pc_rtx = DECL_RTL (eh_saved_pc);
 }
 
 /* Initialize the per-function EH information.  */
Index: except.h
===================================================================
RCS file: /trema/cvs/gnu/egcs/gcc/except.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -u -r1.1.1.1 -r1.2
--- except.h	1997/09/26 09:56:55	1.1.1.1
+++ except.h	1997/09/26 15:43:09	1.2
@@ -246,10 +246,6 @@
 
 extern rtx exception_handler_labels;
 
-/* The rtx for the saved PC value.  */
-
-extern rtx eh_saved_pc_rtx;
-
 /* Performs optimizations for exception handling, such as removing
    unnecessary exception regions. Invoked from jump_optimize ().  */
 
@@ -260,6 +256,9 @@
 
 /* Get the dynamic cleanup chain.  */
 extern rtx get_dynamic_cleanup_chain		PROTO((void));
+
+/* Get the saved PC variable. */
+extern rtx get_saved_pc_ref			PROTO((void));
 
 /* Throw an exception.  */
 
Index: expr.h
===================================================================
RCS file: /trema/cvs/gnu/egcs/gcc/expr.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -u -r1.1.1.1 -r1.2
--- expr.h	1997/09/26 09:56:56	1.1.1.1
+++ expr.h	1997/09/26 15:43:10	1.2
@@ -417,6 +417,8 @@
 extern rtx setjmp_libfunc;
 extern rtx longjmp_libfunc;
 extern rtx get_dynamic_handler_chain_libfunc;
+extern rtx get_saved_pc_libfunc;
+extern rtx get_eh_context_libfunc;
 
 extern rtx eqhf2_libfunc;
 extern rtx nehf2_libfunc;
Index: libgcc2.c
===================================================================
RCS file: /trema/cvs/gnu/egcs/gcc/libgcc2.c,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -u -r1.1.1.1 -r1.3
--- libgcc2.c	1997/09/26 09:57:03	1.1.1.1
+++ libgcc2.c	1997/09/29 08:41:56	1.3
@@ -3109,8 +3109,6 @@
 
 /* Shared exception handling support routines.  */
 
-extern void *__eh_type;
-
 void
 __default_terminate ()
 {
@@ -3142,6 +3140,212 @@
 {
 }
 \f
+/* EH context structures. */
+
+struct cpp_eh_context
+{
+  void *type;
+  void *value;
+  void  (*cleanup) ();
+  int   in_catch;
+};
+
+struct eh_context
+{
+  void **dynamic_handler_chain;
+  void *saved_pc;
+  void *buf[2];
+  struct cpp_eh_context cpp;
+  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 = eh->top_elt;
+  eh->buf[0] = &eh->saved_pc;
+  eh->buf[1] = &__throw;
+  
+  return eh;
+}
+
+/* Pointer to function to return EH context. */
+
+static struct eh_context *eh_context_initialize ();
+static struct eh_context *eh_context_static ();
+static struct eh_context *eh_context_per_thread ();
+
+static struct eh_context *(*get_eh_context) () = &eh_context_initialize;
+
+/* Thread specific key to get EH context. */
+#if _PTHREADS
+
+#include <pthread.h>
+
+static pthread_key_t eh_context_key;
+
+/* Destructor for struct eh_context. */
+static void
+eh_context_free (void *ptr)
+{
+  if (ptr)
+    free (ptr);
+}
+#else /* not _PTHREADS */
+#if _SOLARIS_THREADS
+
+#include <thread.h>
+
+static thread_key_t eh_context_key;
+
+/* Destructor for struct eh_context. */
+static void
+eh_context_free (void *ptr)
+{
+  if (ptr)
+    free (ptr);
+}
+#endif /* _SOLARIS_THREADS */
+#endif /* _PTHREADS */
+
+/* Routine to get EH context.
+   This one will simply call the function pointer. */
+
+void *
+__get_eh_context ()
+{
+  return (void *) (*get_eh_context) ();
+}
+
+void *
+__get_cpp_eh_context ()
+{
+  struct eh_context *eh = (*get_eh_context) ();
+  return (void *) &eh->cpp;
+}
+\f
+#if _PTHREADS
+static void
+eh_pthread_initialize ()
+{
+  /* Try to create the key.  If it fails, revert to static method,
+     otherwise start using thread specific EH contexts. */
+  if (pthread_key_create (&eh_context_key, &eh_context_free) == 0)
+    get_eh_context = &eh_context_per_thread;
+  else
+    get_eh_context = &eh_context_static;
+}
+#endif
+
+/* 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 _PTHREADS
+
+  static pthread_once_t initialized = PTHREAD_ONCE_INIT;
+  pthread_once (&initialized, eh_pthread_initialize);
+
+#else /* not _PTHREADS */
+#if _SOLARIS_THREADS
+
+  /* Mutex to make sure that we do not get initialized twice.
+     There is no need to call mutex_init; we do not need
+     inter-process mutex. */
+  static mutex_t mutex;
+  mutex_lock (&mutex);
+
+  /* Verify that get_eh_context still points to us; another thread
+     may already have changed it. */
+  if (get_eh_context == &eh_context_initialize)
+    {
+      /* Try to create the key.  If it fails, revert to static method,
+	 otherwise start using thread specific EH contexts. */
+      if (thr_keycreate (&eh_context_key, &eh_context_free) == 0)
+	get_eh_context = &eh_context_per_thread;
+      else 
+	get_eh_context = &eh_context_static;
+    }
+  mutex_unlock (&mutex);
+
+#else /* not _SOLARIS_THREADS */
+
+  /* Use static version of EH context. */
+  get_eh_context = &eh_context_static;
+
+#endif /* not _SOLARIS_THREADS */
+#endif /* not _PTHREADS */
+
+  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;
+}
+
+/* Return a thread specific EH context. */
+
+static struct eh_context *
+eh_context_per_thread ()
+{
+  struct eh_context *eh;
+
+#if _PTHREADS
+
+  eh = (struct eh_context *) pthread_getspecific (eh_context_key);
+  if (! eh)
+    {
+      eh = new_eh_context ();
+      if (pthread_setspecific (eh_context_key, (void *) eh) != 0)
+	__terminate ();
+    }
+
+#else /* not _PTHREADS */
+#if _SOLARIS_THREADS
+
+  {
+    void *eh_ptr;
+    if (thr_getspecific (eh_context_key, &eh_ptr) != 0)
+      __terminate ();
+    eh = (struct eh_context *) eh_ptr;
+    if (! eh)
+      {
+	eh = new_eh_context ();
+	if (thr_setspecific (eh_context_key, (void *) eh) != 0)
+	  __terminate ();
+      }
+  }
+
+#else /* not _SOLARIS_THREADS */
+
+  __terminate ();
+
+#endif /* not _SOLARIS_THREADS */
+#endif /* not _PTHREADS */
+
+  return eh;
+}
+\f
 /* Support routines for setjmp/longjmp exception handling.  */
 
 /* Calls to __sjthrow are generated by the compiler when an exception
@@ -3150,18 +3354,21 @@
 
 extern void longjmp (void *, int);
 
-static void *top_elt[2];
-void **__dynamic_handler_chain = top_elt;
-
 /* 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
@@ -3176,7 +3383,8 @@
 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;
@@ -3224,7 +3432,7 @@
   /* 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_type || (*dhc) == top_elt)
+  if (! eh->cpp.type || (*dhc) == eh->top_elt)
     __terminate ();
     
   /* Find the jmpbuf associated with the top element of the dynamic
@@ -3251,7 +3459,8 @@
 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;
@@ -3307,8 +3516,6 @@
 /* This value identifies the place from which an exception is being
    thrown.  */
 
-extern void *__eh_pc;
-
 #ifdef EH_TABLE_LOOKUP
 
 EH_TABLE_LOOKUP
@@ -3431,11 +3638,8 @@
 /* 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)
@@ -3626,6 +3830,7 @@
 void
 __throw ()
 {
+  struct eh_context *eh = (*get_eh_context) ();
   void *pc, *handler, *retaddr;
   frame_state ustruct, ustruct2;
   frame_state *udata = &ustruct;
@@ -3636,7 +3841,7 @@
   /* 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_type)
+  if (! eh->cpp.type)
     __terminate ();
     
   /* Start at our stack frame.  */
@@ -3661,7 +3866,7 @@
   __builtin_unwind_init ();
 
   /* Now reset pc to the right throw point.  */
-  pc = __eh_pc;
+  pc = eh->saved_pc;
 
   for (;;)
     { 
@@ -3692,7 +3897,7 @@
   if (! handler)
     __terminate ();
 
-  if (pc == __eh_pc)
+  if (pc == eh->saved_pc)
     /* We found a handler in the throw context, no need to unwind.  */
     udata = my_udata;
   else
@@ -3707,7 +3912,7 @@
       void *handler_pc = pc;
 
       /* Start from the throw context again.  */
-      pc = __eh_pc;
+      pc = eh->saved_pc;
       memcpy (udata, my_udata, sizeof (*udata));
 
       while (pc != handler_pc)
@@ -3779,6 +3984,69 @@
 #endif /* !DWARF2_UNWIND_INFO */
 
 #endif /* L_eh */
+\f
+#ifdef L_eh_mt_stubs
+#if NEED_THREAD_STUBS
+
+/* Create emty stub subroutines that are normally in MT libraries. */
+
+#if _PTHREADS
+
+#include <pthread.h>
+
+int
+pthread_key_create (pthread_key_t *keyp, void (*dtor) (void *))
+{
+  return -1;
+}
+
+int
+pthread_setspecific (pthread_key_t key, const void *value)
+{
+  return -1;
+}
+
+void *
+pthread_getspecific (pthread_key_t key)
+{
+  return 0;
+}
+
+int
+pthread_once (pthread_once_t *once, void (*func) ())
+{
+  /* Just call the function, it is enough for EH initialization
+     purposes. */
+  (*func) ();
+  return -1;
+}
+#else /* not _PTHREADS */
+#if _SOLARIS_THREADS
+
+#include <thread.h>
+
+int
+thr_keycreate (thread_key_t *keyp, void (*dtor) (void *))
+{
+  return -1;
+}
+
+int
+thr_setspecific (thread_key_t key, void *value)
+{
+  return -1;
+}
+
+int
+thr_getspecific (thread_key_t key, void **valuep)
+{
+  return -1;
+}
+#endif /* _SOLARIS_THREADS */
+#endif /* not _PTHREADS */
+
+#endif /* NEED_THREAD_STUBS */
+#endif /* L_eh_mt_stubs */
 \f
 #ifdef L_pure
 #ifndef inhibit_libc
Index: optabs.c
===================================================================
RCS file: /trema/cvs/gnu/egcs/gcc/optabs.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -u -r1.1.1.1 -r1.2
--- optabs.c	1997/09/26 09:57:06	1.1.1.1
+++ optabs.c	1997/09/26 15:43:12	1.2
@@ -125,6 +125,8 @@
 rtx setjmp_libfunc;
 rtx longjmp_libfunc;
 rtx get_dynamic_handler_chain_libfunc;
+rtx get_saved_pc_libfunc;
+rtx get_eh_context_libfunc;
 
 rtx eqhf2_libfunc;
 rtx nehf2_libfunc;
@@ -4290,6 +4292,8 @@
   longjmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "longjmp");
 #endif
   get_dynamic_handler_chain_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__get_dynamic_handler_chain");
+  get_saved_pc_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__get_saved_pc");
+  get_eh_context_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__get_eh_context");
 
   eqhf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqhf2");
   nehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nehf2");
Index: config/sparc/sol2.h
===================================================================
RCS file: /trema/cvs/gnu/egcs/gcc/config/sparc/sol2.h,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -u -r1.1.1.1 -r1.3
--- sol2.h	1997/09/26 09:58:13	1.1.1.1
+++ sol2.h	1997/09/29 08:41:58	1.3
@@ -23,6 +23,20 @@
 /* Supposedly the same as vanilla sparc svr4, except for the stuff below: */
 #include "sparc/sysv4.h"
 
+/* Define either _SOLARIS_THREADS or _PTHREADS
+   and NEED_THREAD_STUBS to have threads support always in libgcc. */
+#ifndef _SOLARIS_THREADS
+#ifndef _PTHREADS
+/* #define _SOLARIS_THREADS 1  */
+#endif
+#endif
+
+#ifndef NEED_THREAD_STUBS
+#if _PTHREADS || _SOLARIS_THREADS
+/* #define NEED_THREAD_STUBS 1 */
+#endif
+#endif
+
 #undef CPP_PREDEFINES
 #define CPP_PREDEFINES \
  "-Dsun -Dsparc -Dunix -D__svr4__ -D__SVR4 \
@@ -31,6 +45,8 @@
 
 #undef CPP_SPEC
 #define CPP_SPEC "\
+%{pthreads:-D_REENTRANT -D_PTHREADS} \
+%{!pthreads:%{threads:-D_REENTRANT -D_SOLARIS_THREADS}} \
 %{compat-bsd:-iwithprefixbefore ucbinclude -I/usr/ucbinclude} \
 %(cpp_cpu) \
 "
@@ -129,7 +145,12 @@
 
 #undef LIB_SPEC
 #define LIB_SPEC \
-  "%{compat-bsd:-lucb -lsocket -lnsl -lelf -laio} %{!shared:%{!symbolic:-lc}}"
+  "%{compat-bsd:-lucb -lsocket -lnsl -lelf -laio} \
+   %{!shared:\
+     %{!symbolic:\
+       %{pthreads:-lpthread} \
+       %{!pthreads:%{threads:-lthread}} \
+       -lc}}"
 
 #undef  ENDFILE_SPEC
 #define ENDFILE_SPEC "crtend.o%s crtn.o%s"
Index: config/sparc/t-sol2
===================================================================
RCS file: /trema/cvs/gnu/egcs/gcc/config/sparc/t-sol2,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -u -r1.1.1.1 -r1.2
--- t-sol2	1997/09/26 09:58:14	1.1.1.1
+++ t-sol2	1997/09/29 08:41:59	1.2
@@ -5,6 +5,12 @@
 CROSS_LIBGCC1 =
 LIBGCC1_TEST =
 
+MULTILIB_OPTIONS = pthreads/threads
+MULTILIB_DIRNAMES = pthreads threads
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
+
 # gmon build rule:
 gmon.o:	$(srcdir)/config/sparc/gmon-sol2.c $(GCC_PASSES) $(CONFIG_H) stmp-int-hdrs
 	$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
Index: cp/except.c
===================================================================
RCS file: /trema/cvs/gnu/egcs/gcc/cp/except.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -u -r1.1.1.1 -r1.2
--- except.c	1997/09/26 09:58:21	1.1.1.1
+++ except.c	1997/09/26 15:43:16	1.2
@@ -177,11 +177,20 @@
 /* Used to cache a call to __unwind_function.  */
 static tree Unwind;
 
+/* Same for __get_cpp_eh_context (); */
+static tree GetCPPEHContextRef;
+
 /* Holds a ready to emit call to "terminate".  */
 static tree TerminateFunctionCall;
 
 static tree empty_fndecl;
 
+/* void** */
+static tree ptr_ptr_type_node;
+
+/* void (*)() */
+static tree PFV_type_node;
+
 /* ====================================================================== */
 
 
@@ -194,17 +203,6 @@
 
    ========================================================================= */
 
-/* Holds the pc for doing "throw" */
-static tree saved_pc;
-/* Holds the type of the thing being thrown.  */
-static tree saved_throw_type;
-/* Holds the value being thrown.  */
-static tree saved_throw_value;
-/* Holds the cleanup for the value being thrown.  */
-static tree saved_cleanup;
-/* Indicates if we are in a catch clause.  */
-static tree saved_in_catch;
-
 extern int throw_used;
 extern rtx catch_clauses;
 
@@ -240,6 +238,7 @@
   tree catch_match_fndecl;
   tree find_first_exception_match_fndecl;
   tree unwind_fndecl;
+  tree get_cpp_eh_context_ref_fndecl;
   tree declspecs;
   tree d;
 
@@ -256,6 +255,8 @@
   /* void (*pfvtype (void (*) ()))() */
   tree pfvtype = build_function_type (PFV, pfvlist);
 
+  PFV_type_node = PFV;
+
   set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
 					pfvtype, NOT_BUILT_IN);
   set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
@@ -308,49 +309,67 @@
 
   TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
 
-  pop_lang_context ();
+  /* void** */
+  ptr_ptr_type_node = build_pointer_type (ptr_type_node);
 
-  declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
-  d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
-  d = start_decl (d, declspecs, 0);
-  DECL_COMMON (d) = 1;
-  cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
-  saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
-
-  declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
-  d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
-  d = start_decl (d, declspecs, 0);
-  DECL_COMMON (d) = 1;
-  cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
-  saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
-
-  declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
-  d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
-  d = start_decl (d, declspecs, 0);
-  DECL_COMMON (d) = 1;
-  cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
-  saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
-
-  declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
-  d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
-  d = make_call_declarator (d, void_list_node, NULL_TREE, NULL_TREE);
-  d = start_decl (d, declspecs, 0);
-  DECL_COMMON (d) = 1;
-  cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
-  saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
-
-  declspecs = tree_cons (NULL_TREE, get_identifier ("bool"), NULL_TREE);
-  d = get_identifier ("__eh_in_catch");
-  d = start_decl (d, declspecs, 0);
-  DECL_COMMON (d) = 1;
-  cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
-  saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0);
+  get_cpp_eh_context_ref_fndecl
+    = builtin_function ("__get_cpp_eh_context",
+                        build_function_type (ptr_ptr_type_node,
+                                             void_list_node),
+                        NOT_BUILT_IN, NULL_PTR);
+  /* Set this so that multiple calls to __get_cpp_eh_context can be CSE'd. */
+  TREE_READONLY (get_cpp_eh_context_ref_fndecl) = 1;
+  GetCPPEHContextRef = default_conversion (get_cpp_eh_context_ref_fndecl);
+
+  pop_lang_context ();
 
   /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
      be protected with __terminate.  */
   protect_cleanup_actions_with_terminate = 1;
 }
 
+/* The layout of the eh context structure for C++ is
+
+     __eh_type
+     __eh_value
+     __eh_cleanup
+     __eh_in_catch */
+
+static tree
+build_saved_throw_type ()
+{
+  tree t = build_function_call (GetCPPEHContextRef, NULL_TREE);
+  assemble_external (TREE_OPERAND (GetCPPEHContextRef, 0));
+  return build1 (INDIRECT_REF, ptr_type_node, t);
+}
+
+static tree
+build_saved_throw_value ()
+{
+  tree t = build_function_call (GetCPPEHContextRef, NULL_TREE);
+  assemble_external (TREE_OPERAND (GetCPPEHContextRef, 0));
+  t = build_binary_op_nodefault (PLUS_EXPR, t, integer_one_node, PLUS_EXPR);
+  return build1 (INDIRECT_REF, ptr_type_node, t);
+}
+
+static tree
+build_saved_cleanup ()
+{
+  tree t = build_function_call (GetCPPEHContextRef, NULL_TREE);
+  assemble_external (TREE_OPERAND (GetCPPEHContextRef, 0));
+  t = build_binary_op_nodefault (PLUS_EXPR, t, integer_two_node, PLUS_EXPR);
+  return build1 (INDIRECT_REF, PFV_type_node, t);
+}
+
+static tree
+build_saved_in_catch ()
+{
+  tree t = build_function_call (GetCPPEHContextRef, NULL_TREE);
+  assemble_external (TREE_OPERAND (GetCPPEHContextRef, 0));
+  t = build_binary_op_nodefault (PLUS_EXPR, t, integer_three_node, PLUS_EXPR);
+  return build1 (INDIRECT_REF, integer_type_node, t);
+}
+
 /* Build a type value for use at runtime for a type that is matched
    against by the exception handling system.  */
 
@@ -405,10 +424,15 @@
   int yes = suspend_momentary ();
 
   /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
-  tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
+  tree cleanup = build_function_call (build_saved_cleanup(), NULL_TREE);
   cleanup = build (COMPOUND_EXPR, void_type_node, cleanup,
-		   build_modify_expr (saved_in_catch, NOP_EXPR,
-				      build_modify_expr (saved_throw_type, NOP_EXPR, integer_zero_node)));
+		   build_modify_expr
+                     (build_saved_in_catch(), NOP_EXPR,
+                      build_static_cast
+                        (boolean_type_node,
+                         build_modify_expr (build_saved_throw_type (),
+                                            NOP_EXPR,
+                                            integer_zero_node))));
   expand_decl_cleanup (NULL_TREE, cleanup);
 
   resume_momentary (yes);
@@ -425,6 +449,7 @@
 expand_start_catch_block (declspecs, declarator)
      tree declspecs, declarator;
 {
+  rtx in_catch_rtx;
   rtx false_label_rtx;
   tree decl = NULL_TREE;
   tree init;
@@ -486,11 +511,11 @@
 	  && TREE_CODE (init_type) != POINTER_TYPE)
 	init_type = build_reference_type (init_type);
 
-      exp = saved_throw_value;
+      exp = build_saved_throw_value ();
       exp = tree_cons (NULL_TREE,
 		       build_eh_type_type (TREE_TYPE (decl)),
 		       tree_cons (NULL_TREE,
-				  saved_throw_type,
+				  build_saved_throw_type (),
 				  tree_cons (NULL_TREE, exp, NULL_TREE)));
       exp = build_function_call (CatchMatch, exp);
       call_rtx = expand_call (exp, NULL_RTX, 0);
@@ -522,7 +547,8 @@
       /* Fall into the catch all section.  */
     }
 
-  emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
+  in_catch_rtx = expand_expr (build_saved_in_catch (), NULL_RTX, SImode, 0);
+  emit_move_insn (in_catch_rtx, const1_rtx);
 
   /* If we are not doing setjmp/longjmp EH, because we are reordered
      out of line, we arrange to rethrow in the outer context so as to
@@ -718,6 +744,7 @@
   rtx top_of_loop;
   tree t;
   rtx x;
+  rtx throw_type_rtx;
 
   if (! doing_eh (0))
     return;
@@ -746,13 +773,16 @@
   /* These two can be frontend specific.  If wanted, they can go in
      expand_throw.  */
   /* Do we have a valid object we are throwing? */
-  emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
-		 GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
+  throw_type_rtx = expand_expr (build_saved_throw_type (), NULL_RTX, Pmode, 0);
+  emit_cmp_insn (throw_type_rtx, const0_rtx, EQ, NULL_RTX,
+		 GET_MODE (throw_type_rtx), 0, 0);
   emit_jump_insn (gen_beq (gotta_call_terminate));
 
   /* search for an exception handler for the saved_pc */
   handler = do_function_call (FirstExceptionMatch,
-			      tree_cons (NULL_TREE, saved_pc,
+			      tree_cons (NULL_TREE,
+                                         make_tree (ptr_ptr_type_node,
+                                                    get_saved_pc_ref ()),
 					 NULL_TREE),
 			      ptr_type_node);
   assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
@@ -833,7 +863,7 @@
     }
   else
 #endif
-    emit_move_insn (eh_saved_pc_rtx, next_pc);
+    emit_move_insn (get_saved_pc_ref (), next_pc);
 
   after_unwind = gen_label_rtx ();
   do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind));
@@ -968,11 +998,11 @@
       if (match_type)
 	{
 	  /* check TREE_VALUE (raises) here */
-	  exp = saved_throw_value;
+	  exp = build_saved_throw_value ();
 	  exp = tree_cons (NULL_TREE,
 			   build_eh_type_type (match_type),
 			   tree_cons (NULL_TREE,
-				      saved_throw_type,
+				      build_saved_throw_type (),
 				      tree_cons (NULL_TREE, exp, NULL_TREE)));
 	  exp = build_function_call (CatchMatch, exp);
 	  assemble_external (TREE_OPERAND (CatchMatch, 0));
@@ -1148,7 +1178,7 @@
 
        	  /* Build __tcf_ function. */
 	  cleanup = start_anon_func ();
-	  object = build_delete (TREE_TYPE (exp), saved_throw_value, 
+	  object = build_delete (TREE_TYPE (exp), build_saved_throw_value (), 
 				 integer_three_node, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
 	  expand_expr (object, const0_rtx, VOIDmode, 0);
 	  end_anon_func ();
@@ -1158,15 +1188,15 @@
       if (cleanup == empty_fndecl)
 	assemble_external (empty_fndecl);
 	
-      e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
+      e = build_modify_expr (build_saved_throw_type (), NOP_EXPR, throw_type);
       expand_expr (e, const0_rtx, VOIDmode, 0);
 
-      e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
+      e = build_modify_expr (build_saved_throw_value (), NOP_EXPR, exp);
       e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
       expand_expr (e, const0_rtx, VOIDmode, 0);
 
       cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
-      cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
+      cleanup = build_modify_expr (build_saved_cleanup(), NOP_EXPR, cleanup);
       expand_expr (cleanup, const0_rtx, VOIDmode, 0);
     }
   else
Index: cp/exception.cc
===================================================================
RCS file: /trema/cvs/gnu/egcs/gcc/cp/exception.cc,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -u -r1.1.1.1 -r1.2
--- exception.cc	1997/09/26 09:58:22	1.1.1.1
+++ exception.cc	1997/09/26 15:43:17	1.2
@@ -91,12 +91,20 @@
   throw bad_exception ();
 }
 
+// Must match definition in libgcc2.c.
+struct cpp_eh_context
+{
+  void *type;
+  void *value;
+  void  (*cleanup) ();
+  int   in_catch;
+};
+
 bool
 uncaught_exception ()
 {
-  extern void *__eh_type;
-  extern bool __eh_in_catch;
-  return __eh_type && ! __eh_in_catch;
+  cpp_eh_context* ehc = (cpp_eh_context *)__get_cpp_eh_context ();
+  return ehc->type && ! ehc->in_catch;
 }
 
 const char * exception::

----------------------------------------------------------------------

Teemu

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~1997-10-07 22:59 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <199709291121.NAA11557.cygnus.egcs@baht.labs.trema.com>
1997-09-30  0:26 ` MT safe exception diffs Jason Merrill
1997-09-30  0:43   ` Teemu Torma
1997-10-07 22:59     ` Jason Merrill
1997-09-29  4:22 Teemu Torma
1997-09-29  6:38 ` John Carr
1997-09-29  7:43   ` Teemu Torma

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).