15a83710eSEric Fiselier //===----------------------------------------------------------------------===//
25a83710eSEric Fiselier //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65a83710eSEric Fiselier //
75a83710eSEric Fiselier //===----------------------------------------------------------------------===//
85a83710eSEric Fiselier //
95a83710eSEric Fiselier // UNSUPPORTED: libcpp-has-no-threads
105a83710eSEric Fiselier 
115a83710eSEric Fiselier // <condition_variable>
125a83710eSEric Fiselier 
135a83710eSEric Fiselier // class condition_variable;
145a83710eSEric Fiselier 
155a83710eSEric Fiselier // void notify_one();
165a83710eSEric Fiselier 
17579d6ed4SDavid Zarzycki 
18579d6ed4SDavid Zarzycki // NOTE: `notify_one` is just a wrapper around pthread_cond_signal, but
19579d6ed4SDavid Zarzycki // POSIX does not guarantee that one and only one thread will be woken:
20579d6ed4SDavid Zarzycki //
21579d6ed4SDavid Zarzycki // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_signal.html
22579d6ed4SDavid Zarzycki //
23579d6ed4SDavid Zarzycki // Quote:
24579d6ed4SDavid Zarzycki //     Multiple Awakenings by Condition Signal
25579d6ed4SDavid Zarzycki //     On a multi-processor, it may be impossible for an implementation of
26579d6ed4SDavid Zarzycki //     pthread_cond_signal() to avoid the unblocking of more than one thread
27579d6ed4SDavid Zarzycki //     blocked on a condition variable. For example...
28579d6ed4SDavid Zarzycki 
29579d6ed4SDavid Zarzycki 
30579d6ed4SDavid Zarzycki 
31579d6ed4SDavid Zarzycki // NOTE: In previous versions of this test, `notify_one` was called WITHOUT
32579d6ed4SDavid Zarzycki // holding the lock but POSIX says (in the aforementioned URL) that:
33579d6ed4SDavid Zarzycki //     ...if predictable scheduling behavior is required, then that mutex shall
34579d6ed4SDavid Zarzycki //     be locked by the thread calling pthread_cond_broadcast() or
35579d6ed4SDavid Zarzycki //     pthread_cond_signal().
36579d6ed4SDavid Zarzycki 
37579d6ed4SDavid Zarzycki 
385a83710eSEric Fiselier #include <condition_variable>
3992499e45SEric Fiselier #include <atomic>
405a83710eSEric Fiselier #include <mutex>
415a83710eSEric Fiselier #include <thread>
425a83710eSEric Fiselier #include <cassert>
435a83710eSEric Fiselier 
44*56462801SLouis Dionne #include "make_test_thread.h"
457fc6a556SMarshall Clow #include "test_macros.h"
467fc6a556SMarshall Clow 
4710967a6eSEric Fiselier 
485a83710eSEric Fiselier std::condition_variable cv;
495a83710eSEric Fiselier std::mutex mut;
505a83710eSEric Fiselier 
5192499e45SEric Fiselier std::atomic_int test1(0);
5292499e45SEric Fiselier std::atomic_int test2(0);
531c4238e7SDavid Zarzycki std::atomic_int ready(2);
541c4238e7SDavid Zarzycki std::atomic_int which(0);
555a83710eSEric Fiselier 
565a83710eSEric Fiselier void f1()
575a83710eSEric Fiselier {
585a83710eSEric Fiselier   std::unique_lock<std::mutex> lk(mut);
595a83710eSEric Fiselier   assert(test1 == 0);
60579d6ed4SDavid Zarzycki   --ready;
615a83710eSEric Fiselier   while (test1 == 0)
625a83710eSEric Fiselier     cv.wait(lk);
631c4238e7SDavid Zarzycki   which = 1;
645a83710eSEric Fiselier   assert(test1 == 1);
655a83710eSEric Fiselier   test1 = 2;
665a83710eSEric Fiselier }
675a83710eSEric Fiselier 
685a83710eSEric Fiselier void f2()
695a83710eSEric Fiselier {
705a83710eSEric Fiselier   std::unique_lock<std::mutex> lk(mut);
715a83710eSEric Fiselier   assert(test2 == 0);
72579d6ed4SDavid Zarzycki   --ready;
735a83710eSEric Fiselier   while (test2 == 0)
745a83710eSEric Fiselier     cv.wait(lk);
751c4238e7SDavid Zarzycki   which = 2;
765a83710eSEric Fiselier   assert(test2 == 1);
775a83710eSEric Fiselier   test2 = 2;
785a83710eSEric Fiselier }
795a83710eSEric Fiselier 
802df59c50SJF Bastien int main(int, char**)
815a83710eSEric Fiselier {
82*56462801SLouis Dionne   std::thread t1 = support::make_test_thread(f1);
83*56462801SLouis Dionne   std::thread t2 = support::make_test_thread(f2);
84579d6ed4SDavid Zarzycki   {
851c4238e7SDavid Zarzycki     while (ready > 0)
861c4238e7SDavid Zarzycki       std::this_thread::yield();
87579d6ed4SDavid Zarzycki     // At this point:
88579d6ed4SDavid Zarzycki     // 1) Both f1 and f2 have entered their condition variable wait.
89579d6ed4SDavid Zarzycki     // 2) Either f1 or f2 has the mutex locked and is about to wait.
905a83710eSEric Fiselier     std::unique_lock<std::mutex> lk(mut);
915a83710eSEric Fiselier     test1 = 1;
925a83710eSEric Fiselier     test2 = 1;
931c4238e7SDavid Zarzycki     ready = 1;
945a83710eSEric Fiselier     cv.notify_one();
95579d6ed4SDavid Zarzycki   }
965a83710eSEric Fiselier   {
971c4238e7SDavid Zarzycki     while (which == 0)
981c4238e7SDavid Zarzycki       std::this_thread::yield();
995a83710eSEric Fiselier     std::unique_lock<std::mutex> lk(mut);
1001c4238e7SDavid Zarzycki     if (test1 == 2) {
10110967a6eSEric Fiselier       assert(test2 == 1);
1025a83710eSEric Fiselier       t1.join();
1035a83710eSEric Fiselier       test1 = 0;
1041c4238e7SDavid Zarzycki     } else {
10510967a6eSEric Fiselier       assert(test1 == 1);
1061c4238e7SDavid Zarzycki       assert(test2 == 2);
1075a83710eSEric Fiselier       t2.join();
1085a83710eSEric Fiselier       test2 = 0;
1095a83710eSEric Fiselier     }
1101c4238e7SDavid Zarzycki     which = 0;
1115a83710eSEric Fiselier     cv.notify_one();
112579d6ed4SDavid Zarzycki   }
1135a83710eSEric Fiselier   {
1141c4238e7SDavid Zarzycki     while (which == 0)
1151c4238e7SDavid Zarzycki       std::this_thread::yield();
1165a83710eSEric Fiselier     std::unique_lock<std::mutex> lk(mut);
1171c4238e7SDavid Zarzycki     if (test1 == 2) {
11810967a6eSEric Fiselier       assert(test2 == 0);
1195a83710eSEric Fiselier       t1.join();
1205a83710eSEric Fiselier       test1 = 0;
1211c4238e7SDavid Zarzycki     } else {
12210967a6eSEric Fiselier       assert(test1 == 0);
1231c4238e7SDavid Zarzycki       assert(test2 == 2);
1245a83710eSEric Fiselier       t2.join();
1255a83710eSEric Fiselier       test2 = 0;
1265a83710eSEric Fiselier     }
127579d6ed4SDavid Zarzycki   }
1282df59c50SJF Bastien 
1292df59c50SJF Bastien   return 0;
1305a83710eSEric Fiselier }
131