Index: libcxx/include/semaphore =================================================================== --- libcxx/include/semaphore +++ libcxx/include/semaphore @@ -87,10 +87,9 @@ { if(0 < __a.fetch_add(__update, memory_order_release)) ; - else if(__update > 1) - __a.notify_all(); else - __a.notify_one(); + // Always notify all, regardless of the value of __update (see PR47013) + __a.notify_all(); } _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY void acquire() Index: libcxx/test/std/thread/thread.semaphore/lost_wakeup.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/thread/thread.semaphore/lost_wakeup.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// REQUIRES: long_tests +// UNSUPPORTED: libcpp-has-no-threads +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// This is a regression test for PR#47013. + +// + +#include +#include +#include +#include + +static std::counting_semaphore s(0); +static std::barrier b(8 + 2); + +void acquire() { + for (auto i = 0; i < 100'000; ++i) { + s.acquire(); + b.arrive_and_wait(); + } +} + +void release() { + for (auto i = 0; i < 100'000; ++i) { + for (auto j = 0; j < 4; ++j) + s.release(1); + b.arrive_and_wait(); + } +} + +int main(int, char**) { + std::vector threads; + + for (auto i = 0; i < 8; ++i) + threads.emplace_back(acquire); + for (auto i = 0; i < 2; ++i) + threads.emplace_back(release); + + for (auto& thread : threads) + thread.join(); + + return 0; +}