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