On 21/06/19 13:01 -0400, Nathan Sidwell wrote:
On 6/21/19 12:01 PM, Jonathan Wakely wrote:
Nathan noticed that the 'static inline' functions in <ext/atomicity.h>
cause ODR violations when used from inline functions or templates (see
[basic.def.odr] p12 bullet (12.2)). His modules branch now diagnoses
those violations, so we need a fix.
Looking at the history (r114044 by Paolo) I believe the idea was indeed
to allow different definitions to be used in different TUs. I think
__attribute__((__always_inline__)) is a better match for that than
'static inline', and doesn't violate the ODR (at least, not if all TUs
have the same values for __GTHREADS and _GLIBCXX_ATOMIC_BUILTINS).
These functions still violate this rule in [dcl.inline]:
C++17: "If a function with external linkage is declared inline in one
translation unit, it shall be declared inline in all translation units
in which it appears; no diagnostic is required."
C++2a WP: "If a function or variable with external or module linkage
is declared inline in one translation unit, there shall be a reachable
inline declaration in all translation units in which it is declared;
no diagnostic is required."
But that doesn't seem to be diagnosable by today's implementations.
Does this change seem reasonable?
yes, thanks!
Actually, I think I prefer this version. This produces identical code
to the always_inline version, but without the indirection to
additional inline functions, i.e. just inline the relevant code into
the _dispatch functions.
Tests are still running but no failures so far, as expected.
commit 56040dad3b55a98f6e5090d04cb49945c40df39c
Author: Jonathan Wakely <jwak...@redhat.com>
Date: Fri Jun 21 17:52:23 2019 +0100
Simplify
diff --git a/libstdc++-v3/include/ext/atomicity.h b/libstdc++-v3/include/ext/atomicity.h
index 0783a58e01a..30453c92315 100644
--- a/libstdc++-v3/include/ext/atomicity.h
+++ b/libstdc++-v3/include/ext/atomicity.h
@@ -43,62 +43,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// To abstract locking primitives across all thread policies, use:
// __exchange_and_add_dispatch
// __atomic_add_dispatch
-#ifdef _GLIBCXX_ATOMIC_BUILTINS
- static inline _Atomic_word
- __exchange_and_add(volatile _Atomic_word* __mem, int __val)
- { return __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); }
-
- static inline void
- __atomic_add(volatile _Atomic_word* __mem, int __val)
- { __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); }
-#else
+#ifndef _GLIBCXX_ATOMIC_BUILTINS
_Atomic_word
- __attribute__ ((__unused__))
__exchange_and_add(volatile _Atomic_word*, int) throw ();
void
- __attribute__ ((__unused__))
__atomic_add(volatile _Atomic_word*, int) throw ();
#endif
- static inline _Atomic_word
- __exchange_and_add_single(_Atomic_word* __mem, int __val)
+ inline _Atomic_word
+ __attribute__ ((__always_inline__))
+ __exchange_and_add_dispatch(_Atomic_word* __mem, int __val)
{
+#ifdef __GTHREADS
+ if (__gthread_active_p())
+ {
+#ifdef _GLIBCXX_ATOMIC_BUILTINS
+ return __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL);
+#else
+ return __exchange_and_add(__mem, __val);
+#endif
+ }
+#endif
_Atomic_word __result = *__mem;
*__mem += __val;
return __result;
}
- static inline void
- __atomic_add_single(_Atomic_word* __mem, int __val)
- { *__mem += __val; }
-
- static inline _Atomic_word
- __attribute__ ((__unused__))
- __exchange_and_add_dispatch(_Atomic_word* __mem, int __val)
- {
-#ifdef __GTHREADS
- if (__gthread_active_p())
- return __exchange_and_add(__mem, __val);
- else
- return __exchange_and_add_single(__mem, __val);
-#else
- return __exchange_and_add_single(__mem, __val);
-#endif
- }
-
- static inline void
- __attribute__ ((__unused__))
+ inline void
+ __attribute__ ((__always_inline__))
__atomic_add_dispatch(_Atomic_word* __mem, int __val)
{
#ifdef __GTHREADS
if (__gthread_active_p())
- __atomic_add(__mem, __val);
- else
- __atomic_add_single(__mem, __val);
+ {
+#ifdef _GLIBCXX_ATOMIC_BUILTINS
+ __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL);
#else
- __atomic_add_single(__mem, __val);
+ __atomic_add(__mem, __val);
#endif
+ }
+ else
+#endif
+ *__mem += __val;
}
_GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/src/c++98/mt_allocator.cc b/libstdc++-v3/src/c++98/mt_allocator.cc
index f842c6f9cfd..9b26f3dc993 100644
--- a/libstdc++-v3/src/c++98/mt_allocator.cc
+++ b/libstdc++-v3/src/c++98/mt_allocator.cc
@@ -302,7 +302,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__reclaimed > 1024)
{
__bin._M_used[__thread_id] -= __reclaimed;
- __atomic_add(&__reclaimed_base[__thread_id], -__reclaimed);
+ __atomic_fetch_add(&__reclaimed_base[__thread_id], -__reclaimed,
+ __ATOMIC_ACQ_REL);
}
if (__remove >= __net_used)
@@ -332,7 +333,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__block->_M_thread_id == __thread_id)
--__bin._M_used[__thread_id];
else
- __atomic_add(&__reclaimed_base[__block->_M_thread_id], 1);
+ __atomic_fetch_add(&__reclaimed_base[__block->_M_thread_id], 1,
+ __ATOMIC_ACQ_REL);
__block->_M_next = __bin._M_first[__thread_id];
__bin._M_first[__thread_id] = __block;
@@ -379,7 +381,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
reinterpret_cast<_Atomic_word*>(__bin._M_used + __max_threads);
const _Atomic_word __reclaimed = __reclaimed_base[__thread_id];
__bin._M_used[__thread_id] -= __reclaimed;
- __atomic_add(&__reclaimed_base[__thread_id], -__reclaimed);
+ __atomic_fetch_add(&__reclaimed_base[__thread_id], -__reclaimed,
+ __ATOMIC_ACQ_REL);
__gthread_mutex_lock(__bin._M_mutex);
if (__bin._M_first[0] == 0)