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]
Other format: [Raw text]

PATCH [gcc and libstdc++] for memory barriers in staticinitalization


My patch for PR c++/13684 implemented thread-safe initialization of C++
static local variables, using the double-checked locking pattern.  Shortly
after it was applied, someone pointed me to the "double-checked locking is
broken" declaration.  As it turns out, on some recent architectures (Alpha,
PPC, ia64, and SPARC in RMO mode) the hardware is allowed to reorder memory
accesses in ways that break double-checked locking unless explicit memory
barriers are added to prevent this movement.

This patch adds those memory barriers.

For those interested in the topic, I found Doug Lea's JSR-133 cookbook 

  http://gee.cs.oswego.edu/dl/jmm/cookbook.html

to be a good collection of information, if more Java-focused than I am.

Tested ia64-unknown-linux-gnu.  Since this fixes a bug in a new feature, I
think it's appropriate to apply now, but I'll hold off a bit for comments.

2004-12-23  Jason Merrill  <jason@redhat.com>

	Add memory barriers to the double-checked locking used for static
	initialization.

	* doc/tm.texi (TARGET_RELAXED_ORDERING): Document.
	* target.h (struct gcc_target): Add relaxed_ordering field.
	* target-def.h (TARGET_RELAXED_ORDERING): Define default.
	(TARGET_INITIALIZER): Add it.
	* config/alpha/alpha.c (TARGET_RELAXED_ORDERING): Define.
	* config/ia64/ia64.c (TARGET_RELAXED_ORDERING): Define.
	* config/rs6000/rs6000.c (TARGET_RELAXED_ORDERING): Define.
	* config/sparc/sparc.c (TARGET_RELAXED_ORDERING): Add comment.
	* cp/decl.c (expand_static_init): Don't use shortcut if
	targetm.relaxed_ordering.

	* libsupc++/guard.cc (__test_and_acquire): Define default.
	(_GLIBCXX_GUARD_TEST_AND_ACQUIRE, __set_and_release) 
	(_GLIBCXX_GUARD_SET_AND_RELEASE): Likewise.
	(recursion_push, recursion_pop): New abstraction functions.
	(__cxa_guard_acquire): Use _GLIBCXX_GUARD_TEST_AND_ACQUIRE.
	(__cxa_guard_release): Use _GLIBCXX_GUARD_SET_AND_RELEASE.
	* config/cpu/generic/cxxabi_tweaks.h (_GLIBCXX_GUARD_TEST): Rename
	from _GLIBCXX_GUARD_ACQUIRE and reverse sense.
	(_GLIBCXX_GUARD_SET): Rename from _GLIBCXX_GUARD_RELEASE.
	* config/cpu/arm/cxxabi_tweaks.h: Likewise.
	* config/cpu/alpha/atomic_word.h (_GLIBCXX_READ_MEM_BARRIER) 
	(_GLIBCXX_WRITE_MEM_BARRIER): Define.
	* config/cpu/powerpc/atomic_word.h: Likewise.
	* config/cpu/generic/atomic_word.h: Define them, commented out.
	* config/cpu/sparc/atomic_word.h: Likewise.
	* include/bits/atomicity.h: Define defaults.
	* config/cpu/ia64/atomic_word.h (__test_and_acquire)
	(__set_and_release): New inlines.
	(_GLIBCXX_GUARD_TEST_AND_ACQUIRE): Define.
	(_GLIBCXX_GUARD_SET_AND_RELEASE): Define.

	* libsupc++/guard.cc (acquire_1): Use __builtin_trap instead of
	abort();

*** ./gcc/config/alpha/alpha.c.~1~	2004-12-17 19:40:11.000000000 -0500
--- ./gcc/config/alpha/alpha.c	2004-12-23 19:37:36.903315760 -0500
*************** alpha_init_libfuncs (void)
*** 9460,9465 ****
--- 9460,9471 ----
  #undef TARGET_VECTORIZE_MISALIGNED_MEM_OK
  #define TARGET_VECTORIZE_MISALIGNED_MEM_OK alpha_vector_mode_supported_p
  
+ /* The Alpha architecture does not require sequential consistency.  See
+    http://www.cs.umd.edu/~pugh/java/memoryModel/AlphaReordering.html
+    for an example of how it can be violated in practice.  */
+ #undef TARGET_RELAXED_ORDERING
+ #define TARGET_RELAXED_ORDERING true
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  
*** ./gcc/config/ia64/ia64.c.~1~	2004-12-17 19:40:16.000000000 -0500
--- ./gcc/config/ia64/ia64.c	2004-12-23 19:36:09.584812402 -0500
*************** static const struct attribute_spec ia64_
*** 420,425 ****
--- 420,430 ----
  #undef TARGET_SCALAR_MODE_SUPPORTED_P
  #define TARGET_SCALAR_MODE_SUPPORTED_P ia64_scalar_mode_supported_p
  
+ /* ia64 architecture manual 4.4.7: ... reads, writes, and flushes may occur
+    in an order different from the specified program order.  */
+ #undef TARGET_RELAXED_ORDERING
+ #define TARGET_RELAXED_ORDERING true
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  typedef enum
*** ./gcc/config/rs6000/rs6000.c.~1~	2004-12-22 14:21:22.000000000 -0500
--- ./gcc/config/rs6000/rs6000.c	2004-12-23 19:38:07.756315329 -0500
*************** static const char alt_reg_names[][8] =
*** 1004,1009 ****
--- 1004,1020 ----
  #undef TARGET_VECTOR_MODE_SUPPORTED_P
  #define TARGET_VECTOR_MODE_SUPPORTED_P rs6000_vector_mode_supported_p
  
+ /* MPC604EUM 3.5.2 Weak Consistency between Multiple Processors
+    The PowerPC architecture requires only weak consistency among
+    processors--that is, memory accesses between processors need not be
+    sequentially consistent and memory accesses among processors can occur
+    in any order. The ability to order memory accesses weakly provides
+    opportunities for more efficient use of the system bus. Unless a
+    dependency exists, the 604e allows read operations to precede store
+    operations.  */
+ #undef TARGET_RELAXED_ORDERING
+ #define TARGET_RELAXED_ORDERING true
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  
*** ./gcc/config/sparc/sparc.c.~1~	2004-12-17 19:40:23.000000000 -0500
--- ./gcc/config/sparc/sparc.c	2004-12-23 19:38:26.477494447 -0500
*************** enum processor_type sparc_cpu;
*** 494,499 ****
--- 494,504 ----
  #define TARGET_ATTRIBUTE_TABLE sparc_attribute_table
  #endif
  
+ /* The SPARC architecture defines a relaxed memory ordering model (RMO)
+    which would require this, but it is never used in practice, and the
+    Ultra3 processors don't implement it; only the TSO model is used.  */
+ /* #define TARGET_RELAXED_ORDERING true */
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  /* Validate and override various options, and do some machine dependent
*** ./gcc/cp/decl.c.~1~	2004-12-22 14:22:26.000000000 -0500
--- ./gcc/cp/decl.c	2004-12-23 19:37:15.528394139 -0500
*************** expand_static_init (tree decl, tree init
*** 5312,5319 ****
    if (DECL_FUNCTION_SCOPE_P (decl))
      {
        /* Emit code to perform this initialization but once.  */
!       tree if_stmt, inner_if_stmt = NULL_TREE;
!       tree then_clause, inner_then_clause = NULL_TREE;
        tree guard, guard_addr, guard_addr_list;
        tree acquire_fn, release_fn, abort_fn;
        tree flag, begin;
--- 5312,5319 ----
    if (DECL_FUNCTION_SCOPE_P (decl))
      {
        /* Emit code to perform this initialization but once.  */
!       tree if_stmt = NULL_TREE, inner_if_stmt = NULL_TREE;
!       tree then_clause = NULL_TREE, inner_then_clause = NULL_TREE;
        tree guard, guard_addr, guard_addr_list;
        tree acquire_fn, release_fn, abort_fn;
        tree flag, begin;
*************** expand_static_init (tree decl, tree init
*** 5352,5361 ****
        /* Create the guard variable.  */
        guard = get_guard (decl);
  
!       /* Begin the conditional initialization.  */
!       if_stmt = begin_if_stmt ();
!       finish_if_stmt_cond (get_guard_cond (guard), if_stmt);
!       then_clause = begin_compound_stmt (BCS_NO_SCOPE);
  
        if (flag_threadsafe_statics)
  	{
--- 5352,5367 ----
        /* Create the guard variable.  */
        guard = get_guard (decl);
  
!       /* This optimization isn't safe on targets with relaxed memory
! 	 consistency.  On such targets we force synchronization in
! 	 __cxa_guard_acquire.  */
!       if (!targetm.relaxed_ordering || !flag_threadsafe_statics)
! 	{
! 	  /* Begin the conditional initialization.  */
! 	  if_stmt = begin_if_stmt ();
! 	  finish_if_stmt_cond (get_guard_cond (guard), if_stmt);
! 	  then_clause = begin_compound_stmt (BCS_NO_SCOPE);
! 	}
  
        if (flag_threadsafe_statics)
  	{
*************** expand_static_init (tree decl, tree init
*** 5418,5426 ****
  	  finish_if_stmt (inner_if_stmt);
  	}
  
!       finish_compound_stmt (then_clause);
!       finish_then_clause (if_stmt);
!       finish_if_stmt (if_stmt);
      }
    else
      static_aggregates = tree_cons (init, decl, static_aggregates);
--- 5424,5435 ----
  	  finish_if_stmt (inner_if_stmt);
  	}
  
!       if (!targetm.relaxed_ordering || !flag_threadsafe_statics)
! 	{
! 	  finish_compound_stmt (then_clause);
! 	  finish_then_clause (if_stmt);
! 	  finish_if_stmt (if_stmt);
! 	}
      }
    else
      static_aggregates = tree_cons (init, decl, static_aggregates);
*** ./gcc/doc/tm.texi.~1~	2004-12-22 14:22:26.000000000 -0500
--- ./gcc/doc/tm.texi	2004-12-22 14:15:13.000000000 -0500
*************** If defined, this macro is the number of 
*** 9584,9589 ****
--- 9584,9599 ----
  @code{TARGET_FORMAT_TYPES}.
  @end defmac
  
+ @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
+ If set to @code{true}, means that the target's memory model does not
+ guarantee that loads and stores which do not depend on one another
+ will access main memory in the order of the instruction stream; if
+ ordering is important, an explicit memory barrier must be used.  This
+ is true of many recent processors which implement a policy of
+ ``relaxed,'' ``weak,'' or ``release'' memory consistency, such as
+ Alpha, PowerPC, and ia64.  The default is @code{false}.
+ @end deftypefn
+ 
  @defmac TARGET_USE_JCR_SECTION
  This macro determines whether to use the JCR section to register Java
  classes. By default, TARGET_USE_JCR_SECTION is defined to 1 if both
*** ./gcc/target-def.h.~1~	2004-12-22 14:22:26.000000000 -0500
--- ./gcc/target-def.h	2004-12-22 14:15:18.000000000 -0500
*************** Foundation, 59 Temple Place - Suite 330,
*** 398,403 ****
--- 398,406 ----
  
  #define TARGET_GIMPLIFY_VA_ARG_EXPR std_gimplify_va_arg_expr
  #define TARGET_PASS_BY_REFERENCE hook_bool_CUMULATIVE_ARGS_mode_tree_bool_false
+ 
+ #define TARGET_RELAXED_ORDERING false
+ 
  #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size_or_pad
  #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_false
  
*************** Foundation, 59 Temple Place - Suite 330,
*** 537,542 ****
--- 540,546 ----
    TARGET_ASM_FILE_START_FILE_DIRECTIVE,		\
    TARGET_HANDLE_PRAGMA_REDEFINE_EXTNAME,	\
    TARGET_HANDLE_PRAGMA_EXTERN_PREFIX,		\
+   TARGET_RELAXED_ORDERING,			\
  }
  
  #include "hooks.h"
*** ./gcc/target.h.~1~	2004-12-22 14:22:26.000000000 -0500
--- ./gcc/target.h	2004-12-22 14:15:15.000000000 -0500
*************** struct gcc_target
*** 605,610 ****
--- 605,614 ----
    /* True if #pragma extern_prefix is to be supported.  */
    bool handle_pragma_extern_prefix;
  
+   /* True if the target is allowed to reorder memory accesses unless
+      synchronization is explicitly requested.  */
+   bool relaxed_ordering;
+ 
    /* Leave the boolean fields at the end.  */
  };
  
*** ./libstdc++-v3/config/cpu/alpha/atomic_word.h.~1~	2004-12-23 11:45:01.000000000 -0500
--- ./libstdc++-v3/config/cpu/alpha/atomic_word.h	2004-12-23 11:38:55.000000000 -0500
***************
*** 0 ****
--- 1,38 ----
+ // Low-level type for atomic operations -*- C++ -*-
+ 
+ // Copyright (C) 2004 Free Software Foundation, Inc.
+ //
+ // This file is part of the GNU ISO C++ Library.  This library 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.
+ 
+ // This library 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 this library; 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, you may use this file as part of a free software
+ // library without restriction.  Specifically, if other files instantiate
+ // templates or use macros or inline functions from this file, or you compile
+ // this file and link it with other files to produce an executable, this
+ // file 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.
+ 
+ #ifndef _GLIBCXX_ATOMIC_WORD_H
+ #define _GLIBCXX_ATOMIC_WORD_H	1
+ 
+ typedef int _Atomic_word;
+ 
+ #define _GLIBCXX_READ_MEM_BARRIER __asm __volatile ("mb":::"memory")
+ #define _GLIBCXX_WRITE_MEM_BARRIER __asm __volatile ("wmb":::"memory")
+ 
+ #endif 
*** ./libstdc++-v3/config/cpu/generic/cxxabi_tweaks.h.~1~	2004-12-22 14:22:26.000000000 -0500
--- ./libstdc++-v3/config/cpu/generic/cxxabi_tweaks.h	2004-12-23 11:39:30.000000000 -0500
*************** namespace __cxxabiv1
*** 36,43 ****
  #endif
  
    // The generic ABI uses the first byte of a 64-bit guard variable.
! #define _GLIBCXX_GUARD_ACQUIRE(x) (!*(char *) (x))
! #define _GLIBCXX_GUARD_RELEASE(x) *(char *) (x) = 1
    __extension__ typedef int __guard __attribute__((mode (__DI__)));
  
    // __cxa_vec_ctor has void return type.
--- 36,43 ----
  #endif
  
    // The generic ABI uses the first byte of a 64-bit guard variable.
! #define _GLIBCXX_GUARD_TEST(x) (*(char *) (x) != 0)
! #define _GLIBCXX_GUARD_SET(x) *(char *) (x) = 1
    __extension__ typedef int __guard __attribute__((mode (__DI__)));
  
    // __cxa_vec_ctor has void return type.
*** ./libstdc++-v3/config/cpu/generic/atomic_word.h.~1~	2004-02-26 19:49:46.000000000 -0500
--- ./libstdc++-v3/config/cpu/generic/atomic_word.h	2004-12-23 14:39:27.094607386 -0500
***************
*** 32,35 ****
--- 32,48 ----
  
  typedef int _Atomic_word;
  
+ // Define these two macros using the appropriate memory barrier insns iff
+ // TARGET_RELAXED_ORDERING is defined in tm.h.  The commented out versions
+ // below are the defaults.
+ // See ia64/atomic_word.h for an alternative approach.
+ 
+ // This one prevents loads from being hoisted across the barrier;
+ // in other words, this is a Load-Load acquire barrier.
+ // #define _GLIBCXX_READ_MEM_BARRIER __asm __volatile ("":::"memory")
+ 
+ // This one prevents stores from being sunk across the barrier; in other
+ // words, a Store-Store release barrier.
+ // #define _GLIBCXX_WRITE_MEM_BARRIER __asm __volatile ("":::"memory")
+ 
  #endif 
*** ./libstdc++-v3/config/cpu/ia64/atomic_word.h.~1~	2004-12-23 11:45:06.000000000 -0500
--- ./libstdc++-v3/config/cpu/ia64/atomic_word.h	2004-12-23 14:30:31.489390541 -0500
***************
*** 0 ****
--- 1,69 ----
+ // Low-level type for atomic operations -*- C++ -*-
+ 
+ // Copyright (C) 2004 Free Software Foundation, Inc.
+ //
+ // This file is part of the GNU ISO C++ Library.  This library 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.
+ 
+ // This library 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 this library; 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, you may use this file as part of a free software
+ // library without restriction.  Specifically, if other files instantiate
+ // templates or use macros or inline functions from this file, or you compile
+ // this file and link it with other files to produce an executable, this
+ // file 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.
+ 
+ #ifndef _GLIBCXX_ATOMIC_WORD_H
+ #define _GLIBCXX_ATOMIC_WORD_H	1
+ 
+ #include <cxxabi.h>
+ 
+ typedef int _Atomic_word;
+ 
+ namespace __gnu_cxx
+ {
+   // Test the first byte of __g and ensure that no loads are hoisted across
+   // the test.
+   inline bool
+   __test_and_acquire (__cxxabiv1::__guard *__g)
+   {
+     unsigned char __c;
+     unsigned char *__p = reinterpret_cast<unsigned char *>(__g);
+     // ldN.acq is a load with an implied hoist barrier.
+     // would ld8+mask be faster than just doing an ld1?
+     __asm __volatile ("ld1.acq %0 = %1" : "=r"(__c) : "m"(*__p) : "memory");
+     return __c != 0;
+   }
+ 
+   // Set the first byte of __g to 1 and ensure that no stores are sunk
+   // across the store.
+   inline void
+   __set_and_release (__cxxabiv1::__guard *__g)
+   {
+     unsigned char *__p = reinterpret_cast<unsigned char *>(__g);
+     // stN.rel is a store with an implied sink barrier.
+     // could load word, set flag, and CAS it back
+     __asm __volatile ("st1.rel %0 = %1" : "=m"(*__p) : "r"(1) : "memory");
+   }
+ 
+   // We don't define the _BARRIER macros on ia64 because the barriers are
+   // included in the test and set, above.
+ #define _GLIBCXX_GUARD_TEST_AND_ACQUIRE(G) __gnu_cxx::__test_and_acquire (G)
+ #define _GLIBCXX_GUARD_SET_AND_RELEASE(G) __gnu_cxx::__set_and_release (G)
+ }
+ 
+ #endif 
*** ./libstdc++-v3/config/cpu/powerpc/atomic_word.h.~1~	2004-12-23 11:44:56.144990549 -0500
--- ./libstdc++-v3/config/cpu/powerpc/atomic_word.h	2004-12-23 11:40:21.113821732 -0500
***************
*** 0 ****
--- 1,38 ----
+ // Low-level type for atomic operations -*- C++ -*-
+ 
+ // Copyright (C) 2004 Free Software Foundation, Inc.
+ //
+ // This file is part of the GNU ISO C++ Library.  This library 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.
+ 
+ // This library 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 this library; 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, you may use this file as part of a free software
+ // library without restriction.  Specifically, if other files instantiate
+ // templates or use macros or inline functions from this file, or you compile
+ // this file and link it with other files to produce an executable, this
+ // file 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.
+ 
+ #ifndef _GLIBCXX_ATOMIC_WORD_H
+ #define _GLIBCXX_ATOMIC_WORD_H	1
+ 
+ typedef int _Atomic_word;
+ 
+ #define _GLIBCXX_READ_MEM_BARRIER __asm __volatile ("isync":::"memory")
+ #define _GLIBCXX_WRITE_MEM_BARRIER __asm __volatile ("lwsync":::"memory")
+ 
+ #endif 
*** ./libstdc++-v3/config/cpu/sparc/atomic_word.h.~1~	2004-02-26 19:49:48.000000000 -0500
--- ./libstdc++-v3/config/cpu/sparc/atomic_word.h	2004-12-23 11:41:23.000000000 -0500
***************
*** 36,39 ****
--- 36,46 ----
    typedef int _Atomic_word;
  #endif
  
+ // These are only necessary under the V9 RMO model, which is never used;
+ // the Ultra3 only supports TSO.
+ // #define _GLIBCXX_READ_MEM_BARRIER \
+ //  __asm __volatile ("membar #LoadLoad":::"memory")
+ // #define _GLIBCXX_WRITE_MEM_BARRIER \
+ //  __asm __volatile ("membar #StoreStore":::"memory")
+ 
  #endif 
*** ./libstdc++-v3/config/cpu/arm/cxxabi_tweaks.h.~1~	2004-12-22 14:22:26.000000000 -0500
--- ./libstdc++-v3/config/cpu/arm/cxxabi_tweaks.h	2004-09-27 15:39:13.000000000 -0400
*************** namespace __cxxabiv1
*** 38,45 ****
  #ifdef __ARM_EABI__
    // The ARM EABI uses the least significant bit of a 32-bit
    // guard variable.  */
! #define _GLIBCXX_GUARD_ACQUIRE(x) (!(*(x) & 1))
! #define _GLIBCXX_GUARD_RELEASE(x) *(x) = 1
    typedef int __guard;
  
    // We also want the element size in array cookies.
--- 38,45 ----
  #ifdef __ARM_EABI__
    // The ARM EABI uses the least significant bit of a 32-bit
    // guard variable.  */
! #define _GLIBCXX_GUARD_TEST(x) ((*(x) & 1) != 0)
! #define _GLIBCXX_GUARD_SET(x) *(x) = 1
    typedef int __guard;
  
    // We also want the element size in array cookies.
*************** namespace __cxxabiv1
*** 54,61 ****
  #else // __ARM_EABI__
  
    // The generic ABI uses the first byte of a 64-bit guard variable.
! #define _GLIBCXX_GUARD_ACQUIRE(x) (!*(char *) (x))
! #define _GLIBCXX_GUARD_RELEASE(x) *(char *) (x) = 1
    __extension__ typedef int __guard __attribute__((mode (__DI__)));
  
    // __cxa_vec_ctor has void return type.
--- 54,61 ----
  #else // __ARM_EABI__
  
    // The generic ABI uses the first byte of a 64-bit guard variable.
! #define _GLIBCXX_GUARD_TEST(x) (*(char *) (x) != 0)
! #define _GLIBCXX_GUARD_SET(x) *(char *) (x) = 1
    __extension__ typedef int __guard __attribute__((mode (__DI__)));
  
    // __cxa_vec_ctor has void return type.
*** ./libstdc++-v3/include/bits/atomicity.h.~1~	2004-12-17 19:42:45.000000000 -0500
--- ./libstdc++-v3/include/bits/atomicity.h	2004-12-23 11:36:29.000000000 -0500
*************** namespace __gnu_cxx
*** 48,51 ****
--- 48,60 ----
    __atomic_add(volatile _Atomic_word* __mem, int __val);
  } // namespace __gnu_cxx
  
+ /* Even if the CPU doesn't need a memory barrier, we need to ensure that
+    the compiler doesn't reorder memory accesses across the barriers.  */
+ #ifndef _GLIBCXX_READ_MEM_BARRIER
+ #define _GLIBCXX_READ_MEM_BARRIER __asm __volatile ("":::"memory")
+ #endif
+ #ifndef _GLIBCXX_WRITE_MEM_BARRIER
+ #define _GLIBCXX_WRITE_MEM_BARRIER __asm __volatile ("":::"memory")
+ #endif
+ 
  #endif 
*** ./libstdc++-v3/libsupc++/guard.cc.~1~	2004-12-22 14:22:26.000000000 -0500
--- ./libstdc++-v3/libsupc++/guard.cc	2004-12-23 11:44:01.000000000 -0500
***************
*** 27,37 ****
--- 27,39 ----
  // the GNU General Public License.
  
  // Written by Mark Mitchell, CodeSourcery LLC, <mark@codesourcery.com>
+ // Thread support written by Jason Merrill, Red Hat Inc. <jason@redhat.com>
  
  #include <cxxabi.h>
  #include <exception>
  #include <bits/c++config.h>
  #include <bits/gthr.h>
+ #include <bits/atomicity.h>
  
  // The IA64/generic ABI uses the first byte of the guard variable.
  // The ARM EABI uses the least significant bit.
*************** namespace
*** 84,91 ****
--- 86,121 ----
      __gthread_recursive_mutex_unlock (&mutex);
    }
  }
+ 
+ #ifndef _GLIBCXX_GUARD_TEST_AND_ACQUIRE
+ inline bool
+ __test_and_acquire (__cxxabiv1::__guard *g)
+ {
+   bool b = _GLIBCXX_GUARD_TEST (g);
+   _GLIBCXX_READ_MEM_BARRIER;
+   return b;
+ }
+ #define _GLIBCXX_GUARD_TEST_AND_ACQUIRE(G) __test_and_acquire (G)
  #endif
  
+ #ifndef _GLIBCXX_GUARD_SET_AND_RELEASE
+ inline void
+ __set_and_release (__cxxabiv1::__guard *g)
+ {
+   _GLIBCXX_WRITE_MEM_BARRIER;
+   _GLIBCXX_GUARD_SET (g);
+ }
+ #define _GLIBCXX_GUARD_SET_AND_RELEASE(G) __set_and_release (G)
+ #endif
+ 
+ #else /* !__GTHREADS */
+ 
+ #undef _GLIBCXX_GUARD_TEST_AND_ACQUIRE
+ #undef _GLIBCXX_GUARD_SET_AND_RELEASE
+ #define _GLIBCXX_GUARD_SET_AND_RELEASE(G) _GLIBCXX_GUARD_SET (G)
+ 
+ #endif /* __GTHREADS */
+ 
  namespace __gnu_cxx
  {
    // 6.7[stmt.dcl]/4: If control re-enters the declaration (recursively)
*************** namespace __gnu_cxx
*** 107,134 ****
  
  namespace __cxxabiv1 
  {
    static int
    acquire_1 (__guard *g)
    {
!     if (_GLIBCXX_GUARD_ACQUIRE (g))
        {
- 	if (((char *)g)[1]++)
- 	  {
  #ifdef __EXCEPTIONS
! 	    throw __gnu_cxx::recursive_init();
  #else
! 	    abort ();
  #endif
- 	  }
- 	return 1;
        }
!     return 0;
    }
!   
    extern "C"
    int __cxa_guard_acquire (__guard *g) 
    {
  #ifdef __GTHREADS
      if (__gthread_active_p ())
        {
  	// Simple wrapper for exception safety.
--- 137,182 ----
  
  namespace __cxxabiv1 
  {
+   static inline int
+   recursion_push (__guard* g)
+   {
+     return ((char *)g)[1]++;
+   }
+ 
+   static inline void
+   recursion_pop (__guard* g)
+   {
+     --((char *)g)[1];
+   }
+ 
    static int
    acquire_1 (__guard *g)
    {
!     if (_GLIBCXX_GUARD_TEST (g))
!       return 0;
! 
!     if (recursion_push (g))
        {
  #ifdef __EXCEPTIONS
! 	throw __gnu_cxx::recursive_init();
  #else
! 	// Use __builtin_trap so we don't require abort().
! 	__builtin_trap ();
  #endif
        }
!     return 1;
    }
! 
    extern "C"
    int __cxa_guard_acquire (__guard *g) 
    {
  #ifdef __GTHREADS
+     // If the target can reorder loads, we need to insert a read memory
+     // barrier so that accesses to the guarded variable happen after the
+     // guard test.
+     if (_GLIBCXX_GUARD_TEST_AND_ACQUIRE (g))
+       return 0;
+ 
      if (__gthread_active_p ())
        {
  	// Simple wrapper for exception safety.
*************** namespace __cxxabiv1 
*** 162,168 ****
    extern "C"
    void __cxa_guard_abort (__guard *g)
    {
!     ((char *)g)[1]--;
  #ifdef __GTHREADS
      if (__gthread_active_p ())
        static_mutex::unlock ();
--- 210,216 ----
    extern "C"
    void __cxa_guard_abort (__guard *g)
    {
!     recursion_pop (g);
  #ifdef __GTHREADS
      if (__gthread_active_p ())
        static_mutex::unlock ();
*************** namespace __cxxabiv1 
*** 172,179 ****
    extern "C"
    void __cxa_guard_release (__guard *g)
    {
!     ((char *)g)[1]--;
!     _GLIBCXX_GUARD_RELEASE (g);
  #ifdef __GTHREADS
      if (__gthread_active_p ())
        static_mutex::unlock ();
--- 220,227 ----
    extern "C"
    void __cxa_guard_release (__guard *g)
    {
!     recursion_pop (g);
!     _GLIBCXX_GUARD_SET_AND_RELEASE (g);
  #ifdef __GTHREADS
      if (__gthread_active_p ())
        static_mutex::unlock ();

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