Skip to content

Commit 8a4b98a

Browse files
committed
[libc++] refactor semaphore latch barrier in terms of atomic::wait
1 parent 75c4339 commit 8a4b98a

File tree

5 files changed

+90
-29
lines changed

5 files changed

+90
-29
lines changed

libcxx/include/barrier

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,6 @@ namespace std
5656
#include <__atomic/memory_order.h>
5757
#include <__availability>
5858
#include <__memory/unique_ptr.h>
59-
#include <__thread/poll_with_backoff.h>
60-
#include <__thread/timed_backoff_policy.h>
6159
#include <__utility/move.h>
6260
#include <cstddef>
6361
#include <cstdint>
@@ -144,8 +142,7 @@ public:
144142
return __old_phase;
145143
}
146144
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(arrival_token&& __old_phase) const {
147-
auto const __test_fn = [this, __old_phase]() -> bool { return __phase_.load(memory_order_acquire) != __old_phase; };
148-
std::__libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy());
145+
__phase_.wait(__old_phase, std::memory_order_acquire);
149146
}
150147
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_drop() {
151148
__expected_adjustment_.fetch_sub(1, memory_order_relaxed);
@@ -242,11 +239,11 @@ public:
242239
return __old & __phase_bit;
243240
}
244241
inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(arrival_token&& __phase) const {
245-
auto const __test_fn = [=]() -> bool {
246-
uint64_t const __current = __phase_arrived_expected.load(memory_order_acquire);
247-
return ((__current & __phase_bit) != __phase);
248-
};
249-
__libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy());
242+
uint64_t __current = __phase_arrived_expected.load(memory_order_acquire);
243+
while ((__current & __phase_bit) == __phase) {
244+
__phase_arrived_expected.wait(__current, std::memory_order_relaxed);
245+
__current = __phase_arrived_expected.load(memory_order_acquire);
246+
}
250247
}
251248
inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_drop() {
252249
__phase_arrived_expected.fetch_add(__expected_unit, memory_order_relaxed);

libcxx/include/latch

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ namespace std
4848

4949
#include <__assert> // all public C++ headers provide the assertion handler
5050
#include <__atomic/atomic_base.h>
51-
#include <__atomic/atomic_sync.h>
5251
#include <__atomic/memory_order.h>
5352
#include <__availability>
5453
#include <cstddef>
@@ -99,7 +98,11 @@ public:
9998
}
10099
inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept { return 0 == __a_.load(memory_order_acquire); }
101100
inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait() const {
102-
__cxx_atomic_wait(&__a_.__a_, [this]() -> bool { return try_wait(); });
101+
auto __old = __a_.load(memory_order_acquire);
102+
while (__old != 0) {
103+
__a_.wait(__old, std::memory_order_relaxed);
104+
__old = __a_.load(memory_order_acquire);
105+
}
103106
}
104107
inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) {
105108
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value");

libcxx/include/semaphore

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -95,20 +95,23 @@ public:
9595
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
9696
__update <= _LIBCPP_SEMAPHORE_MAX - __old, "update is greater than the expected value");
9797

98-
if (__old > 0) {
99-
// Nothing to do
100-
} else if (__update > 1)
98+
if (__old != 0) {
10199
__a_.notify_all();
102-
else
103-
__a_.notify_one();
100+
}
104101
}
102+
105103
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void acquire() {
106-
auto const __test_fn = [this]() -> bool {
107-
auto __old = __a_.load(memory_order_relaxed);
108-
return (__old != 0) && __a_.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed);
109-
};
110-
__cxx_atomic_wait(&__a_.__a_, __test_fn);
104+
auto __old = __a_.load(std::memory_order_relaxed);
105+
while (true) {
106+
if (__old == 0) {
107+
__a_.wait(__old, std::memory_order_relaxed);
108+
__old = __a_.load(std::memory_order_relaxed);
109+
} else if (__a_.compare_exchange_weak(__old, __old - 1, std::memory_order_acquire, std::memory_order_relaxed)) {
110+
break;
111+
}
112+
}
111113
}
114+
112115
template <class _Rep, class _Period>
113116
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
114117
try_acquire_for(chrono::duration<_Rep, _Period> const& __rel_time) {
@@ -117,14 +120,10 @@ public:
117120
auto const __test_fn = [this]() { return try_acquire(); };
118121
return std::__libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy(), __rel_time);
119122
}
123+
120124
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool try_acquire() {
121125
auto __old = __a_.load(memory_order_acquire);
122-
while (true) {
123-
if (__old == 0)
124-
return false;
125-
if (__a_.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed))
126-
return true;
127-
}
126+
return __old != 0 && __a_.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed);
128127
}
129128
};
130129

libcxx/src/thread.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include <__thread/poll_with_backoff.h>
10-
#include <__thread/timed_backoff_policy.h>
119
#include <exception>
1210
#include <future>
1311
#include <limits>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: libcpp-has-no-threads
10+
// UNSUPPORTED: c++03, c++11, c++14, c++17
11+
12+
// XFAIL: availability-synchronization_library-missing
13+
14+
// This is a regression test for https://llvm.org/PR47013.
15+
16+
// <semaphore>
17+
18+
#include <barrier>
19+
#include <semaphore>
20+
#include <thread>
21+
#include <vector>
22+
23+
#include "make_test_thread.h"
24+
25+
static std::counting_semaphore<> s(0);
26+
static std::barrier<> b(8 + 1);
27+
28+
void acquire() {
29+
for (int i = 0; i < 10'000; ++i) {
30+
s.acquire();
31+
b.arrive_and_wait();
32+
}
33+
}
34+
35+
void release() {
36+
for (int i = 0; i < 10'000; ++i) {
37+
s.release(1);
38+
s.release(1);
39+
s.release(1);
40+
s.release(1);
41+
42+
s.release(1);
43+
s.release(1);
44+
s.release(1);
45+
s.release(1);
46+
47+
b.arrive_and_wait();
48+
}
49+
}
50+
51+
int main(int, char**) {
52+
for (int run = 0; run < 20; ++run) {
53+
std::vector<std::thread> threads;
54+
for (int i = 0; i < 8; ++i)
55+
threads.push_back(support::make_test_thread(acquire));
56+
57+
threads.push_back(support::make_test_thread(release));
58+
59+
for (auto& thread : threads)
60+
thread.join();
61+
}
62+
63+
return 0;
64+
}

0 commit comments

Comments
 (0)