Skip to content

Commit c92a253

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
1 parent baa820c commit c92a253

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
@@ -30,14 +30,17 @@ int main(int, char**)
3030
std::counting_semaphore<> s(1);
3131

3232
assert(s.try_acquire());
33+
assert(!s.try_acquire());
3334
s.release();
3435
assert(s.try_acquire());
36+
assert(!s.try_acquire());
3537
s.release(2);
3638
std::thread t = support::make_test_thread([&](){
3739
assert(s.try_acquire());
3840
});
3941
t.join();
4042
assert(s.try_acquire());
43+
assert(!s.try_acquire());
4144

4245
return 0;
4346
}

0 commit comments

Comments
 (0)