1 /**
2 * Copyright 2019 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "minddata/dataset/util/lock.h"
17 #include "minddata/dataset/util/log_adapter.h"
18
19 namespace mindspore {
20 namespace dataset {
Lock()21 void SpinLock::Lock() {
22 while (true) {
23 int expected = kUnlocked;
24 if (val_.compare_exchange_weak(expected, kLocked)) {
25 break;
26 }
27 }
28 }
29
TryLock()30 bool SpinLock::TryLock() {
31 int expected = kUnlocked;
32 return val_.compare_exchange_strong(expected, kLocked);
33 }
34
Unlock()35 void SpinLock::Unlock() noexcept { val_.store(kUnlocked); }
36
LockShared()37 void RWLock::LockShared() {
38 std::unique_lock<std::mutex> lck(mtx_);
39 waiting_readers_ += 1;
40 read_cv_.wait(lck, [this]() { return (waiting_writers_ == 0 && status_ >= 0); });
41 waiting_readers_ -= 1;
42 status_ += 1;
43 }
44
Unlock()45 void RWLock::Unlock() noexcept {
46 std::unique_lock<std::mutex> lck(mtx_);
47 if (status_ == -1) {
48 // I am the writer. By definition, no other writer nor reader.
49 status_ = 0;
50 } else if (status_ > 0) {
51 // One less reader
52 status_ -= 1;
53 }
54 // Wake up writer only if there is no reader.
55 if (waiting_writers_ > 0) {
56 if (status_ == 0) {
57 write_cv_.notify_one();
58 }
59 } else {
60 read_cv_.notify_all();
61 }
62 }
63
Upgrade()64 void RWLock::Upgrade() {
65 std::unique_lock<std::mutex> lck(mtx_);
66 if (status_ == -1) {
67 // I am a writer already.
68 return;
69 } else if (status_ == 1) {
70 // If I am the only reader. Just change the status.
71 status_ = -1;
72 return;
73 } else {
74 // In all other cases, let of the shared lock and relock in exclusive.
75 lck.unlock();
76 this->Unlock();
77 this->LockExclusive();
78 }
79 }
80
Downgrade()81 void RWLock::Downgrade() {
82 std::unique_lock<std::mutex> lck(mtx_);
83 if (status_ == -1) {
84 // If there are no other writers waiting, just change the status
85 if (waiting_writers_ == 0) {
86 status_ = 1;
87 } else {
88 // Otherwise just unlock and relock in shared
89 lck.unlock();
90 this->Unlock();
91 this->LockShared();
92 }
93 } else if (status_ > 0) {
94 return;
95 }
96 }
97
SharedLock(RWLock * rw)98 SharedLock::SharedLock(RWLock *rw) : rw_(rw), ownlock_(false) {
99 rw_->LockShared();
100 ownlock_ = true;
101 }
102
~SharedLock()103 SharedLock::~SharedLock() {
104 if (ownlock_) {
105 rw_->Unlock();
106 ownlock_ = false;
107 }
108 rw_ = nullptr;
109 }
110
Unlock()111 void SharedLock::Unlock() {
112 rw_->Unlock();
113 ownlock_ = false;
114 }
115
Lock()116 void SharedLock::Lock() {
117 rw_->LockShared();
118 ownlock_ = true;
119 }
120
Upgrade()121 void SharedLock::Upgrade() { rw_->Upgrade(); }
122
Downgrade()123 void SharedLock::Downgrade() { rw_->Downgrade(); }
124
UniqueLock(RWLock * rw)125 UniqueLock::UniqueLock(RWLock *rw) : rw_(rw), ownlock_(false) {
126 rw_->LockExclusive();
127 ownlock_ = true;
128 }
129
~UniqueLock()130 UniqueLock::~UniqueLock() {
131 if (ownlock_) {
132 rw_->Unlock();
133 ownlock_ = false;
134 }
135 rw_ = nullptr;
136 }
137
Unlock()138 void UniqueLock::Unlock() {
139 rw_->Unlock();
140 ownlock_ = false;
141 }
142
Lock()143 void UniqueLock::Lock() {
144 rw_->LockExclusive();
145 ownlock_ = true;
146 }
147
LockGuard(SpinLock * lock)148 LockGuard::LockGuard(SpinLock *lock) : lck_(lock), own_lock_(false) {
149 lck_->Lock();
150 own_lock_ = true;
151 }
152
~LockGuard()153 LockGuard::~LockGuard() {
154 if (own_lock_) {
155 lck_->Unlock();
156 own_lock_ = false;
157 }
158 lck_ = nullptr;
159 }
160
Unlock()161 void LockGuard::Unlock() {
162 lck_->Unlock();
163 own_lock_ = false;
164 }
165
Lock()166 void LockGuard::Lock() {
167 lck_->Lock();
168 own_lock_ = true;
169 }
170 } // namespace dataset
171 } // namespace mindspore
172