[all-commits] [llvm/llvm-project] 208a6d: [libc++] Fix inconsistency between is_lock_free an...

Louis Dionne via All-commits all-commits at lists.llvm.org
Wed Oct 18 19:58:37 PDT 2023


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: 208a6d97f56fc36da6833a0e14e5847b7d84322e
      https://github.com/llvm/llvm-project/commit/208a6d97f56fc36da6833a0e14e5847b7d84322e
  Author: Louis Dionne <ldionne.2 at gmail.com>
  Date:   2023-10-18 (Wed, 18 Oct 2023)

  Changed paths:
    M libcxx/include/__atomic/atomic_base.h
    M libcxx/test/libcxx/atomics/atomics.align/align.pass.cpp
    M libcxx/test/std/atomics/atomics.lockfree/isalwayslockfree.pass.cpp
    M libcxx/test/std/atomics/atomics.types.generic/address.pass.cpp
    M libcxx/test/std/atomics/atomics.types.generic/bool.pass.cpp
    M libcxx/test/std/atomics/atomics.types.generic/integral.pass.cpp
    M libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_is_lock_free.pass.cpp

  Log Message:
  -----------
  [libc++] Fix inconsistency between is_lock_free and is_always_lock_free (#68109)

std::atomic is implemented with the following (confusing!) hierarchy of
types:

     std::atomic<T> : std::__atomic_base<T> { ... };
     std::__atomic_base<T> {
          std::__cxx_atomic_impl<T> __impl;
     };
     std::__cxx_atomic_impl<T> {
          _Atomic(T) __val;
     };

Inside std::__atomic_base, we implement the is_lock_free() and
is_always_lock_free() functions. However, we used to implement them
inconsistently:
- is_always_lock_free() is based on whether __cxx_atomic_impl<T> is
always lock free (using the builtin), which means that we include any
potential padding added by _Atomic(T) into the determination.
- is_lock_free() was based on whether T is lock free (using the
builtin), which meant that we did not take into account any potential
padding added by _Atomic(T).

It is important to note that the padding added by _Atomic(T) can turn a
type that wouldn't be lock free into a lock free type, for example by
making its size become a power of two.

The inconsistency of how the two functions were implemented could lead
to cases where is_always_lock_free() would return true, but
is_lock_free() would then return false. This is the case for example of
the following type, which is always lock free on arm64 but was
incorrectly reported as !is_lock_free() before this patch:

     struct Foo { float x[3]; };

This patch switches the determination of is_lock_free() to be based on
__cxx_atomic_impl<T> instead to match how we determine
is_always_lock_free().

rdar://115324353




More information about the All-commits mailing list