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_CAPABILITY(x) __attribute__((capability(x))) |
56 | #else |
57 | #define GOOGLE_PROTOBUF_ACQUIRE(...) |
58 | #define GOOGLE_PROTOBUF_RELEASE(...) |
59 | #define GOOGLE_PROTOBUF_CAPABILITY(x) |
60 | #endif |
61 | |
62 | #include <google/protobuf/port_def.inc> |
63 | |
64 | // =================================================================== |
65 | // emulates google3/base/mutex.h |
66 | namespace google { |
67 | namespace protobuf { |
68 | namespace internal { |
69 | |
70 | #define GOOGLE_PROTOBUF_LINKER_INITIALIZED |
71 | |
72 | #ifdef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP |
73 | |
74 | // This class is a lightweight replacement for std::mutex on Windows platforms. |
75 | // std::mutex does not work on Windows XP SP2 with the latest VC++ libraries, |
76 | // because it utilizes the Concurrency Runtime that is only supported on Windows |
77 | // XP SP3 and above. |
78 | class PROTOBUF_EXPORT CriticalSectionLock { |
79 | public: |
80 | CriticalSectionLock() { InitializeCriticalSection(&critical_section_); } |
81 | ~CriticalSectionLock() { DeleteCriticalSection(&critical_section_); } |
82 | void lock() { EnterCriticalSection(&critical_section_); } |
83 | void unlock() { LeaveCriticalSection(&critical_section_); } |
84 | |
85 | private: |
86 | CRITICAL_SECTION critical_section_; |
87 | |
88 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CriticalSectionLock); |
89 | }; |
90 | |
91 | #endif |
92 | |
93 | // Mutex is a natural type to wrap. As both google and other organization have |
94 | // specialized mutexes. gRPC also provides an injection mechanism for custom |
95 | // mutexes. |
96 | class GOOGLE_PROTOBUF_CAPABILITY("mutex" ) PROTOBUF_EXPORT WrappedMutex { |
97 | public: |
98 | WrappedMutex() = default; |
99 | void Lock() GOOGLE_PROTOBUF_ACQUIRE() { mu_.lock(); } |
100 | void Unlock() GOOGLE_PROTOBUF_RELEASE() { mu_.unlock(); } |
101 | // Crash if this Mutex is not held exclusively by this thread. |
102 | // May fail to crash when it should; will never crash when it should not. |
103 | void AssertHeld() const {} |
104 | |
105 | private: |
106 | #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP |
107 | std::mutex mu_; |
108 | #else // ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP |
109 | CriticalSectionLock mu_; |
110 | #endif // #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP |
111 | }; |
112 | |
113 | using Mutex = WrappedMutex; |
114 | |
115 | // MutexLock(mu) acquires mu when constructed and releases it when destroyed. |
116 | class PROTOBUF_EXPORT MutexLock { |
117 | public: |
118 | explicit MutexLock(Mutex *mu) : mu_(mu) { this->mu_->Lock(); } |
119 | ~MutexLock() { this->mu_->Unlock(); } |
120 | private: |
121 | Mutex *const mu_; |
122 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock); |
123 | }; |
124 | |
125 | // TODO(kenton): Implement these? Hard to implement portably. |
126 | typedef MutexLock ReaderMutexLock; |
127 | typedef MutexLock WriterMutexLock; |
128 | |
129 | // MutexLockMaybe is like MutexLock, but is a no-op when mu is nullptr. |
130 | class PROTOBUF_EXPORT MutexLockMaybe { |
131 | public: |
132 | explicit MutexLockMaybe(Mutex *mu) : |
133 | mu_(mu) { if (this->mu_ != nullptr) { this->mu_->Lock(); } } |
134 | ~MutexLockMaybe() { if (this->mu_ != nullptr) { this->mu_->Unlock(); } } |
135 | private: |
136 | Mutex *const mu_; |
137 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe); |
138 | }; |
139 | |
140 | #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL) |
141 | template<typename T> |
142 | class ThreadLocalStorage { |
143 | public: |
144 | ThreadLocalStorage() { |
145 | pthread_key_create(&key_, &ThreadLocalStorage::Delete); |
146 | } |
147 | ~ThreadLocalStorage() { |
148 | pthread_key_delete(key_); |
149 | } |
150 | T* Get() { |
151 | T* result = static_cast<T*>(pthread_getspecific(key_)); |
152 | if (result == nullptr) { |
153 | result = new T(); |
154 | pthread_setspecific(key_, result); |
155 | } |
156 | return result; |
157 | } |
158 | private: |
159 | static void Delete(void* value) { |
160 | delete static_cast<T*>(value); |
161 | } |
162 | pthread_key_t key_; |
163 | |
164 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadLocalStorage); |
165 | }; |
166 | #endif |
167 | |
168 | } // namespace internal |
169 | |
170 | // We made these internal so that they would show up as such in the docs, |
171 | // but we don't want to stick "internal::" in front of them everywhere. |
172 | using internal::Mutex; |
173 | using internal::MutexLock; |
174 | using internal::ReaderMutexLock; |
175 | using internal::WriterMutexLock; |
176 | using internal::MutexLockMaybe; |
177 | |
178 | } // namespace protobuf |
179 | } // namespace google |
180 | |
181 | #undef GOOGLE_PROTOBUF_ACQUIRE |
182 | #undef GOOGLE_PROTOBUF_RELEASE |
183 | |
184 | #include <google/protobuf/port_undef.inc> |
185 | |
186 | #endif // GOOGLE_PROTOBUF_STUBS_MUTEX_H_ |
187 | |