diff mbox

[libstdc++/65033] Give alignment info to libatomic

Message ID 54DD19B7.6060401@redhat.com
State New
Headers show

Commit Message

Richard Henderson Feb. 12, 2015, 9:23 p.m. UTC
When we fixed PR54005, making sure that atomic_is_lock_free returns the same
value for all objects of a given type, we probably should have changed the
interface so that we would pass size and alignment rather than size and object
pointer.

Instead, we decided that passing null for the object pointer would be
sufficient.  But as this PR shows, we really do need to take alignment into
account.

The following patch constructs a fake object pointer that is maximally
misaligned.  This allows the interface to both the builtin and to libatomic to
remain unchanged.  Which probably makes this back-portable to maintenance
releases as well.

I believe that for all of our current systems, size_t == uintptr_t, so the
reinterpret_cast ought not generate warnings.

The test case is problematic, as there's currently no good place to put it.
The libstdc++ testsuite doesn't have the libatomic library path configured, and
the libatomic testsuite doesn't have the libstdc++ include paths configured.
Yet another example where we really need an install tree for testing.  Thoughts?


Ok?


r~
* include/bits/atomic_base.h (__atomic_base<T>::is_lock_free): Build
	a fake pointer indicating type alignment.
	(__atomic_base<T *>::is_lock_free): Likewise.
	* include/std/atomic (atomic<T>::is_lock_free): Likewise.

Comments

Jonathan Wakely Feb. 18, 2015, 12:15 p.m. UTC | #1
On 12/02/15 13:23 -0800, Richard Henderson wrote:
>When we fixed PR54005, making sure that atomic_is_lock_free returns the same
>value for all objects of a given type, we probably should have changed the
>interface so that we would pass size and alignment rather than size and object
>pointer.
>
>Instead, we decided that passing null for the object pointer would be
>sufficient.  But as this PR shows, we really do need to take alignment into
>account.
>
>The following patch constructs a fake object pointer that is maximally
>misaligned.  This allows the interface to both the builtin and to libatomic to
>remain unchanged.  Which probably makes this back-portable to maintenance
>releases as well.

Am I right in thinking that another option would be to ensure that
std::atomic<> objects are always suitably aligned? Would that make
std::atomic<> slightly more compatible with a C11 atomic_int, where
the _Atomic qualifier affects alignment?

https://gcc.gnu.org/PR62259 suggests we might need to enforce
alignment on std::atomic anyway, or am I barking up the wrong tree?
Jonathan Wakely March 26, 2015, 11:54 a.m. UTC | #2
On 12/02/15 13:23 -0800, Richard Henderson wrote:
>When we fixed PR54005, making sure that atomic_is_lock_free returns the same
>value for all objects of a given type, we probably should have changed the
>interface so that we would pass size and alignment rather than size and object
>pointer.
>
>Instead, we decided that passing null for the object pointer would be
>sufficient.  But as this PR shows, we really do need to take alignment into
>account.
>
>The following patch constructs a fake object pointer that is maximally
>misaligned.  This allows the interface to both the builtin and to libatomic to
>remain unchanged.  Which probably makes this back-portable to maintenance
>releases as well.
>
>I believe that for all of our current systems, size_t == uintptr_t, so the
>reinterpret_cast ought not generate warnings.
>
>The test case is problematic, as there's currently no good place to put it.
>The libstdc++ testsuite doesn't have the libatomic library path configured, and
>the libatomic testsuite doesn't have the libstdc++ include paths configured.
>Yet another example where we really need an install tree for testing.  Thoughts?
>
>
>Ok?

OK for trunk.

>
>r~

>	* include/bits/atomic_base.h (__atomic_base<T>::is_lock_free): Build
>	a fake pointer indicating type alignment.
>	(__atomic_base<T *>::is_lock_free): Likewise.
>	* include/std/atomic (atomic<T>::is_lock_free): Likewise.
Hans-Peter Nilsson April 3, 2015, 3:57 a.m. UTC | #3
On Thu, 12 Feb 2015, Richard Henderson wrote:
> When we fixed PR54005,

Hm, there's confusion.  When was this fixed?  (Not fixed
AFAICT.)  Maybe you mean PR54004, but there was no note there
either.  Or maybe there's a typo and you meant some other PR and
that PR54005 is supposedly fixed by this patch (committed as
r221701)

...but it doesn't seem right: you use a specific object when
deducing the alignment for the fake-pointer, so it's used anyway
and is_lock_free must not be object-specific (despite its name)
and only type-specific as mandated by the standard (see PR).

To wit, deduce from the known-alignment of _Tp, not
known-alignment of _M_i. Or is this what happens; they're the
same?  Why then use __alignof(_M_i) (the object-alignment)
instead of _S_alignment (the deduced alas insufficiently
increased type-alignment)?

> making sure that atomic_is_lock_free returns the same
> value for all objects of a given type,

(That would work but it doesn't seem to be the case.)

> we probably should have changed the
> interface so that we would pass size and alignment rather than size and object
> pointer.
>
> Instead, we decided that passing null for the object pointer would be
> sufficient.  But as this PR shows, we really do need to take alignment into
> account.

Regarding what's actually needed, alignment of an atomic type
should always be *forced to be at least the natural alignment of
of the object* (with non-power-of-two sized-objects rounded up)
and until then atomic types won't work for targets where the
non-atomic equivalents have less alignment (as straddling a
page-boundary won't be lock-less-atomic anywhere where
straddling a page-boundary may cause a non-atomic-access...) So,
not target-specific except for targets that require even
higher-than-natural alignment.

> The following patch constructs a fake object pointer that is maximally
> misaligned.

(With regards to the known object alignment of the _M_i object.)

>  This allows the interface to both the builtin and to libatomic to
> remain unchanged.  Which probably makes this back-portable to maintenance
> releases as well.
>
> I believe that for all of our current systems, size_t == uintptr_t, so the
> reinterpret_cast ought not generate warnings.
>
> The test case is problematic, as there's currently no good place to put it.
> The libstdc++ testsuite doesn't have the libatomic library path configured, and
> the libatomic testsuite doesn't have the libstdc++ include paths configured.
> Yet another example where we really need an install tree for testing.  Thoughts?

brgds, H-P
diff mbox

Patch

diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index fe6524f..8104c98 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -346,11 +346,19 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       bool
       is_lock_free() const noexcept
-      { return __atomic_is_lock_free(sizeof(_M_i), nullptr); }
+      {
+	// Produce a fake, minimally aligned pointer.
+	void *__a = reinterpret_cast<void *>(-__alignof(_M_i));
+	return __atomic_is_lock_free(sizeof(_M_i), __a);
+      }
 
       bool
       is_lock_free() const volatile noexcept
-      { return __atomic_is_lock_free(sizeof(_M_i), nullptr); }
+      {
+	// Produce a fake, minimally aligned pointer.
+	void *__a = reinterpret_cast<void *>(-__alignof(_M_i));
+	return __atomic_is_lock_free(sizeof(_M_i), __a);
+      }
 
       _GLIBCXX_ALWAYS_INLINE void
       store(__int_type __i, memory_order __m = memory_order_seq_cst) noexcept
@@ -653,11 +661,19 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       bool
       is_lock_free() const noexcept
-      { return __atomic_is_lock_free(sizeof(__pointer_type), nullptr); }
+      {
+	// Produce a fake, minimally aligned pointer.
+	void *__a = reinterpret_cast<void *>(-__alignof(_M_p));
+	return __atomic_is_lock_free(sizeof(_M_p), __a);
+      }
 
       bool
       is_lock_free() const volatile noexcept
-      { return __atomic_is_lock_free(sizeof(__pointer_type), nullptr); }
+      {
+	// Produce a fake, minimally aligned pointer.
+	void *__a = reinterpret_cast<void *>(-__alignof(_M_p));
+	return __atomic_is_lock_free(sizeof(_M_p), __a);
+      }
 
       _GLIBCXX_ALWAYS_INLINE void
       store(__pointer_type __p,
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 1a17427..cc4b5f1 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -198,11 +198,19 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       bool
       is_lock_free() const noexcept
-      { return __atomic_is_lock_free(sizeof(_M_i), nullptr); }
+      {
+	// Produce a fake, minimally aligned pointer.
+	void *__a = reinterpret_cast<void *>(-__alignof(_M_i));
+	return __atomic_is_lock_free(sizeof(_M_i), __a);
+      }
 
       bool
       is_lock_free() const volatile noexcept
-      { return __atomic_is_lock_free(sizeof(_M_i), nullptr); }
+      {
+	// Produce a fake, minimally aligned pointer.
+	void *__a = reinterpret_cast<void *>(-__alignof(_M_i));
+	return __atomic_is_lock_free(sizeof(_M_i), __a);
+      }
 
       void
       store(_Tp __i, memory_order __m = memory_order_seq_cst) noexcept