Skip to content

Commit 216200a

Browse files
author
Arthur O'Dwyer
committed
[libc++] Fix hang in counting_semaphore::try_acquire
Before this patch, `try_acquire` blocks instead of returning false. This is because `__libcpp_thread_poll_with_backoff` interprets zero as meaning infinite, causing `try_acquire` to wait indefinitely. Thanks to Pablo Busse (pabusse) for the patch! Differential Revision: https://reviews.llvm.org/D98334 (cherry picked from commit c92a253)
1 parent 00f64cc commit 216200a

File tree

2 files changed

+19
-11
lines changed

2 files changed

+19
-11
lines changed

libcxx/include/semaphore

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,22 @@ public:
105105
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
106106
bool try_acquire_for(chrono::duration<Rep, Period> const& __rel_time)
107107
{
108-
auto const __test_fn = [this]() -> bool {
109-
auto __old = __a.load(memory_order_acquire);
110-
while(1) {
111-
if (__old == 0)
112-
return false;
113-
if(__a.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed))
114-
return true;
115-
}
116-
};
108+
if (__rel_time == chrono::duration<Rep, Period>::zero())
109+
return try_acquire();
110+
auto const __test_fn = [this]() { return try_acquire(); };
117111
return __libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy(), __rel_time);
118112
}
113+
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
114+
bool try_acquire()
115+
{
116+
auto __old = __a.load(memory_order_acquire);
117+
while (true) {
118+
if (__old == 0)
119+
return false;
120+
if (__a.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed))
121+
return true;
122+
}
123+
}
119124
};
120125

121126
#define _LIBCPP_SEMAPHORE_MAX (numeric_limits<ptrdiff_t>::max())
@@ -156,14 +161,14 @@ public:
156161
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
157162
bool try_acquire()
158163
{
159-
return try_acquire_for(chrono::nanoseconds::zero());
164+
return __semaphore.try_acquire();
160165
}
161166
template <class Clock, class Duration>
162167
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
163168
bool try_acquire_until(chrono::time_point<Clock, Duration> const& __abs_time)
164169
{
165170
auto const current = Clock::now();
166-
if(current >= __abs_time)
171+
if (current >= __abs_time)
167172
return try_acquire();
168173
else
169174
return try_acquire_for(__abs_time - current);

libcxx/test/std/thread/thread.semaphore/try_acquire.pass.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,17 @@ int main(int, char**)
2727
std::counting_semaphore<> s(1);
2828

2929
assert(s.try_acquire());
30+
assert(!s.try_acquire());
3031
s.release();
3132
assert(s.try_acquire());
33+
assert(!s.try_acquire());
3234
s.release(2);
3335
std::thread t = support::make_test_thread([&](){
3436
assert(s.try_acquire());
3537
});
3638
t.join();
3739
assert(s.try_acquire());
40+
assert(!s.try_acquire());
3841

3942
return 0;
4043
}

0 commit comments

Comments
 (0)