]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | // This source code is licensed under the BSD-style license found in the | |
3 | // LICENSE file in the root directory of this source tree. An additional grant | |
4 | // of patent rights can be found in the PATENTS file in the same directory. | |
5 | // | |
6 | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. | |
7 | // Use of this source code is governed by a BSD-style license that can be | |
8 | // found in the LICENSE file. See the AUTHORS file for names of contributors. | |
9 | ||
10 | #pragma once | |
11 | #include <assert.h> | |
12 | #include <atomic> | |
13 | #include <mutex> | |
14 | #include <thread> | |
15 | #include "port/port.h" | |
16 | ||
17 | namespace rocksdb { | |
18 | ||
19 | // Helper class that locks a mutex on construction and unlocks the mutex when | |
20 | // the destructor of the MutexLock object is invoked. | |
21 | // | |
22 | // Typical usage: | |
23 | // | |
24 | // void MyClass::MyMethod() { | |
25 | // MutexLock l(&mu_); // mu_ is an instance variable | |
26 | // ... some complex code, possibly with multiple return paths ... | |
27 | // } | |
28 | ||
29 | class MutexLock { | |
30 | public: | |
31 | explicit MutexLock(port::Mutex *mu) : mu_(mu) { | |
32 | this->mu_->Lock(); | |
33 | } | |
34 | ~MutexLock() { this->mu_->Unlock(); } | |
35 | ||
36 | private: | |
37 | port::Mutex *const mu_; | |
38 | // No copying allowed | |
39 | MutexLock(const MutexLock&); | |
40 | void operator=(const MutexLock&); | |
41 | }; | |
42 | ||
43 | // | |
44 | // Acquire a ReadLock on the specified RWMutex. | |
45 | // The Lock will be automatically released then the | |
46 | // object goes out of scope. | |
47 | // | |
48 | class ReadLock { | |
49 | public: | |
50 | explicit ReadLock(port::RWMutex *mu) : mu_(mu) { | |
51 | this->mu_->ReadLock(); | |
52 | } | |
53 | ~ReadLock() { this->mu_->ReadUnlock(); } | |
54 | ||
55 | private: | |
56 | port::RWMutex *const mu_; | |
57 | // No copying allowed | |
58 | ReadLock(const ReadLock&); | |
59 | void operator=(const ReadLock&); | |
60 | }; | |
61 | ||
62 | // | |
63 | // Automatically unlock a locked mutex when the object is destroyed | |
64 | // | |
65 | class ReadUnlock { | |
66 | public: | |
67 | explicit ReadUnlock(port::RWMutex *mu) : mu_(mu) { mu->AssertHeld(); } | |
68 | ~ReadUnlock() { mu_->ReadUnlock(); } | |
69 | ||
70 | private: | |
71 | port::RWMutex *const mu_; | |
72 | // No copying allowed | |
73 | ReadUnlock(const ReadUnlock &) = delete; | |
74 | ReadUnlock &operator=(const ReadUnlock &) = delete; | |
75 | }; | |
76 | ||
77 | // | |
78 | // Acquire a WriteLock on the specified RWMutex. | |
79 | // The Lock will be automatically released then the | |
80 | // object goes out of scope. | |
81 | // | |
82 | class WriteLock { | |
83 | public: | |
84 | explicit WriteLock(port::RWMutex *mu) : mu_(mu) { | |
85 | this->mu_->WriteLock(); | |
86 | } | |
87 | ~WriteLock() { this->mu_->WriteUnlock(); } | |
88 | ||
89 | private: | |
90 | port::RWMutex *const mu_; | |
91 | // No copying allowed | |
92 | WriteLock(const WriteLock&); | |
93 | void operator=(const WriteLock&); | |
94 | }; | |
95 | ||
96 | // | |
97 | // SpinMutex has very low overhead for low-contention cases. Method names | |
98 | // are chosen so you can use std::unique_lock or std::lock_guard with it. | |
99 | // | |
100 | class SpinMutex { | |
101 | public: | |
102 | SpinMutex() : locked_(false) {} | |
103 | ||
104 | bool try_lock() { | |
105 | auto currently_locked = locked_.load(std::memory_order_relaxed); | |
106 | return !currently_locked && | |
107 | locked_.compare_exchange_weak(currently_locked, true, | |
108 | std::memory_order_acquire, | |
109 | std::memory_order_relaxed); | |
110 | } | |
111 | ||
112 | void lock() { | |
113 | for (size_t tries = 0;; ++tries) { | |
114 | if (try_lock()) { | |
115 | // success | |
116 | break; | |
117 | } | |
118 | port::AsmVolatilePause(); | |
119 | if (tries > 100) { | |
120 | std::this_thread::yield(); | |
121 | } | |
122 | } | |
123 | } | |
124 | ||
125 | void unlock() { locked_.store(false, std::memory_order_release); } | |
126 | ||
127 | private: | |
128 | std::atomic<bool> locked_; | |
129 | }; | |
130 | ||
131 | } // namespace rocksdb |