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