aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/protobuf_old/src/google/protobuf/stubs/mutex.h
blob: c4599913be22350c2d718c3c48d034d75bf41e51 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef GOOGLE_PROTOBUF_STUBS_MUTEX_H_
#define GOOGLE_PROTOBUF_STUBS_MUTEX_H_

#include <mutex>

#ifdef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP

#include <windows.h>

// GetMessage conflicts with GeneratedMessageReflection::GetMessage().
#ifdef GetMessage
#undef GetMessage
#endif

#endif

#include <google/protobuf/stubs/macros.h>

// Define thread-safety annotations for use below, if we are building with
// Clang.
#if defined(__clang__) && !defined(SWIG)
#define GOOGLE_PROTOBUF_ACQUIRE(...) \
  __attribute__((acquire_capability(__VA_ARGS__)))
#define GOOGLE_PROTOBUF_RELEASE(...) \
  __attribute__((release_capability(__VA_ARGS__)))
#define GOOGLE_PROTOBUF_SCOPED_CAPABILITY __attribute__((scoped_lockable))
#define GOOGLE_PROTOBUF_CAPABILITY(x) __attribute__((capability(x)))
#else
#define GOOGLE_PROTOBUF_ACQUIRE(...)
#define GOOGLE_PROTOBUF_RELEASE(...)
#define GOOGLE_PROTOBUF_SCOPED_CAPABILITY
#define GOOGLE_PROTOBUF_CAPABILITY(x)
#endif

#include <google/protobuf/port_def.inc>

// ===================================================================
// emulates google3/base/mutex.h
namespace google {
namespace protobuf {
namespace internal {

#define GOOGLE_PROTOBUF_LINKER_INITIALIZED

#ifdef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP

// This class is a lightweight replacement for std::mutex on Windows platforms.
// std::mutex does not work on Windows XP SP2 with the latest VC++ libraries,
// because it utilizes the Concurrency Runtime that is only supported on Windows
// XP SP3 and above.
class PROTOBUF_EXPORT CriticalSectionLock {
 public:
  CriticalSectionLock() { InitializeCriticalSection(&critical_section_); }
  ~CriticalSectionLock() { DeleteCriticalSection(&critical_section_); }
  void lock() { EnterCriticalSection(&critical_section_); }
  void unlock() { LeaveCriticalSection(&critical_section_); }

 private:
  CRITICAL_SECTION critical_section_;

  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CriticalSectionLock);
};

#endif

// In MSVC std::mutex does not have a constexpr constructor.
// This wrapper makes the constructor constexpr.
template <typename T>
class CallOnceInitializedMutex {
 public:
  constexpr CallOnceInitializedMutex() : flag_{}, buf_{} {}
  ~CallOnceInitializedMutex() { get().~T(); }

  void lock() { get().lock(); }
  void unlock() { get().unlock(); }

 private:
  T& get() {
    std::call_once(flag_, [&] { ::new (static_cast<void*>(&buf_)) T(); });
    return reinterpret_cast<T&>(buf_);
  }

  std::once_flag flag_;
  alignas(T) char buf_[sizeof(T)];
};

// Mutex is a natural type to wrap. As both google and other organization have
// specialized mutexes. gRPC also provides an injection mechanism for custom
// mutexes.
class GOOGLE_PROTOBUF_CAPABILITY("mutex") PROTOBUF_EXPORT WrappedMutex {
 public:
#if defined(__QNX__)
  constexpr WrappedMutex() = default;
#else
  constexpr WrappedMutex() {}
#endif
  void Lock() GOOGLE_PROTOBUF_ACQUIRE() { mu_.lock(); }
  void Unlock() GOOGLE_PROTOBUF_RELEASE() { mu_.unlock(); }
  // Crash if this Mutex is not held exclusively by this thread.
  // May fail to crash when it should; will never crash when it should not.
  void AssertHeld() const {}

 private:
#if defined(GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP)
  CallOnceInitializedMutex<CriticalSectionLock> mu_{};
#elif defined(_WIN32)
  CallOnceInitializedMutex<std::mutex> mu_{};
#else
  std::mutex mu_{};
#endif
};

using Mutex = WrappedMutex;

// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
class GOOGLE_PROTOBUF_SCOPED_CAPABILITY PROTOBUF_EXPORT MutexLock {
 public:
  explicit MutexLock(Mutex* mu) GOOGLE_PROTOBUF_ACQUIRE(mu) : mu_(mu) {
    this->mu_->Lock();
  }
  ~MutexLock() GOOGLE_PROTOBUF_RELEASE() { this->mu_->Unlock(); }

 private:
  Mutex *const mu_;
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock);
};

// TODO(kenton):  Implement these?  Hard to implement portably.
typedef MutexLock ReaderMutexLock;
typedef MutexLock WriterMutexLock;

// MutexLockMaybe is like MutexLock, but is a no-op when mu is nullptr.
class PROTOBUF_EXPORT MutexLockMaybe {
 public:
  explicit MutexLockMaybe(Mutex *mu) :
    mu_(mu) { if (this->mu_ != nullptr) { this->mu_->Lock(); } }
  ~MutexLockMaybe() { if (this->mu_ != nullptr) { this->mu_->Unlock(); } }
 private:
  Mutex *const mu_;
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe);
};

#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
template<typename T>
class ThreadLocalStorage {
 public:
  ThreadLocalStorage() {
    pthread_key_create(&key_, &ThreadLocalStorage::Delete);
  }
  ~ThreadLocalStorage() {
    pthread_key_delete(key_);
  }
  T* Get() {
    T* result = static_cast<T*>(pthread_getspecific(key_));
    if (result == nullptr) {
      result = new T();
      pthread_setspecific(key_, result);
    }
    return result;
  }
 private:
  static void Delete(void* value) {
    delete static_cast<T*>(value);
  }
  pthread_key_t key_;

  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadLocalStorage);
};
#endif

}  // namespace internal

// We made these internal so that they would show up as such in the docs,
// but we don't want to stick "internal::" in front of them everywhere.
using internal::Mutex;
using internal::MutexLock;
using internal::ReaderMutexLock;
using internal::WriterMutexLock;
using internal::MutexLockMaybe;

}  // namespace protobuf
}  // namespace google

#undef GOOGLE_PROTOBUF_ACQUIRE
#undef GOOGLE_PROTOBUF_RELEASE

#include <google/protobuf/port_undef.inc>

#endif  // GOOGLE_PROTOBUF_STUBS_MUTEX_H_