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,67 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: libcpp-has-no-threads +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// This test requires the dylib support introduced in D68480, which shipped in macOS 11.0. +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}} + +// TODO(ldionne): This test fails on Ubuntu Focal on our CI nodes (and only there), in 32 bit mode. +// UNSUPPORTED: linux && 32bits-on-64bits + +// This is a regression test for PR#47013. + +// + +#include +#include +#include +#include + +#include "make_test_thread.h" + +static std::counting_semaphore s(0); +static std::barrier b(8 + 1); + +void acquire() { + for (int i = 0; i < 10'000; ++i) { + s.acquire(); + b.arrive_and_wait(); + } +} + +void release() { + for (int i = 0; i < 10'000; ++i) { + s.release(1); + s.release(1); + s.release(1); + s.release(1); + + s.release(1); + s.release(1); + s.release(1); + s.release(1); + + b.arrive_and_wait(); + } +} + +int main(int, char**) { + std::vector threads; + + for (int i = 0; i < 8; ++i) + threads.push_back(support::make_test_thread(acquire)); + + threads.push_back(support::make_test_thread(release)); + + for (auto& thread : threads) + thread.join(); + + return 0; +}