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 //
9*a7f9895cSLouis Dionne // UNSUPPORTED: no-threads
1031cbe0f2SLouis Dionne // UNSUPPORTED: c++03, c++11
112659663eSLouis Dionne
122659663eSLouis Dionne // dylib support for shared_mutex was added in macosx10.12
13c360553cSLouis Dionne // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11}}
145a83710eSEric Fiselier
155a83710eSEric Fiselier // <shared_mutex>
165a83710eSEric Fiselier
175a83710eSEric Fiselier // class timed_mutex;
185a83710eSEric Fiselier
195a83710eSEric Fiselier // template <class Rep, class Period>
205a83710eSEric Fiselier // shared_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
215a83710eSEric Fiselier
225a83710eSEric Fiselier #include <thread>
23332da1c2SChristopher Di Bella
24332da1c2SChristopher Di Bella #include <atomic>
255a83710eSEric Fiselier #include <cassert>
26332da1c2SChristopher Di Bella #include <cstdlib>
27332da1c2SChristopher Di Bella #include <shared_mutex>
28332da1c2SChristopher Di Bella #include <vector>
295a83710eSEric Fiselier
3056462801SLouis Dionne #include "make_test_thread.h"
314c0a2a98SEric Fiselier #include "test_macros.h"
325a83710eSEric Fiselier
335a83710eSEric Fiselier std::shared_timed_mutex m;
345a83710eSEric Fiselier
355a83710eSEric Fiselier typedef std::chrono::steady_clock Clock;
365a83710eSEric Fiselier typedef Clock::time_point time_point;
375a83710eSEric Fiselier typedef Clock::duration duration;
385a83710eSEric Fiselier typedef std::chrono::milliseconds ms;
395a83710eSEric Fiselier typedef std::chrono::nanoseconds ns;
405a83710eSEric Fiselier
418aff6891SDavid Zarzycki ms LongTime = ms(5000);
428aff6891SDavid Zarzycki ms ShortTime = ms(50);
434c0a2a98SEric Fiselier
448aff6891SDavid Zarzycki static const unsigned Threads = 5;
454c0a2a98SEric Fiselier
46305b500eSLouis Dionne std::atomic<unsigned> CountDown(Threads);
474c0a2a98SEric Fiselier
f1()485a83710eSEric Fiselier void f1()
495a83710eSEric Fiselier {
508aff6891SDavid Zarzycki // Preemptive scheduling means that one cannot make assumptions about when
518aff6891SDavid Zarzycki // code executes and therefore we cannot assume anthing about when the mutex
528aff6891SDavid Zarzycki // starts waiting relative to code in the main thread. We can however prove
538aff6891SDavid Zarzycki // that a timeout occured and that implies that this code is waiting.
548aff6891SDavid Zarzycki // See f2() below.
558aff6891SDavid Zarzycki //
568aff6891SDavid Zarzycki // Nevertheless, we should at least try to ensure that the mutex waits and
578aff6891SDavid Zarzycki // therefore we use an atomic variable to signal to the main thread that this
588aff6891SDavid Zarzycki // code is just a few instructions away from waiting.
598aff6891SDavid Zarzycki --CountDown;
608aff6891SDavid Zarzycki std::shared_lock<std::shared_timed_mutex> lk(m, LongTime);
615a83710eSEric Fiselier assert(lk.owns_lock() == true);
625a83710eSEric Fiselier }
635a83710eSEric Fiselier
f2()645a83710eSEric Fiselier void f2()
655a83710eSEric Fiselier {
665a83710eSEric Fiselier time_point t0 = Clock::now();
678aff6891SDavid Zarzycki std::shared_lock<std::shared_timed_mutex> lk(m, ShortTime);
685a83710eSEric Fiselier time_point t1 = Clock::now();
698aff6891SDavid Zarzycki assert(lk.owns_lock() == false);
708aff6891SDavid Zarzycki assert(t1 - t0 >= ShortTime);
715a83710eSEric Fiselier }
725a83710eSEric Fiselier
main(int,char **)732df59c50SJF Bastien int main(int, char**)
745a83710eSEric Fiselier {
755a83710eSEric Fiselier {
765a83710eSEric Fiselier m.lock();
775a83710eSEric Fiselier std::vector<std::thread> v;
788aff6891SDavid Zarzycki for (unsigned i = 0; i < Threads; ++i)
7956462801SLouis Dionne v.push_back(support::make_test_thread(f1));
808aff6891SDavid Zarzycki while (CountDown > 0)
818aff6891SDavid Zarzycki std::this_thread::yield();
828aff6891SDavid Zarzycki // Give one more chance for threads to block and wait for the mutex.
838aff6891SDavid Zarzycki std::this_thread::yield();
848aff6891SDavid Zarzycki std::this_thread::sleep_for(ShortTime);
855a83710eSEric Fiselier m.unlock();
865a83710eSEric Fiselier for (auto& t : v)
875a83710eSEric Fiselier t.join();
885a83710eSEric Fiselier }
895a83710eSEric Fiselier {
905a83710eSEric Fiselier m.lock();
915a83710eSEric Fiselier std::vector<std::thread> v;
928aff6891SDavid Zarzycki for (unsigned i = 0; i < Threads; ++i)
9356462801SLouis Dionne v.push_back(support::make_test_thread(f2));
945a83710eSEric Fiselier for (auto& t : v)
955a83710eSEric Fiselier t.join();
968aff6891SDavid Zarzycki m.unlock();
975a83710eSEric Fiselier }
982df59c50SJF Bastien
992df59c50SJF Bastien return 0;
1005a83710eSEric Fiselier }
101