1//===---------------------- shared_mutex.cpp ------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "__config"
10#ifndef _LIBCPP_HAS_NO_THREADS
11
12#include "shared_mutex"
13#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
14#pragma comment(lib, "pthread")
15#endif
16
17_LIBCPP_BEGIN_NAMESPACE_STD
18
19// Shared Mutex Base
20__shared_mutex_base::__shared_mutex_base()
21    : __state_(0)
22{
23}
24
25// Exclusive ownership
26
27void
28__shared_mutex_base::lock()
29{
30    unique_lock<mutex> lk(__mut_);
31    while (__state_ & __write_entered_)
32        __gate1_.wait(lk);
33    __state_ |= __write_entered_;
34    while (__state_ & __n_readers_)
35        __gate2_.wait(lk);
36}
37
38bool
39__shared_mutex_base::try_lock()
40{
41    unique_lock<mutex> lk(__mut_);
42    if (__state_ == 0)
43    {
44        __state_ = __write_entered_;
45        return true;
46    }
47    return false;
48}
49
50void
51__shared_mutex_base::unlock()
52{
53    lock_guard<mutex> _(__mut_);
54    __state_ = 0;
55    __gate1_.notify_all();
56}
57
58// Shared ownership
59
60void
61__shared_mutex_base::lock_shared()
62{
63    unique_lock<mutex> lk(__mut_);
64    while ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_)
65        __gate1_.wait(lk);
66    unsigned num_readers = (__state_ & __n_readers_) + 1;
67    __state_ &= ~__n_readers_;
68    __state_ |= num_readers;
69}
70
71bool
72__shared_mutex_base::try_lock_shared()
73{
74    unique_lock<mutex> lk(__mut_);
75    unsigned num_readers = __state_ & __n_readers_;
76    if (!(__state_ & __write_entered_) && num_readers != __n_readers_)
77    {
78        ++num_readers;
79        __state_ &= ~__n_readers_;
80        __state_ |= num_readers;
81        return true;
82    }
83    return false;
84}
85
86void
87__shared_mutex_base::unlock_shared()
88{
89    lock_guard<mutex> _(__mut_);
90    unsigned num_readers = (__state_ & __n_readers_) - 1;
91    __state_ &= ~__n_readers_;
92    __state_ |= num_readers;
93    if (__state_ & __write_entered_)
94    {
95        if (num_readers == 0)
96            __gate2_.notify_one();
97    }
98    else
99    {
100        if (num_readers == __n_readers_ - 1)
101            __gate1_.notify_one();
102    }
103}
104
105
106// Shared Timed Mutex
107// These routines are here for ABI stability
108shared_timed_mutex::shared_timed_mutex() : __base() {}
109void shared_timed_mutex::lock()     { return __base.lock(); }
110bool shared_timed_mutex::try_lock() { return __base.try_lock(); }
111void shared_timed_mutex::unlock()   { return __base.unlock(); }
112void shared_timed_mutex::lock_shared() { return __base.lock_shared(); }
113bool shared_timed_mutex::try_lock_shared() { return __base.try_lock_shared(); }
114void shared_timed_mutex::unlock_shared() { return __base.unlock_shared(); }
115
116_LIBCPP_END_NAMESPACE_STD
117
118#endif // !_LIBCPP_HAS_NO_THREADS
119