diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8cc43d3097329f493a010d99cc006c231255a042..6c6860be8dbb75728c345b05ab102e93a39138ab 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2004-12-27 Jason Merrill <jason@redhat.com> + + * 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): Define. + 2004-12-27 Roger Sayle <roger@eyesopen.com> PR driver/16118 diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index 823cdbc18c4008919269bd545fc1109976ee9001..042ffa6abcc697e21c69cf427112d4a19bb909ab 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -9462,6 +9462,12 @@ alpha_init_libfuncs (void) #undef TARGET_BUILD_BUILTIN_VA_LIST #define TARGET_BUILD_BUILTIN_VA_LIST alpha_build_builtin_va_list +/* 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; diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 64a4e54a56ca207a2192e978bf38dcbf2a7de6a3..332fa9be3ccaa82aaced39af90a2461d17dc42ae 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -420,6 +420,11 @@ static const struct attribute_spec ia64_attribute_table[] = #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 diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index cf7c8eec816bb4523132c12f264724ad20c4170b..95a7b1619bf7fce9d3c2f4893bbb3d1fa2ae5a17 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -1004,6 +1004,17 @@ static const char alt_reg_names[][8] = #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; diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 0eff775bbb21c26f840e5f0ca0a0538f7bf9a672..dd83f544b4f7dd64848ab55763e81fa118357223 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -494,6 +494,11 @@ enum processor_type sparc_cpu; #define TARGET_ATTRIBUTE_TABLE sparc_attribute_table #endif +/* The SPARC v9 architecture defines a relaxed memory ordering model (RMO) + which requires this if enabled, though it is never used in userspace, + and the Ultra3 processors don't implement it. */ +#define TARGET_RELAXED_ORDERING TARGET_V9 + struct gcc_target targetm = TARGET_INITIALIZER; /* Validate and override various options, and do some machine dependent diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a62a61e565c67a4ef095c1d323edf4f0df6b507e..622a0012a13ba1fdd9a2688084c8dac0608c2ba5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2004-12-27 Jason Merrill <jason@redhat.com> + + * decl.c (expand_static_init): Don't use shortcut if + targetm.relaxed_ordering. + 2004-12-27 Mark Mitchell <mark@codesourcery.com> PR c++/19149 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 991996bc3f56f8d3b5c9ffa242b1df7ed337c591..7a839d7f3bfc9acc0bef302a103ec9142264a26c 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5313,8 +5313,8 @@ expand_static_init (tree decl, tree init) 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 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; @@ -5353,10 +5353,16 @@ expand_static_init (tree decl, tree init) /* 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); + /* 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) { @@ -5419,9 +5425,12 @@ expand_static_init (tree decl, tree init) finish_if_stmt (inner_if_stmt); } - finish_compound_stmt (then_clause); - finish_then_clause (if_stmt); - finish_if_stmt (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); diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index fb45a6c8ea3d6b8d29094222a2fedfb72869c039..abcf7071763ecaf14f0ceb6d1fa805c9b06c030e 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -9574,6 +9574,16 @@ If defined, this macro is the number of entries in @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 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 diff --git a/gcc/target-def.h b/gcc/target-def.h index 75c949e9e2973bd81c7d193ed5a913ae2b46ade4..cd333c3b5e6ac9cc849640a0032e40a327ca8f07 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -394,6 +394,9 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #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 @@ -533,6 +536,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. TARGET_ASM_FILE_START_FILE_DIRECTIVE, \ TARGET_HANDLE_PRAGMA_REDEFINE_EXTNAME, \ TARGET_HANDLE_PRAGMA_EXTERN_PREFIX, \ + TARGET_RELAXED_ORDERING, \ } #include "hooks.h" diff --git a/gcc/target.h b/gcc/target.h index 4f4b49ebb51265bb9c48ce1c9eea81192880e978..9ad460c18c9309c15c178822756447f4fef259c6 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -598,6 +598,10 @@ struct gcc_target /* 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. */ }; diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index ba4b65ec707b4f8d0931b26c023b3de832c9363a..da33b5de852ed90cc2eb7f598ce09a8e8b424192 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,31 @@ +2004-12-27 Jason Merrill <jason@redhat.com> + + Add memory barriers to the double-checked locking used for static + initialization. + * 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/sparc/atomic_word.h: Likewise. + * config/cpu/generic/atomic_word.h: Define them, commented out. + * 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(); + 2004-12-27 Paolo Carlini <pcarlini@suse.de> * include/tr1/type_traits: Rework the _DEFINE_SPEC* macros. diff --git a/libstdc++-v3/config/cpu/alpha/atomic_word.h b/libstdc++-v3/config/cpu/alpha/atomic_word.h new file mode 100644 index 0000000000000000000000000000000000000000..254e3d9ecb3053d3ef9cbe9899259fd9f6c47208 --- /dev/null +++ b/libstdc++-v3/config/cpu/alpha/atomic_word.h @@ -0,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 diff --git a/libstdc++-v3/config/cpu/arm/cxxabi_tweaks.h b/libstdc++-v3/config/cpu/arm/cxxabi_tweaks.h index 06c16fa3993bc04cc9daaa4da421474ef4d6018b..39a10436c2e2f8676174668bbd4259bde9d7c88e 100644 --- a/libstdc++-v3/config/cpu/arm/cxxabi_tweaks.h +++ b/libstdc++-v3/config/cpu/arm/cxxabi_tweaks.h @@ -38,8 +38,8 @@ namespace __cxxabiv1 #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 +#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. @@ -54,8 +54,8 @@ namespace __cxxabiv1 #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 +#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. diff --git a/libstdc++-v3/config/cpu/generic/atomic_word.h b/libstdc++-v3/config/cpu/generic/atomic_word.h index b46adc2a4743efc75af3f53e4f6b607697625d3b..f03f1ecbce13d7df1dc891e3ec3ca244a3a4a174 100644 --- a/libstdc++-v3/config/cpu/generic/atomic_word.h +++ b/libstdc++-v3/config/cpu/generic/atomic_word.h @@ -32,4 +32,17 @@ typedef int _Atomic_word; +// Define these two macros using the appropriate memory barrier for the target. +// 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. +// This is necessary iff TARGET_RELAXED_ORDERING is defined in tm.h. +// #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 diff --git a/libstdc++-v3/config/cpu/generic/cxxabi_tweaks.h b/libstdc++-v3/config/cpu/generic/cxxabi_tweaks.h index 5cacb3c5531a20d3028a3a7586d05787c1a0987f..b5808a265dc14d795f439822a4f6d213674c5d28 100644 --- a/libstdc++-v3/config/cpu/generic/cxxabi_tweaks.h +++ b/libstdc++-v3/config/cpu/generic/cxxabi_tweaks.h @@ -36,8 +36,8 @@ namespace __cxxabiv1 #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 +#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. diff --git a/libstdc++-v3/config/cpu/ia64/atomic_word.h b/libstdc++-v3/config/cpu/ia64/atomic_word.h new file mode 100644 index 0000000000000000000000000000000000000000..2e49e2707368b6063469b548e7d4e3acbc472a45 --- /dev/null +++ b/libstdc++-v3/config/cpu/ia64/atomic_word.h @@ -0,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 diff --git a/libstdc++-v3/config/cpu/powerpc/atomic_word.h b/libstdc++-v3/config/cpu/powerpc/atomic_word.h new file mode 100644 index 0000000000000000000000000000000000000000..ff418cc540db87c4d9e31a6cd977dab4ba778a4f --- /dev/null +++ b/libstdc++-v3/config/cpu/powerpc/atomic_word.h @@ -0,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 diff --git a/libstdc++-v3/config/cpu/sparc/atomic_word.h b/libstdc++-v3/config/cpu/sparc/atomic_word.h index 941fddd2b0e518832ac5914419578998cfc057eb..59b1a2c9df673fc24ebdd5652b148ea4d3a23689 100644 --- a/libstdc++-v3/config/cpu/sparc/atomic_word.h +++ b/libstdc++-v3/config/cpu/sparc/atomic_word.h @@ -36,4 +36,18 @@ typedef int _Atomic_word; #endif +#if defined(__sparc_v9__) +// These are necessary under the V9 RMO model, though it is almost never +// used in userspace. +#define _GLIBCXX_READ_MEM_BARRIER \ + __asm __volatile ("membar #LoadLoad":::"memory") +#define _GLIBCXX_WRITE_MEM_BARRIER \ + __asm __volatile ("membar #StoreStore":::"memory") + +#elif defined(__sparc_v8__) +// This is necessary under the PSO model. +#define _GLIBCXX_WRITE_MEM_BARRIER __asm __volatile ("stbar":::"memory") + +#endif + #endif diff --git a/libstdc++-v3/include/bits/atomicity.h b/libstdc++-v3/include/bits/atomicity.h index 932efe931ce3c733e72e662ccef40416157f6871..9ad25e0f34295c595e2f4061ea11184031b403d6 100644 --- a/libstdc++-v3/include/bits/atomicity.h +++ b/libstdc++-v3/include/bits/atomicity.h @@ -48,4 +48,13 @@ namespace __gnu_cxx __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 diff --git a/libstdc++-v3/libsupc++/guard.cc b/libstdc++-v3/libsupc++/guard.cc index a9280bccdc54c548ef915b2aefe7e8f11346b6c7..e9e147037704bcadddc7c17bb4b13f970e505f85 100644 --- a/libstdc++-v3/libsupc++/guard.cc +++ b/libstdc++-v3/libsupc++/guard.cc @@ -27,11 +27,13 @@ // 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. @@ -84,8 +86,36 @@ namespace __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) @@ -107,28 +137,46 @@ namespace __gnu_cxx 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_ACQUIRE (g)) + if (_GLIBCXX_GUARD_TEST (g)) + return 0; + + if (recursion_push (g)) { - if (((char *)g)[1]++) - { #ifdef __EXCEPTIONS - throw __gnu_cxx::recursive_init(); + throw __gnu_cxx::recursive_init(); #else - abort (); + // Use __builtin_trap so we don't require abort(). + __builtin_trap (); #endif - } - return 1; } - return 0; + 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. @@ -162,7 +210,7 @@ namespace __cxxabiv1 extern "C" void __cxa_guard_abort (__guard *g) { - ((char *)g)[1]--; + recursion_pop (g); #ifdef __GTHREADS if (__gthread_active_p ()) static_mutex::unlock (); @@ -172,8 +220,8 @@ namespace __cxxabiv1 extern "C" void __cxa_guard_release (__guard *g) { - ((char *)g)[1]--; - _GLIBCXX_GUARD_RELEASE (g); + recursion_pop (g); + _GLIBCXX_GUARD_SET_AND_RELEASE (g); #ifdef __GTHREADS if (__gthread_active_p ()) static_mutex::unlock ();