This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Destruction of globals


This patch fixes a number of problems with the destruction of global
and block-static objects:
- If initialization of a block-local fails with an exception,
  initialization is not retried
- Objects are not always destroyed in reverse order of construction
- Destruction order does not correctly interleave with atexit
- In a multi-threaded environment, block-statics may be initialized
  twice, or threads may access uninitialized block-statics.

To do so, a number of interfaces to libgcc2 is introduced:

struct __dtorlist{
  void (*dtor)();
  struct __dtorlist *next;
};

/* Register a most-recent destructor. If entry is null, do so using
   atexit. */
 
void __cp_register_dtor (void (*dtor)(), struct __dtorlist *entry);

/* See whether the variable associated with p needs initialization.
   Returns 0 if no initialization is needed. If initialization is in
   progress in another thread, block until initialization is
   complete. */

int __cp_init_begin (int * p);

/* Initialization failed with an exception. Unblock waiting
   threads, restore *p to 'uninitialized' */

void __cp_init_failed (int* p);

/* Initialization succeeded. Record that fact in *p,
   register the destructor, and release waiting threads. */

void __cp_init_complete (int *p, void (*dtor)(), 
                         struct __dtorlist *entry);

To the user, the functionality is exposed with three command line
flags:

-fdtors-static is the current behaviour, and the default.
-fdtors-dynamic builds lists of destructors in reverse order.
 atexit interleaving is not guaranteed, but it does not require
 dynamic memory allocation, and it does not suffer from atexit
 limitations. Potentially, it also gets the dlclose issue right.
 This is implicitly enabled with -fnew-abi.
-fdtors-atexit uses atexit to register the destructor. If the C
 library supports early execution or unregistration of atexit
 functions, such a facility can be used.
 This is implicitly enabled with -ansi.

There is a number of limitations in this implementation:
- The issues with shared images are not all resolved, yet. In
  particular, libgcc2 maintains a list of dtors *per shared object*
  in the dynamic case, whereas the list should be program-global.
  Unregistration of specific dtors is already possible.
- If there was a global list, it is not clear whether it should
  be protected against multiple threads that dlopen shared images
  simultaneously.
- The interfaces proposed need review.
- Optimizations with respect to the code size are still possible.
  For example, when the constructor doesn't throw exceptions,
  the init_failed part is not needed, which would also remove.

The change is included below, please comment.

Martin

1998-08-31  Martin von L÷wis  <loewis@informatik.hu-berlin.de>

	* cp-tree.h (dtor_ordering): New enumeration.
	* decl.c (expand_static_init): Call expand_static_init_dynamic for
	dynamic and atexit ordering.
	* decl2.c (flag_dtors_ordering): New flag variable.
	(lang_decode_option): Initialize it.
	(do_dtors): Do nothing for dynamic and atexit ordering.
	(do_ctors): Instead, call do_dynamic_dtor.
	* init.c (dtorlist_type_node, dtorlist_ptr_node,
	null_dtorlist_node): New static variables.
	(init_init_processing): Initialize them.
	(expand_static_init_dynamic, do_dynamic_dtor): New functions.
	* lang_options.h (-fdtors-static, -fdtors-dynamic,
	-fdtors-atexit): New flags.
	* initialize.c: New file.
	* Make-lang.in: Compile it into libgcc2.


Index: Make-lang.in
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/Make-lang.in,v
retrieving revision 1.17
diff -c -p -r1.17 Make-lang.in
*** Make-lang.in	1998/08/17 11:42:20	1.17
--- Make-lang.in	1998/08/31 07:24:06
*************** CXX_EXTRA_HEADERS = $(srcdir)/cp/inc/typ
*** 61,70 ****
  
  # Extra code to include in libgcc2.
  CXX_LIB2FUNCS = tinfo.o tinfo2.o new.o opnew.o opnewnt.o opvnew.o opvnewnt.o \
! 	opdel.o opdelnt.o opvdel.o opvdelnt.o exception.o
  CXX_LIB2SRCS = $(srcdir)/cp/new.cc $(srcdir)/cp/new1.cc $(srcdir)/cp/new2.cc \
  	$(srcdir)/cp/exception.cc $(srcdir)/cp/tinfo.cc \
! 	$(srcdir)/cp/tinfo2.cc $(srcdir)/cp/tinfo.h
  #
  # Define the names for selecting c++ in LANGUAGES.
  # Note that it would be nice to move the dependency on g++
--- 61,70 ----
  
  # Extra code to include in libgcc2.
  CXX_LIB2FUNCS = tinfo.o tinfo2.o new.o opnew.o opnewnt.o opvnew.o opvnewnt.o \
! 	opdel.o opdelnt.o opvdel.o opvdelnt.o exception.o initialize.o
  CXX_LIB2SRCS = $(srcdir)/cp/new.cc $(srcdir)/cp/new1.cc $(srcdir)/cp/new2.cc \
  	$(srcdir)/cp/exception.cc $(srcdir)/cp/tinfo.cc \
! 	$(srcdir)/cp/tinfo2.cc $(srcdir)/cp/tinfo.h $(srcdir)/cp/initialize.c
  #
  # Define the names for selecting c++ in LANGUAGES.
  # Note that it would be nice to move the dependency on g++
*************** tinfo2.o: cc1plus$(exeext) $(srcdir)/cp/
*** 148,153 ****
--- 148,156 ----
  exception.o: cc1plus$(exeext) $(srcdir)/cp/exception.cc
  	$(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
  	  -c -fexceptions $(srcdir)/cp/exception.cc
+ initialize.o: cc1$(exeext) $(srcdir)/cp/initialize.c
+ 	$(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ 	  -c $(srcdir)/cp/initialize.c
  new.o: cc1plus$(exeext) $(srcdir)/cp/new.cc
  	$(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
  	  -c $(srcdir)/cp/new.cc
Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.126
diff -c -p -r1.126 cp-tree.h
*** cp-tree.h	1998/08/28 16:11:31	1.126
--- cp-tree.h	1998/08/31 07:24:11
*************** extern int flag_gnu_binutils;
*** 325,330 ****
--- 326,336 ----
  
  extern int flag_no_ident;
  
+ /* Three different ways of ordering destructors. */
+ 
+ enum dtor_ordering {dtors_static, dtors_dynamic, dtors_atexit};
+ enum dtor_ordering flag_dtors_ordering;
+ 
  /* Nonzero means warn about implicit declarations.  */
  
  extern int warn_implicit;
*************** extern tree build_x_delete			PROTO((tree
*** 2700,2705 ****
--- 2706,2713 ----
  extern tree build_delete			PROTO((tree, tree, tree, int, int));
  extern tree build_vbase_delete			PROTO((tree, tree));
  extern tree build_vec_delete			PROTO((tree, tree, tree, tree, int));
+ extern void expand_static_init_dynamic		PROTO((tree, tree));
+ extern void do_dynamic_dtor			PROTO((tree));
  
  /* in input.c */
  
Index: decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.199
diff -c -p -r1.199 decl.c
*** decl.c	1998/08/30 11:46:42	1.199
--- decl.c	1998/08/31 07:24:25
*************** expand_static_init (decl, init)
*** 7629,7635 ****
        if (TREE_PURPOSE (oldstatic) && init != NULL_TREE)
  	cp_error ("multiple initializations given for `%D'", decl);
      }
!   else if (! toplevel_bindings_p () && ! pseudo_global_level_p ())
      {
        /* Emit code to perform this initialization but once.  */
        tree temp;
--- 7631,7638 ----
        if (TREE_PURPOSE (oldstatic) && init != NULL_TREE)
  	cp_error ("multiple initializations given for `%D'", decl);
      }
!   else if (! toplevel_bindings_p () && ! pseudo_global_level_p ()
! 	   && flag_dtors_ordering == dtors_static)
      {
        /* Emit code to perform this initialization but once.  */
        tree temp;
*************** expand_static_init (decl, init)
*** 7702,7707 ****
--- 7705,7712 ----
        /* Resume old (possibly temporary) allocation.  */
        pop_obstacks ();
      }
+   else if (! toplevel_bindings_p () && ! pseudo_global_level_p ())
+       expand_static_init_dynamic (decl,init);
    else
      {
        /* This code takes into account memory allocation
Index: decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.123
diff -c -p -r1.123 decl2.c
*** decl2.c	1998/08/28 16:11:33	1.123
--- decl2.c	1998/08/31 07:24:30
*************** int flag_init_priority = 1;
*** 181,186 ****
--- 181,190 ----
  int flag_init_priority;
  #endif
  
+ /* Define destructor ordering. */
+ 
+ enum dtor_ordering flag_dtors_ordering = dtors_dynamic;
+ 
  /* Nonzero means warn about implicit declarations.  */
  
  int warn_implicit = 1;
*************** lang_decode_option (argc, argv)
*** 597,614 ****
--- 601,626 ----
  	  error ("-fno-ansi-overloading is no longer supported");
  	  found = 1;
  	}
+       else if (!strcmp (p, "dtors-static"))
+ 	  flag_dtors_ordering = dtors_static;
+       else if (!strcmp (p, "dtors-dynamic"))
+ 	  flag_dtors_ordering = dtors_dynamic;
+       else if (!strcmp (p, "dtors-atexit"))
+ 	  flag_dtors_ordering = dtors_atexit;
        else if (!strcmp (p, "new-abi"))
  	{
  	  flag_new_abi = 1;
  	  flag_do_squangling = 1;
  	  flag_honor_std = 1;
  	  flag_vtable_thunks = 1;
+ 	  flag_dtors_ordering = dtors_dynamic;
  	}
        else if (!strcmp (p, "no-new-abi"))
  	{
  	  flag_new_abi = 0;
  	  flag_do_squangling = 0;
  	  flag_honor_std = 0;
+ 	  flag_dtors_ordering = dtors_static;
  	}
        else if (!strncmp (p, "template-depth-", 15))
  	{
*************** lang_decode_option (argc, argv)
*** 763,769 ****
      }
    else if (!strcmp (p, "-ansi"))
      flag_no_nonansi_builtin = 1, flag_ansi = 1,
!     flag_no_gnu_keywords = 1, flag_operator_names = 1;
  #ifdef SPEW_DEBUG
    /* Undocumented, only ever used when you're invoking cc1plus by hand, since
       it's probably safe to assume no sane person would ever want to use this
--- 775,782 ----
      }
    else if (!strcmp (p, "-ansi"))
      flag_no_nonansi_builtin = 1, flag_ansi = 1,
!     flag_no_gnu_keywords = 1, flag_operator_names = 1,
!     flag_dtors_ordering = dtors_atexit;
  #ifdef SPEW_DEBUG
    /* Undocumented, only ever used when you're invoking cc1plus by hand, since
       it's probably safe to assume no sane person would ever want to use this
*************** do_dtors (start)
*** 3159,3164 ****
--- 3180,3189 ----
        initp = TREE_INT_CST_LOW (TREE_PURPOSE (start));
        vars = TREE_VALUE (start);
      }
+   else if (flag_dtors_ordering != dtors_static)
+     /* For dynamic and atexit registration, the destructors will 
+        be registered during construction. */
+     return;
    else
      {
        initp = 0;
*************** do_ctors (start)
*** 3319,3329 ****
--- 3344,3360 ----
  	  /* Cleanup any temporaries needed for the initial value.  */
  	  expand_end_target_temps ();
  
+ 	  /* If we need to register the destructor, do it now. */
+ 	  if (flag_dtors_ordering == dtors_dynamic ||
+ 	      flag_dtors_ordering == dtors_atexit)
+ 	    do_dynamic_dtor (decl);
+ 
  	  if (protect)
  	    expand_end_cond ();
  
  	  DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE;
  	  DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
+ 
  	}
        else if (decl == error_mark_node)
  	/* OK */;
Index: init.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/init.c,v
retrieving revision 1.62
diff -c -p -r1.62 init.c
*** init.c	1998/08/27 17:33:33	1.62
--- init.c	1998/08/31 07:24:36
*************** static tree minus_one;
*** 73,81 ****
  
  static tree BI_header_type, BI_header_size;
  
  void init_init_processing ()
  {
!   tree fields[1];
  
    minus_one = build_int_2 (-1, -1);
  
--- 73,86 ----
  
  static tree BI_header_type, BI_header_size;
  
+ /* Destructor lists. */
+ static tree dtorlist_type_node;
+ static tree dtorlist_ptr_node;
+ static tree null_dtorlist_node;
+ 
  void init_init_processing ()
  {
!   tree t1, fields[2];
  
    minus_one = build_int_2 (-1, -1);
  
*************** void init_init_processing ()
*** 87,92 ****
--- 92,111 ----
    finish_builtin_type (BI_header_type, "__new_cookie", fields,
  		       0, double_type_node);
    BI_header_size = size_in_bytes (BI_header_type);
+ 
+   /* struct __dtorlist. This must match initialize.c.  */
+   dtorlist_type_node = t1 = make_lang_type (RECORD_TYPE);
+   fields[0] = build_lang_field_decl 
+     (FIELD_DECL, get_identifier ("dtor"), 
+      build_pointer_type (build_function_type 
+ 			 (void_type_node, void_list_node)));
+   fields[1] = build_lang_field_decl 
+     (FIELD_DECL, get_identifier ("next"), build_pointer_type (t1));
+   finish_builtin_type (t1, "__dtorlist", fields, 1, ptr_type_node);
+   dtorlist_ptr_node = build_pointer_type (t1);
+ 
+   null_dtorlist_node = build_int_2 (0, 0);
+   TREE_TYPE (null_dtorlist_node) = dtorlist_ptr_node;
  }
  
  /* Subroutine of emit_base_init.  For BINFO, initialize all the
*************** build_vec_delete (base, maxindex, auto_d
*** 3300,3303 ****
--- 3319,3559 ----
  
    return build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
  			     use_global_delete);
+ }
+ 
+ /* Emit code to perform this initialization but once.  */
+ 
+ void
+ expand_static_init_dynamic (decl, init)
+      tree decl, init;
+ {
+   extern struct obstack permanent_obstack;
+   tree temp, ptemp, e, cleanup, registry;
+   tree PFV, fn;
+ 
+   /* Remember this information until end of file.  */
+   push_obstacks (&permanent_obstack, &permanent_obstack);
+ 
+   /* Emit code to perform this initialization but once.  */
+   temp = get_temp_name (integer_type_node, 1);
+   rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
+ 
+   fn = get_identifier ("__cp_init_begin");
+   if (IDENTIFIER_GLOBAL_VALUE (fn))
+     fn = IDENTIFIER_GLOBAL_VALUE (fn);
+   else
+     {
+       /* Declare int __cp_init_begin (int *); */
+       tree tmp;
+       tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+       fn = build_lang_decl (FUNCTION_DECL, fn,
+ 			    build_function_type (integer_type_node, tmp));
+       DECL_EXTERNAL (fn) = 1;
+       TREE_PUBLIC (fn) = 1;
+       DECL_ARTIFICIAL (fn) = 1;
+       pushdecl_top_level (fn);
+       make_function_rtl (fn);
+       assemble_external (fn);
+     }
+ 
+   e = build1 (ADDR_EXPR, ptr_type_node, temp);
+   e = expr_tree_cons (NULL_TREE, e, NULL_TREE);
+   e = build_function_call (fn, e);
+ 
+   expand_start_cond (e, 0);
+   expand_start_target_temps ();
+ 
+   if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
+       || (init && TREE_CODE (init) == TREE_LIST))
+     {
+       /* This implements the following pseudo code
+          try{
+            initialization;
+          }catch(...){
+            __cp_init_failed(&_tmp_flag);
+            throw;
+          }
+       */
+       begin_try_block ();
+       expand_aggr_init (decl, init, 0, 0);
+       do_pending_stack_adjust ();
+       expand_start_all_catch ();
+       /* expand_start_catch_block (NULL_TREE, NULL_TREE); */
+ 
+       fn = get_identifier ("__cp_init_failed");
+       if (IDENTIFIER_GLOBAL_VALUE (fn))
+ 	fn = IDENTIFIER_GLOBAL_VALUE (fn);
+       else
+ 	{
+ 	  /* Declare void __cp_init_failed (int *); */
+ 	  tree tmp;
+ 	  tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+ 	  fn = build_lang_decl (FUNCTION_DECL, fn,
+ 				build_function_type (void_type_node, tmp));
+ 	  DECL_EXTERNAL (fn) = 1;
+ 	  TREE_PUBLIC (fn) = 1;
+ 	  DECL_ARTIFICIAL (fn) = 1;
+ 	  pushdecl_top_level (fn);
+ 	  make_function_rtl (fn);
+ 	  assemble_external (fn);
+ 	}
+ 
+       e = build1 (ADDR_EXPR, ptr_type_node, temp);
+       e = expr_tree_cons (NULL_TREE, e, NULL_TREE);
+       e = build_function_call (fn, e);
+       expand_expr_stmt (e);
+ 
+       /* expand_expr_stmt (build_throw (NULL_TREE));
+          expand_end_catch_block (); */
+       expand_end_all_catch ();
+     }
+   else if (init)
+     expand_assignment (decl, init, 0, 0);
+ 
+   /* Cleanup any temporaries needed for the initial value.  */
+   expand_end_target_temps ();
+ 
+   /* void (*)(); */
+   PFV = build_pointer_type (build_function_type
+ 			    (void_type_node, void_list_node));
+ 
+   fn = get_identifier ("__cp_init_complete");
+   if (IDENTIFIER_GLOBAL_VALUE (fn))
+     fn = IDENTIFIER_GLOBAL_VALUE (fn);
+   else
+     {
+       /* Declare void 
+ 	 __cp_init_complete (int *, void (*)(), struct __dtorlist *); */
+       tree tmp;
+       tmp = tree_cons (NULL_TREE, ptr_type_node, tree_cons
+ 		       (NULL_TREE, PFV, tree_cons
+ 			(NULL_TREE, dtorlist_ptr_node, void_list_node)));
+       fn = build_lang_decl (FUNCTION_DECL, fn,
+ 			    build_function_type (void_type_node, tmp));
+       DECL_EXTERNAL (fn) = 1;
+       TREE_PUBLIC (fn) = 1;
+       DECL_ARTIFICIAL (fn) = 1;
+       pushdecl_top_level (fn);
+       make_function_rtl (fn);
+       assemble_external (fn);
+     }
+ 
+   /* Call init_complete. */
+   if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
+     {
+       e = start_anon_func ();
+       expand_expr_stmt (build_cleanup (decl));
+       end_anon_func ();
+       mark_addressable (e);
+       cleanup = build_unary_op (ADDR_EXPR, e, 0);
+       if (flag_dtors_ordering == dtors_atexit)
+ 	/* Under strict compliance, we don't run our own
+ 	   destructor registry, but use atexit or equivalent.  */
+ 	registry = null_dtorlist_node;
+       else if (flag_dtors_ordering == dtors_dynamic)
+ 	{
+ 	  registry = get_temp_name (dtorlist_type_node, 1);
+ 	  rest_of_decl_compilation (registry, NULL_PTR, 0, 0);
+ 	  registry = build1 (ADDR_EXPR, dtorlist_ptr_node, registry);
+ 	}
+       else
+ 	/* We don't do static registration here. */
+ 	my_friendly_abort (980830);
+     }
+   else
+     {
+       static tree null_fptr = NULL_TREE;
+       if (null_fptr == NULL_TREE)
+ 	{
+ 	  tree ftype = build_pointer_type (build_function_type 
+ 					   (void_type_node, void_list_node));
+ 	  layout_type (ftype);
+ 	  null_fptr = build_int_2 (0, 0);
+ 	  TREE_TYPE (null_fptr) = ftype;
+ 	}
+       cleanup = null_fptr;
+       registry = null_dtorlist_node;
+     }
+   
+   e = expr_tree_cons (NULL_TREE, registry, NULL_TREE);
+   e = expr_tree_cons (NULL_TREE, cleanup, e);
+   ptemp = build1 (ADDR_EXPR, ptr_type_node, temp);
+   e = expr_tree_cons (NULL_TREE, ptemp, e);
+   e = build_function_call (fn, e);
+   
+   expand_expr_stmt (e);
+   expand_end_cond ();
+ 
+   /* Resume old (possibly temporary) allocation.  */
+   pop_obstacks ();
+ }
+ 
+ /* Register a single destructor function at runtime. */
+ void
+ do_dynamic_dtor (decl)
+      tree decl;
+ {
+   tree type = TREE_TYPE (decl);
+   tree e, fn, registry, dtor;
+ 
+   if (!TYPE_NEEDS_DESTRUCTOR (type) || DECL_EXTERNAL (decl))
+     return;
+ 
+   dtor = start_anon_func ();
+ 
+   if (member_p (decl))
+     {
+       DECL_CLASS_CONTEXT (current_function_decl) = DECL_CONTEXT (decl);
+       DECL_STATIC_FUNCTION_P (current_function_decl) = 1;
+     }
+       
+   /* We need no protection agains multiple destruction here,
+      since the constructor is protected and registers us.  */
+   expand_expr_stmt (build_cleanup (decl));
+       
+   DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE;
+   DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
+   
+   end_anon_func ();
+   mark_addressable (dtor);
+ 
+   fn = get_identifier ("__cp_register_dtor");
+   if (IDENTIFIER_GLOBAL_VALUE (fn))
+     fn = IDENTIFIER_GLOBAL_VALUE (fn);
+   else
+     {
+       /* Declare void 
+ 	 __cp_register_dtor (void (*)(), struct __dtorlist *); */
+       tree tmp, PFV;
+       PFV = build_pointer_type (build_function_type
+ 				(void_type_node, void_list_node));
+       tmp = tree_cons(NULL_TREE, PFV, tree_cons
+ 		      (NULL_TREE, dtorlist_ptr_node, void_list_node));
+       fn = build_lang_decl (FUNCTION_DECL, fn,
+ 			    build_function_type (void_type_node, tmp));
+       DECL_EXTERNAL (fn) = 1;
+       TREE_PUBLIC (fn) = 1;
+       DECL_ARTIFICIAL (fn) = 1;
+       pushdecl_top_level (fn);
+       make_function_rtl (fn);
+       assemble_external (fn);
+     }
+   
+   if (flag_dtors_ordering == dtors_atexit)
+     registry = null_dtorlist_node;
+   else if (flag_dtors_ordering == dtors_dynamic)
+     {
+       /* We could make this shared if the object is shared. */
+       registry = get_temp_name (dtorlist_type_node, 1);
+       rest_of_decl_compilation (registry, NULL_PTR, 0, 0);
+       registry = build1 (ADDR_EXPR, dtorlist_ptr_node, registry);
+     }
+   else
+     /* We don't do static registration here. */
+     my_friendly_abort (980830);
+ 
+   e = expr_tree_cons (NULL_TREE, registry, NULL_TREE);
+   e = expr_tree_cons (NULL_TREE, dtor, e);
+   e = build_function_call (fn, e);
+   expand_expr_stmt (e);
  }
Index: lang-options.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/lang-options.h,v
retrieving revision 1.15
diff -c -p -r1.15 lang-options.h
*** lang-options.h	1998/08/28 16:11:34	1.15
--- lang-options.h	1998/08/31 07:24:36
*************** DEFINE_LANG_NAME ("C++")
*** 67,72 ****
--- 67,75 ----
    { "-fno-implicit-templates", "" },
    { "-finit-priority", "Handle the init_priority attribute" },
    { "-fno-init-priority", "" },
+   { "-fdtors-atexit", "Register destructors with atexit" },
+   { "-fdtors-dynamic", "Register destructors dynamically" },
+   { "-fdtors-static", "Register destructors at compile time" },
    { "-flabels-ok", "Labels can be used as first class objects" },
    { "-fno-labels-ok", "" },
    { "-fmemoize-lookups", "" },
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ initialize.c	Sun Aug 30 20:34:13 1998
@@ -0,0 +1,144 @@
+// Functions for Initialization Support for C++, -*- C -*-
+// Copyright (C) 1998 Free Software Foundation
+
+// This file is part of GNU CC.
+
+// GNU CC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// GNU CC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GNU CC; see the file COPYING.  If not, write to
+// the Free Software Foundation, 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA. 
+
+// As a special exception, if you link this library with other files,
+// some of which are compiled with GCC, to produce an executable,
+// this library does not by itself cause the resulting executable
+// to be covered by the GNU General Public License.
+// This exception does not however invalidate any other reasons why
+// the executable file might be covered by the GNU General Public License.
+
+/* Initialization variables have the following states:
+   0 - uninitialized
+   1 - initialization in progress
+   2 - initialization complete
+*/
+
+#include <stdlib.h>
+#include "gthr.h"
+
+/* FIXME: There should be one of these per program,
+   not per shared object. */
+
+static __gthread_mutex_t initlock = __GTHREAD_MUTEX_INIT;
+
+struct __dtorlist{
+  void (*dtor)();
+  struct __dtorlist *next;
+};
+
+/* FIXME: There should be one of these per program,
+   not per shared object. */
+
+static struct __dtorlist *__cp_dtors;
+
+/* These are meant to be per shared object. */
+static void *min_dtor, *max_dtor;
+
+/* For static initialization, this runs unprotected.
+   For dynamic (block-static) ctors, we hold the initlock.  */
+
+void
+__cp_register_dtor (void (*dtor)(), struct __dtorlist *entry)
+{
+  if (!entry)
+    {
+      /* FIXME: If we have an atexit implementation that supports
+	 unregistration, use it. */
+      atexit(dtor);
+      return;
+    }
+  entry->dtor = dtor;
+  entry->next = __cp_dtors;
+  __cp_dtors = entry;
+  if (!min_dtor || min_dtor > (void*)dtor)
+    min_dtor = dtor;
+  if (!max_dtor || max_dtor < (void*)dtor)
+    max_dtor = dtor;
+}
+
+static void __cp_run_dtors () __attribute__((destructor));
+
+static void
+__cp_run_dtors ()
+{
+  /* First, run everything and clear the function pointer */
+  struct __dtorlist *entry, *prev;
+  for (entry = __cp_dtors; entry; entry = entry->next)
+    if (entry->dtor && (void*)entry->dtor >= min_dtor
+	&& (void*)entry->dtor <= max_dtor)
+      {
+	entry->dtor();
+	entry->dtor = 0;
+      }
+  /* When removing from the list, obtain the lock. */
+  __gthread_mutex_lock (&initlock);
+  for (entry = __cp_dtors, prev = 0; entry; 
+       prev = entry, entry = entry->next)
+    if (!entry->dtor)
+      {
+	if (prev)
+	  prev->next = entry->next;
+	else
+	  __cp_dtors = entry->next;
+      }
+  __gthread_mutex_unlock (&initlock);
+}
+
+int
+__cp_init_begin (int * p)
+{
+  if (*p == 2)
+    /* Nothing to do. */
+    return 0;
+  __gthread_mutex_lock (&initlock);
+  switch (*p)
+    {
+    case 0:
+      *p = 1;
+      /* Could release lock here if we had condition variables. */
+      return 1;
+    case 2:
+      /* Done. */
+      __gthread_mutex_unlock (&initlock);
+      return 0;
+    }
+  /* Must have been 1, or some illegal value. With us holding the
+     lock, this should not happen. */
+  __gthread_mutex_unlock (&initlock);
+  abort ();
+  return 0;
+}
+
+void
+__cp_init_failed (int* p)
+{
+  *p = 0;
+  __gthread_mutex_unlock (&initlock);
+}
+
+void
+__cp_init_complete (int *p, void (*dtor)(), struct __dtorlist *entry)
+{
+  if (dtor)
+    __cp_register_dtor (dtor, entry);
+  *p = 2;
+  __gthread_mutex_unlock (&initlock);
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]