154fa9ecdSOlivier Giroux// -*- C++ -*-
2eb8650a7SLouis Dionne//===----------------------------------------------------------------------===//
354fa9ecdSOlivier Giroux//
454fa9ecdSOlivier Giroux// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
554fa9ecdSOlivier Giroux// See https://llvm.org/LICENSE.txt for license information.
654fa9ecdSOlivier Giroux// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
754fa9ecdSOlivier Giroux//
854fa9ecdSOlivier Giroux//===----------------------------------------------------------------------===//
954fa9ecdSOlivier Giroux
1054fa9ecdSOlivier Giroux#ifndef _LIBCPP_BARRIER
1154fa9ecdSOlivier Giroux#define _LIBCPP_BARRIER
1254fa9ecdSOlivier Giroux
1354fa9ecdSOlivier Giroux/*
1454fa9ecdSOlivier Giroux    barrier synopsis
1554fa9ecdSOlivier Giroux
1654fa9ecdSOlivier Girouxnamespace std
1754fa9ecdSOlivier Giroux{
1854fa9ecdSOlivier Giroux
1954fa9ecdSOlivier Giroux  template<class CompletionFunction = see below>
2054fa9ecdSOlivier Giroux  class barrier
2154fa9ecdSOlivier Giroux  {
2254fa9ecdSOlivier Giroux  public:
2354fa9ecdSOlivier Giroux    using arrival_token = see below;
2454fa9ecdSOlivier Giroux
25e2279c23SMarek Kurdej    static constexpr ptrdiff_t max() noexcept;
26e2279c23SMarek Kurdej
2754fa9ecdSOlivier Giroux    constexpr explicit barrier(ptrdiff_t phase_count,
2854fa9ecdSOlivier Giroux                               CompletionFunction f = CompletionFunction());
2954fa9ecdSOlivier Giroux    ~barrier();
3054fa9ecdSOlivier Giroux
3154fa9ecdSOlivier Giroux    barrier(const barrier&) = delete;
3254fa9ecdSOlivier Giroux    barrier& operator=(const barrier&) = delete;
3354fa9ecdSOlivier Giroux
3454fa9ecdSOlivier Giroux    [[nodiscard]] arrival_token arrive(ptrdiff_t update = 1);
3554fa9ecdSOlivier Giroux    void wait(arrival_token&& arrival) const;
3654fa9ecdSOlivier Giroux
3754fa9ecdSOlivier Giroux    void arrive_and_wait();
3854fa9ecdSOlivier Giroux    void arrive_and_drop();
3954fa9ecdSOlivier Giroux
4054fa9ecdSOlivier Giroux  private:
4154fa9ecdSOlivier Giroux    CompletionFunction completion; // exposition only
4254fa9ecdSOlivier Giroux  };
4354fa9ecdSOlivier Giroux
4454fa9ecdSOlivier Giroux}
4554fa9ecdSOlivier Giroux
4654fa9ecdSOlivier Giroux*/
4754fa9ecdSOlivier Giroux
48385cc25aSLouis Dionne#include <__assert> // all public C++ headers provide the assertion handler
492eadbc86SLouis Dionne#include <__availability>
50bfbd73f8SArthur O'Dwyer#include <__config>
51df51be85SLouis Dionne#include <__thread/timed_backoff_policy.h>
5254fa9ecdSOlivier Giroux#include <atomic>
53643df8faSLouis Dionne#include <limits>
5454fa9ecdSOlivier Giroux#include <memory>
5554fa9ecdSOlivier Giroux
5654fa9ecdSOlivier Giroux#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
5754fa9ecdSOlivier Giroux#  pragma GCC system_header
5854fa9ecdSOlivier Giroux#endif
5954fa9ecdSOlivier Giroux
6054fa9ecdSOlivier Giroux#ifdef _LIBCPP_HAS_NO_THREADS
611c4b31c3SLouis Dionne# error "<barrier> is not supported since libc++ has been configured without support for threads."
6254fa9ecdSOlivier Giroux#endif
6354fa9ecdSOlivier Giroux
64d4303307SArthur O'Dwyer_LIBCPP_PUSH_MACROS
65d4303307SArthur O'Dwyer#include <__undef_macros>
66d4303307SArthur O'Dwyer
67ab41129bSLouis Dionne#if _LIBCPP_STD_VER >= 14
6854fa9ecdSOlivier Giroux
6954fa9ecdSOlivier Giroux_LIBCPP_BEGIN_NAMESPACE_STD
7054fa9ecdSOlivier Giroux
7154fa9ecdSOlivier Girouxstruct __empty_completion
7254fa9ecdSOlivier Giroux{
7354fa9ecdSOlivier Giroux    inline _LIBCPP_INLINE_VISIBILITY
7454fa9ecdSOlivier Giroux    void operator()() noexcept
7554fa9ecdSOlivier Giroux    {
7654fa9ecdSOlivier Giroux    }
7754fa9ecdSOlivier Giroux};
7854fa9ecdSOlivier Giroux
7954fa9ecdSOlivier Giroux#ifndef _LIBCPP_HAS_NO_TREE_BARRIER
8054fa9ecdSOlivier Giroux
8154fa9ecdSOlivier Giroux/*
8254fa9ecdSOlivier Giroux
8354fa9ecdSOlivier GirouxThe default implementation of __barrier_base is a classic tree barrier.
8454fa9ecdSOlivier Giroux
8554fa9ecdSOlivier GirouxIt looks different from literature pseudocode for two main reasons:
8654fa9ecdSOlivier Giroux 1. Threads that call into std::barrier functions do not provide indices,
8754fa9ecdSOlivier Giroux    so a numbering step is added before the actual barrier algorithm,
8854fa9ecdSOlivier Giroux    appearing as an N+1 round to the N rounds of the tree barrier.
8954fa9ecdSOlivier Giroux 2. A great deal of attention has been paid to avoid cache line thrashing
9054fa9ecdSOlivier Giroux    by flattening the tree structure into cache-line sized arrays, that
9154fa9ecdSOlivier Giroux    are indexed in an efficient way.
9254fa9ecdSOlivier Giroux
9354fa9ecdSOlivier Giroux*/
9454fa9ecdSOlivier Giroux
9554fa9ecdSOlivier Girouxusing __barrier_phase_t = uint8_t;
9654fa9ecdSOlivier Giroux
9754fa9ecdSOlivier Girouxclass __barrier_algorithm_base;
9854fa9ecdSOlivier Giroux
9980e73f22SLouis Dionne_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI
10054fa9ecdSOlivier Giroux__barrier_algorithm_base* __construct_barrier_algorithm_base(ptrdiff_t& __expected);
10154fa9ecdSOlivier Giroux
10280e73f22SLouis Dionne_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI
10354fa9ecdSOlivier Girouxbool __arrive_barrier_algorithm_base(__barrier_algorithm_base* __barrier,
10454fa9ecdSOlivier Giroux                                     __barrier_phase_t __old_phase);
10554fa9ecdSOlivier Giroux
10680e73f22SLouis Dionne_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI
10754fa9ecdSOlivier Girouxvoid __destroy_barrier_algorithm_base(__barrier_algorithm_base* __barrier);
10854fa9ecdSOlivier Giroux
10954fa9ecdSOlivier Girouxtemplate<class _CompletionF>
11054fa9ecdSOlivier Girouxclass __barrier_base {
111e39095a3SLouis Dionne    ptrdiff_t                                               __expected_;
11254fa9ecdSOlivier Giroux    unique_ptr<__barrier_algorithm_base,
113e39095a3SLouis Dionne               void (*)(__barrier_algorithm_base*)>         __base_;
114e39095a3SLouis Dionne    __atomic_base<ptrdiff_t>                                __expected_adjustment_;
115e39095a3SLouis Dionne    _CompletionF                                            __completion_;
116e39095a3SLouis Dionne    __atomic_base<__barrier_phase_t>                        __phase_;
11754fa9ecdSOlivier Giroux
11854fa9ecdSOlivier Girouxpublic:
11954fa9ecdSOlivier Giroux    using arrival_token = __barrier_phase_t;
12054fa9ecdSOlivier Giroux
12154fa9ecdSOlivier Giroux    static constexpr ptrdiff_t max() noexcept {
12254fa9ecdSOlivier Giroux        return numeric_limits<ptrdiff_t>::max();
12354fa9ecdSOlivier Giroux    }
12454fa9ecdSOlivier Giroux
12546c38761SLouis Dionne    _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
12654fa9ecdSOlivier Giroux    __barrier_base(ptrdiff_t __expected, _CompletionF __completion = _CompletionF())
127e39095a3SLouis Dionne            : __expected_(__expected), __base_(__construct_barrier_algorithm_base(this->__expected_),
12854fa9ecdSOlivier Giroux                                               &__destroy_barrier_algorithm_base),
129e39095a3SLouis Dionne              __expected_adjustment_(0), __completion_(std::move(__completion)), __phase_(0)
13054fa9ecdSOlivier Giroux    {
13154fa9ecdSOlivier Giroux    }
13246c38761SLouis Dionne    [[nodiscard]] _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
133*b48c5010SNikolas Klauser    arrival_token arrive(ptrdiff_t __update)
13454fa9ecdSOlivier Giroux    {
135e39095a3SLouis Dionne        auto const __old_phase = __phase_.load(memory_order_relaxed);
136*b48c5010SNikolas Klauser        for(; __update; --__update)
137e39095a3SLouis Dionne            if(__arrive_barrier_algorithm_base(__base_.get(), __old_phase)) {
138e39095a3SLouis Dionne                __completion_();
139e39095a3SLouis Dionne                __expected_ += __expected_adjustment_.load(memory_order_relaxed);
140e39095a3SLouis Dionne                __expected_adjustment_.store(0, memory_order_relaxed);
141e39095a3SLouis Dionne                __phase_.store(__old_phase + 2, memory_order_release);
142e39095a3SLouis Dionne                __phase_.notify_all();
14354fa9ecdSOlivier Giroux            }
14454fa9ecdSOlivier Giroux        return __old_phase;
14554fa9ecdSOlivier Giroux    }
14646c38761SLouis Dionne    _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
14754fa9ecdSOlivier Giroux    void wait(arrival_token&& __old_phase) const
14854fa9ecdSOlivier Giroux    {
1492e4755ffSLouis Dionne        auto const __test_fn = [this, __old_phase]() -> bool {
150e39095a3SLouis Dionne            return __phase_.load(memory_order_acquire) != __old_phase;
15154fa9ecdSOlivier Giroux        };
15254fa9ecdSOlivier Giroux        __libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy());
15354fa9ecdSOlivier Giroux    }
15446c38761SLouis Dionne    _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
15554fa9ecdSOlivier Giroux    void arrive_and_drop()
15654fa9ecdSOlivier Giroux    {
157e39095a3SLouis Dionne        __expected_adjustment_.fetch_sub(1, memory_order_relaxed);
15854fa9ecdSOlivier Giroux        (void)arrive(1);
15954fa9ecdSOlivier Giroux    }
16054fa9ecdSOlivier Giroux};
16154fa9ecdSOlivier Giroux
16254fa9ecdSOlivier Giroux#else
16354fa9ecdSOlivier Giroux
16454fa9ecdSOlivier Giroux/*
16554fa9ecdSOlivier Giroux
16654fa9ecdSOlivier GirouxThe alternative implementation of __barrier_base is a central barrier.
16754fa9ecdSOlivier Giroux
16854fa9ecdSOlivier GirouxTwo versions of this algorithm are provided:
16954fa9ecdSOlivier Giroux 1. A fairly straightforward implementation of the litterature for the
17054fa9ecdSOlivier Giroux    general case where the completion function is not empty.
17154fa9ecdSOlivier Giroux 2. An optimized implementation that exploits 2's complement arithmetic
17254fa9ecdSOlivier Giroux    and well-defined overflow in atomic arithmetic, to handle the phase
17354fa9ecdSOlivier Giroux    roll-over for free.
17454fa9ecdSOlivier Giroux
17554fa9ecdSOlivier Giroux*/
17654fa9ecdSOlivier Giroux
17754fa9ecdSOlivier Girouxtemplate<class _CompletionF>
17854fa9ecdSOlivier Girouxclass __barrier_base {
17954fa9ecdSOlivier Giroux
18054fa9ecdSOlivier Giroux    __atomic_base<ptrdiff_t> __expected;
18154fa9ecdSOlivier Giroux    __atomic_base<ptrdiff_t> __arrived;
18254fa9ecdSOlivier Giroux    _CompletionF             __completion;
18354fa9ecdSOlivier Giroux    __atomic_base<bool>      __phase;
18454fa9ecdSOlivier Girouxpublic:
18554fa9ecdSOlivier Giroux    using arrival_token = bool;
18654fa9ecdSOlivier Giroux
18754fa9ecdSOlivier Giroux    static constexpr ptrdiff_t max() noexcept {
18854fa9ecdSOlivier Giroux        return numeric_limits<ptrdiff_t>::max();
18954fa9ecdSOlivier Giroux    }
19054fa9ecdSOlivier Giroux
19154fa9ecdSOlivier Giroux    _LIBCPP_INLINE_VISIBILITY
19254fa9ecdSOlivier Giroux    __barrier_base(ptrdiff_t __expected, _CompletionF __completion = _CompletionF())
19348f8a7c4SCorentin Jabot        : __expected(__expected), __arrived(__expected), __completion(std::move(__completion)), __phase(false)
19454fa9ecdSOlivier Giroux    {
19554fa9ecdSOlivier Giroux    }
19646c38761SLouis Dionne    [[nodiscard]] _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
19754fa9ecdSOlivier Giroux    arrival_token arrive(ptrdiff_t update)
19854fa9ecdSOlivier Giroux    {
19954fa9ecdSOlivier Giroux        auto const __old_phase = __phase.load(memory_order_relaxed);
20054fa9ecdSOlivier Giroux        auto const __result = __arrived.fetch_sub(update, memory_order_acq_rel) - update;
20154fa9ecdSOlivier Giroux        auto const new_expected = __expected.load(memory_order_relaxed);
20254fa9ecdSOlivier Giroux        if(0 == __result) {
20354fa9ecdSOlivier Giroux            __completion();
20454fa9ecdSOlivier Giroux            __arrived.store(new_expected, memory_order_relaxed);
20554fa9ecdSOlivier Giroux            __phase.store(!__old_phase, memory_order_release);
20654fa9ecdSOlivier Giroux            __phase.notify_all();
20754fa9ecdSOlivier Giroux        }
20854fa9ecdSOlivier Giroux        return __old_phase;
20954fa9ecdSOlivier Giroux    }
21046c38761SLouis Dionne    _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
21154fa9ecdSOlivier Giroux    void wait(arrival_token&& __old_phase) const
21254fa9ecdSOlivier Giroux    {
21354fa9ecdSOlivier Giroux        __phase.wait(__old_phase, memory_order_acquire);
21454fa9ecdSOlivier Giroux    }
21546c38761SLouis Dionne    _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
21654fa9ecdSOlivier Giroux    void arrive_and_drop()
21754fa9ecdSOlivier Giroux    {
21854fa9ecdSOlivier Giroux        __expected.fetch_sub(1, memory_order_relaxed);
21954fa9ecdSOlivier Giroux        (void)arrive(1);
22054fa9ecdSOlivier Giroux    }
22154fa9ecdSOlivier Giroux};
22254fa9ecdSOlivier Giroux
22354fa9ecdSOlivier Girouxtemplate<>
22454fa9ecdSOlivier Girouxclass __barrier_base<__empty_completion> {
22554fa9ecdSOlivier Giroux
22654fa9ecdSOlivier Giroux    static constexpr uint64_t __expected_unit = 1ull;
22754fa9ecdSOlivier Giroux    static constexpr uint64_t __arrived_unit = 1ull << 32;
22854fa9ecdSOlivier Giroux    static constexpr uint64_t __expected_mask = __arrived_unit - 1;
22954fa9ecdSOlivier Giroux    static constexpr uint64_t __phase_bit = 1ull << 63;
23054fa9ecdSOlivier Giroux    static constexpr uint64_t __arrived_mask = (__phase_bit - 1) & ~__expected_mask;
23154fa9ecdSOlivier Giroux
23254fa9ecdSOlivier Giroux    __atomic_base<uint64_t>   __phase_arrived_expected;
23354fa9ecdSOlivier Giroux
23454fa9ecdSOlivier Giroux    static _LIBCPP_INLINE_VISIBILITY
23554fa9ecdSOlivier Giroux    constexpr uint64_t __init(ptrdiff_t __count) _NOEXCEPT
23654fa9ecdSOlivier Giroux    {
23754fa9ecdSOlivier Giroux        return ((uint64_t(1u << 31) - __count) << 32)
23854fa9ecdSOlivier Giroux              | (uint64_t(1u << 31) - __count);
23954fa9ecdSOlivier Giroux    }
24054fa9ecdSOlivier Giroux
24154fa9ecdSOlivier Girouxpublic:
24254fa9ecdSOlivier Giroux    using arrival_token = uint64_t;
24354fa9ecdSOlivier Giroux
24454fa9ecdSOlivier Giroux    static constexpr ptrdiff_t max() noexcept {
24554fa9ecdSOlivier Giroux        return ptrdiff_t(1u << 31) - 1;
24654fa9ecdSOlivier Giroux    }
24754fa9ecdSOlivier Giroux
24854fa9ecdSOlivier Giroux    _LIBCPP_INLINE_VISIBILITY
24954fa9ecdSOlivier Giroux    explicit inline __barrier_base(ptrdiff_t __count, __empty_completion = __empty_completion())
25054fa9ecdSOlivier Giroux        : __phase_arrived_expected(__init(__count))
25154fa9ecdSOlivier Giroux    {
25254fa9ecdSOlivier Giroux    }
25346c38761SLouis Dionne    [[nodiscard]] inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
25454fa9ecdSOlivier Giroux    arrival_token arrive(ptrdiff_t update)
25554fa9ecdSOlivier Giroux    {
25654fa9ecdSOlivier Giroux        auto const __inc = __arrived_unit * update;
25754fa9ecdSOlivier Giroux        auto const __old = __phase_arrived_expected.fetch_add(__inc, memory_order_acq_rel);
25854fa9ecdSOlivier Giroux        if((__old ^ (__old + __inc)) & __phase_bit) {
25954fa9ecdSOlivier Giroux            __phase_arrived_expected.fetch_add((__old & __expected_mask) << 32, memory_order_relaxed);
26054fa9ecdSOlivier Giroux            __phase_arrived_expected.notify_all();
26154fa9ecdSOlivier Giroux        }
26254fa9ecdSOlivier Giroux        return __old & __phase_bit;
26354fa9ecdSOlivier Giroux    }
26446c38761SLouis Dionne    inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
26554fa9ecdSOlivier Giroux    void wait(arrival_token&& __phase) const
26654fa9ecdSOlivier Giroux    {
26754fa9ecdSOlivier Giroux        auto const __test_fn = [=]() -> bool {
26854fa9ecdSOlivier Giroux            uint64_t const __current = __phase_arrived_expected.load(memory_order_acquire);
26954fa9ecdSOlivier Giroux            return ((__current & __phase_bit) != __phase);
27054fa9ecdSOlivier Giroux        };
27154fa9ecdSOlivier Giroux        __libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy());
27254fa9ecdSOlivier Giroux    }
27346c38761SLouis Dionne    inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
27454fa9ecdSOlivier Giroux    void arrive_and_drop()
27554fa9ecdSOlivier Giroux    {
27654fa9ecdSOlivier Giroux        __phase_arrived_expected.fetch_add(__expected_unit, memory_order_relaxed);
27754fa9ecdSOlivier Giroux        (void)arrive(1);
27854fa9ecdSOlivier Giroux    }
27954fa9ecdSOlivier Giroux};
28054fa9ecdSOlivier Giroux
2818383351dSLouis Dionne#endif // !_LIBCPP_HAS_NO_TREE_BARRIER
28254fa9ecdSOlivier Giroux
28354fa9ecdSOlivier Girouxtemplate<class _CompletionF = __empty_completion>
28454fa9ecdSOlivier Girouxclass barrier {
28554fa9ecdSOlivier Giroux
28654fa9ecdSOlivier Giroux    __barrier_base<_CompletionF> __b;
28754fa9ecdSOlivier Girouxpublic:
28854fa9ecdSOlivier Giroux    using arrival_token = typename __barrier_base<_CompletionF>::arrival_token;
28954fa9ecdSOlivier Giroux
29054fa9ecdSOlivier Giroux    static constexpr ptrdiff_t max() noexcept {
29154fa9ecdSOlivier Giroux        return __barrier_base<_CompletionF>::max();
29254fa9ecdSOlivier Giroux    }
29354fa9ecdSOlivier Giroux
29446c38761SLouis Dionne    _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
29554fa9ecdSOlivier Giroux    barrier(ptrdiff_t __count, _CompletionF __completion = _CompletionF())
296d586f92cSArthur O'Dwyer        : __b(__count, _VSTD::move(__completion)) {
29754fa9ecdSOlivier Giroux    }
29854fa9ecdSOlivier Giroux
29954fa9ecdSOlivier Giroux    barrier(barrier const&) = delete;
30054fa9ecdSOlivier Giroux    barrier& operator=(barrier const&) = delete;
30154fa9ecdSOlivier Giroux
30246c38761SLouis Dionne    [[nodiscard]] _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
303*b48c5010SNikolas Klauser    arrival_token arrive(ptrdiff_t __update = 1)
30454fa9ecdSOlivier Giroux    {
305*b48c5010SNikolas Klauser        return __b.arrive(__update);
30654fa9ecdSOlivier Giroux    }
30746c38761SLouis Dionne    _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
30854fa9ecdSOlivier Giroux    void wait(arrival_token&& __phase) const
30954fa9ecdSOlivier Giroux    {
310d586f92cSArthur O'Dwyer        __b.wait(_VSTD::move(__phase));
31154fa9ecdSOlivier Giroux    }
31246c38761SLouis Dionne    _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
31354fa9ecdSOlivier Giroux    void arrive_and_wait()
31454fa9ecdSOlivier Giroux    {
31554fa9ecdSOlivier Giroux        wait(arrive());
31654fa9ecdSOlivier Giroux    }
31746c38761SLouis Dionne    _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
31854fa9ecdSOlivier Giroux    void arrive_and_drop()
31954fa9ecdSOlivier Giroux    {
32054fa9ecdSOlivier Giroux        __b.arrive_and_drop();
32154fa9ecdSOlivier Giroux    }
32254fa9ecdSOlivier Giroux};
32354fa9ecdSOlivier Giroux
32454fa9ecdSOlivier Giroux_LIBCPP_END_NAMESPACE_STD
32554fa9ecdSOlivier Giroux
326ab41129bSLouis Dionne#endif // _LIBCPP_STD_VER >= 14
327ab41129bSLouis Dionne
328d4303307SArthur O'Dwyer_LIBCPP_POP_MACROS
329d4303307SArthur O'Dwyer
33054fa9ecdSOlivier Giroux#endif //_LIBCPP_BARRIER
331