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 
17*579d6ed4SDavid Zarzycki 
18*579d6ed4SDavid Zarzycki // NOTE: `notify_one` is just a wrapper around pthread_cond_signal, but
19*579d6ed4SDavid Zarzycki // POSIX does not guarantee that one and only one thread will be woken:
20*579d6ed4SDavid Zarzycki //
21*579d6ed4SDavid Zarzycki // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_signal.html
22*579d6ed4SDavid Zarzycki //
23*579d6ed4SDavid Zarzycki // Quote:
24*579d6ed4SDavid Zarzycki //     Multiple Awakenings by Condition Signal
25*579d6ed4SDavid Zarzycki //     On a multi-processor, it may be impossible for an implementation of
26*579d6ed4SDavid Zarzycki //     pthread_cond_signal() to avoid the unblocking of more than one thread
27*579d6ed4SDavid Zarzycki //     blocked on a condition variable. For example...
28*579d6ed4SDavid Zarzycki 
29*579d6ed4SDavid Zarzycki 
30*579d6ed4SDavid Zarzycki 
31*579d6ed4SDavid Zarzycki // NOTE: In previous versions of this test, `notify_one` was called WITHOUT
32*579d6ed4SDavid Zarzycki // holding the lock but POSIX says (in the aforementioned URL) that:
33*579d6ed4SDavid Zarzycki //     ...if predictable scheduling behavior is required, then that mutex shall
34*579d6ed4SDavid Zarzycki //     be locked by the thread calling pthread_cond_broadcast() or
35*579d6ed4SDavid Zarzycki //     pthread_cond_signal().
36*579d6ed4SDavid Zarzycki 
37*579d6ed4SDavid Zarzycki 
385a83710eSEric Fiselier #include <condition_variable>
3992499e45SEric Fiselier #include <atomic>
405a83710eSEric Fiselier #include <mutex>
415a83710eSEric Fiselier #include <thread>
425a83710eSEric Fiselier #include <cassert>
435a83710eSEric Fiselier 
447fc6a556SMarshall Clow #include "test_macros.h"
457fc6a556SMarshall Clow 
4610967a6eSEric Fiselier 
475a83710eSEric Fiselier std::condition_variable cv;
485a83710eSEric Fiselier std::mutex mut;
495a83710eSEric Fiselier 
5092499e45SEric Fiselier std::atomic_int test1(0);
5192499e45SEric Fiselier std::atomic_int test2(0);
521c4238e7SDavid Zarzycki std::atomic_int ready(2);
531c4238e7SDavid Zarzycki std::atomic_int which(0);
545a83710eSEric Fiselier 
555a83710eSEric Fiselier void f1()
565a83710eSEric Fiselier {
575a83710eSEric Fiselier   std::unique_lock<std::mutex> lk(mut);
585a83710eSEric Fiselier   assert(test1 == 0);
59*579d6ed4SDavid Zarzycki   --ready;
605a83710eSEric Fiselier   while (test1 == 0)
615a83710eSEric Fiselier     cv.wait(lk);
621c4238e7SDavid Zarzycki   which = 1;
635a83710eSEric Fiselier   assert(test1 == 1);
645a83710eSEric Fiselier   test1 = 2;
655a83710eSEric Fiselier }
665a83710eSEric Fiselier 
675a83710eSEric Fiselier void f2()
685a83710eSEric Fiselier {
695a83710eSEric Fiselier   std::unique_lock<std::mutex> lk(mut);
705a83710eSEric Fiselier   assert(test2 == 0);
71*579d6ed4SDavid Zarzycki   --ready;
725a83710eSEric Fiselier   while (test2 == 0)
735a83710eSEric Fiselier     cv.wait(lk);
741c4238e7SDavid Zarzycki   which = 2;
755a83710eSEric Fiselier   assert(test2 == 1);
765a83710eSEric Fiselier   test2 = 2;
775a83710eSEric Fiselier }
785a83710eSEric Fiselier 
792df59c50SJF Bastien int main(int, char**)
805a83710eSEric Fiselier {
815a83710eSEric Fiselier   std::thread t1(f1);
825a83710eSEric Fiselier   std::thread t2(f2);
83*579d6ed4SDavid Zarzycki   {
841c4238e7SDavid Zarzycki     while (ready > 0)
851c4238e7SDavid Zarzycki       std::this_thread::yield();
86*579d6ed4SDavid Zarzycki     // At this point:
87*579d6ed4SDavid Zarzycki     // 1) Both f1 and f2 have entered their condition variable wait.
88*579d6ed4SDavid Zarzycki     // 2) Either f1 or f2 has the mutex locked and is about to wait.
895a83710eSEric Fiselier     std::unique_lock<std::mutex> lk(mut);
905a83710eSEric Fiselier     test1 = 1;
915a83710eSEric Fiselier     test2 = 1;
921c4238e7SDavid Zarzycki     ready = 1;
935a83710eSEric Fiselier     cv.notify_one();
94*579d6ed4SDavid Zarzycki   }
955a83710eSEric Fiselier   {
961c4238e7SDavid Zarzycki     while (which == 0)
971c4238e7SDavid Zarzycki       std::this_thread::yield();
985a83710eSEric Fiselier     std::unique_lock<std::mutex> lk(mut);
991c4238e7SDavid Zarzycki     if (test1 == 2) {
10010967a6eSEric Fiselier       assert(test2 == 1);
1015a83710eSEric Fiselier       t1.join();
1025a83710eSEric Fiselier       test1 = 0;
1031c4238e7SDavid Zarzycki     } else {
10410967a6eSEric Fiselier       assert(test1 == 1);
1051c4238e7SDavid Zarzycki       assert(test2 == 2);
1065a83710eSEric Fiselier       t2.join();
1075a83710eSEric Fiselier       test2 = 0;
1085a83710eSEric Fiselier     }
1091c4238e7SDavid Zarzycki     which = 0;
1105a83710eSEric Fiselier     cv.notify_one();
111*579d6ed4SDavid Zarzycki   }
1125a83710eSEric Fiselier   {
1131c4238e7SDavid Zarzycki     while (which == 0)
1141c4238e7SDavid Zarzycki       std::this_thread::yield();
1155a83710eSEric Fiselier     std::unique_lock<std::mutex> lk(mut);
1161c4238e7SDavid Zarzycki     if (test1 == 2) {
11710967a6eSEric Fiselier       assert(test2 == 0);
1185a83710eSEric Fiselier       t1.join();
1195a83710eSEric Fiselier       test1 = 0;
1201c4238e7SDavid Zarzycki     } else {
12110967a6eSEric Fiselier       assert(test1 == 0);
1221c4238e7SDavid Zarzycki       assert(test2 == 2);
1235a83710eSEric Fiselier       t2.join();
1245a83710eSEric Fiselier       test2 = 0;
1255a83710eSEric Fiselier     }
126*579d6ed4SDavid Zarzycki   }
1272df59c50SJF Bastien 
1282df59c50SJF Bastien   return 0;
1295a83710eSEric Fiselier }
130