1 | // Copyright (c) 2006, Google Inc. |
2 | // All rights reserved. |
3 | // |
4 | // Redistribution and use in source and binary forms, with or without |
5 | // modification, are permitted provided that the following conditions are |
6 | // met: |
7 | // |
8 | // * Redistributions of source code must retain the above copyright |
9 | // notice, this list of conditions and the following disclaimer. |
10 | // * Redistributions in binary form must reproduce the above |
11 | // copyright notice, this list of conditions and the following disclaimer |
12 | // in the documentation and/or other materials provided with the |
13 | // distribution. |
14 | // * Neither the name of Google Inc. nor the names of its |
15 | // contributors may be used to endorse or promote products derived from |
16 | // this software without specific prior written permission. |
17 | // |
18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | |
30 | #ifndef GOOGLE_PROTOBUF_STUBS_MUTEX_H_ |
31 | #define GOOGLE_PROTOBUF_STUBS_MUTEX_H_ |
32 | |
33 | #include <mutex> |
34 | |
35 | #ifdef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP |
36 | |
37 | #include <windows.h> |
38 | |
39 | // GetMessage conflicts with GeneratedMessageReflection::GetMessage(). |
40 | #ifdef GetMessage |
41 | #undef GetMessage |
42 | #endif |
43 | |
44 | #endif |
45 | |
46 | #include <google/protobuf/stubs/macros.h> |
47 | |
48 | // Define thread-safety annotations for use below, if we are building with |
49 | // Clang. |
50 | #if defined(__clang__) && !defined(SWIG) |
51 | #define GOOGLE_PROTOBUF_ACQUIRE(...) \ |
52 | __attribute__((acquire_capability(__VA_ARGS__))) |
53 | #define GOOGLE_PROTOBUF_RELEASE(...) \ |
54 | __attribute__((release_capability(__VA_ARGS__))) |
55 | #define GOOGLE_PROTOBUF_SCOPED_CAPABILITY __attribute__((scoped_lockable)) |
56 | #define GOOGLE_PROTOBUF_CAPABILITY(x) __attribute__((capability(x))) |
57 | #else |
58 | #define GOOGLE_PROTOBUF_ACQUIRE(...) |
59 | #define GOOGLE_PROTOBUF_RELEASE(...) |
60 | #define GOOGLE_PROTOBUF_SCOPED_CAPABILITY |
61 | #define GOOGLE_PROTOBUF_CAPABILITY(x) |
62 | #endif |
63 | |
64 | #include <google/protobuf/port_def.inc> |
65 | |
66 | // =================================================================== |
67 | // emulates google3/base/mutex.h |
68 | namespace google { |
69 | namespace protobuf { |
70 | namespace internal { |
71 | |
72 | #define GOOGLE_PROTOBUF_LINKER_INITIALIZED |
73 | |
74 | #ifdef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP |
75 | |
76 | // This class is a lightweight replacement for std::mutex on Windows platforms. |
77 | // std::mutex does not work on Windows XP SP2 with the latest VC++ libraries, |
78 | // because it utilizes the Concurrency Runtime that is only supported on Windows |
79 | // XP SP3 and above. |
80 | class PROTOBUF_EXPORT CriticalSectionLock { |
81 | public: |
82 | CriticalSectionLock() { InitializeCriticalSection(&critical_section_); } |
83 | ~CriticalSectionLock() { DeleteCriticalSection(&critical_section_); } |
84 | void lock() { EnterCriticalSection(&critical_section_); } |
85 | void unlock() { LeaveCriticalSection(&critical_section_); } |
86 | |
87 | private: |
88 | CRITICAL_SECTION critical_section_; |
89 | |
90 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CriticalSectionLock); |
91 | }; |
92 | |
93 | #endif |
94 | |
95 | // In MSVC std::mutex does not have a constexpr constructor. |
96 | // This wrapper makes the constructor constexpr. |
97 | template <typename T> |
98 | class CallOnceInitializedMutex { |
99 | public: |
100 | constexpr CallOnceInitializedMutex() : flag_{}, buf_{} {} |
101 | ~CallOnceInitializedMutex() { get().~T(); } |
102 | |
103 | void lock() { get().lock(); } |
104 | void unlock() { get().unlock(); } |
105 | |
106 | private: |
107 | T& get() { |
108 | std::call_once(flag_, [&] { ::new (static_cast<void*>(&buf_)) T(); }); |
109 | return reinterpret_cast<T&>(buf_); |
110 | } |
111 | |
112 | std::once_flag flag_; |
113 | alignas(T) char buf_[sizeof(T)]; |
114 | }; |
115 | |
116 | // Mutex is a natural type to wrap. As both google and other organization have |
117 | // specialized mutexes. gRPC also provides an injection mechanism for custom |
118 | // mutexes. |
119 | class GOOGLE_PROTOBUF_CAPABILITY("mutex" ) PROTOBUF_EXPORT WrappedMutex { |
120 | public: |
121 | #if defined(__QNX__) |
122 | constexpr WrappedMutex() = default; |
123 | #else |
124 | constexpr WrappedMutex() {} |
125 | #endif |
126 | void Lock() GOOGLE_PROTOBUF_ACQUIRE() { mu_.lock(); } |
127 | void Unlock() GOOGLE_PROTOBUF_RELEASE() { mu_.unlock(); } |
128 | // Crash if this Mutex is not held exclusively by this thread. |
129 | // May fail to crash when it should; will never crash when it should not. |
130 | void AssertHeld() const {} |
131 | |
132 | private: |
133 | #if defined(GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP) |
134 | CallOnceInitializedMutex<CriticalSectionLock> mu_{}; |
135 | #elif defined(_WIN32) |
136 | CallOnceInitializedMutex<std::mutex> mu_{}; |
137 | #else |
138 | std::mutex mu_{}; |
139 | #endif |
140 | }; |
141 | |
142 | using Mutex = WrappedMutex; |
143 | |
144 | // MutexLock(mu) acquires mu when constructed and releases it when destroyed. |
145 | class GOOGLE_PROTOBUF_SCOPED_CAPABILITY PROTOBUF_EXPORT MutexLock { |
146 | public: |
147 | explicit MutexLock(Mutex* mu) GOOGLE_PROTOBUF_ACQUIRE(mu) : mu_(mu) { |
148 | this->mu_->Lock(); |
149 | } |
150 | ~MutexLock() GOOGLE_PROTOBUF_RELEASE() { this->mu_->Unlock(); } |
151 | |
152 | private: |
153 | Mutex *const mu_; |
154 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock); |
155 | }; |
156 | |
157 | // TODO(kenton): Implement these? Hard to implement portably. |
158 | typedef MutexLock ReaderMutexLock; |
159 | typedef MutexLock WriterMutexLock; |
160 | |
161 | // MutexLockMaybe is like MutexLock, but is a no-op when mu is nullptr. |
162 | class PROTOBUF_EXPORT MutexLockMaybe { |
163 | public: |
164 | explicit MutexLockMaybe(Mutex *mu) : |
165 | mu_(mu) { if (this->mu_ != nullptr) { this->mu_->Lock(); } } |
166 | ~MutexLockMaybe() { if (this->mu_ != nullptr) { this->mu_->Unlock(); } } |
167 | private: |
168 | Mutex *const mu_; |
169 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe); |
170 | }; |
171 | |
172 | #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL) |
173 | template<typename T> |
174 | class ThreadLocalStorage { |
175 | public: |
176 | ThreadLocalStorage() { |
177 | pthread_key_create(&key_, &ThreadLocalStorage::Delete); |
178 | } |
179 | ~ThreadLocalStorage() { |
180 | pthread_key_delete(key_); |
181 | } |
182 | T* Get() { |
183 | T* result = static_cast<T*>(pthread_getspecific(key_)); |
184 | if (result == nullptr) { |
185 | result = new T(); |
186 | pthread_setspecific(key_, result); |
187 | } |
188 | return result; |
189 | } |
190 | private: |
191 | static void Delete(void* value) { |
192 | delete static_cast<T*>(value); |
193 | } |
194 | pthread_key_t key_; |
195 | |
196 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadLocalStorage); |
197 | }; |
198 | #endif |
199 | |
200 | } // namespace internal |
201 | |
202 | // We made these internal so that they would show up as such in the docs, |
203 | // but we don't want to stick "internal::" in front of them everywhere. |
204 | using internal::Mutex; |
205 | using internal::MutexLock; |
206 | using internal::ReaderMutexLock; |
207 | using internal::WriterMutexLock; |
208 | using internal::MutexLockMaybe; |
209 | |
210 | } // namespace protobuf |
211 | } // namespace google |
212 | |
213 | #undef GOOGLE_PROTOBUF_ACQUIRE |
214 | #undef GOOGLE_PROTOBUF_RELEASE |
215 | |
216 | #include <google/protobuf/port_undef.inc> |
217 | |
218 | #endif // GOOGLE_PROTOBUF_STUBS_MUTEX_H_ |
219 | |