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#ifdef GOOGLE_PROTOBUF_NO_THREADLOCAL
34#include <pthread.h>
35#endif
36
37#include <google/protobuf/stubs/macros.h>
38
39// ===================================================================
40// emulates google3/base/mutex.h
41namespace google {
42namespace protobuf {
43namespace internal {
44
45// A Mutex is a non-reentrant (aka non-recursive) mutex.  At most one thread T
46// may hold a mutex at a given time.  If T attempts to Lock() the same Mutex
47// while holding it, T will deadlock.
48class LIBPROTOBUF_EXPORT Mutex {
49 public:
50  // Create a Mutex that is not held by anybody.
51  Mutex();
52
53  // Destructor
54  ~Mutex();
55
56  // Block if necessary until this Mutex is free, then acquire it exclusively.
57  void Lock();
58
59  // Release this Mutex.  Caller must hold it exclusively.
60  void Unlock();
61
62  // Crash if this Mutex is not held exclusively by this thread.
63  // May fail to crash when it should; will never crash when it should not.
64  void AssertHeld();
65
66 private:
67  struct Internal;
68  Internal* mInternal;
69
70  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Mutex);
71};
72
73// Undefine the macros  to workaround the conflicts with Google internal
74// MutexLock implementation.
75// TODO(liujisi): Remove the undef once internal macros are removed.
76#undef MutexLock
77#undef ReaderMutexLock
78#undef WriterMutexLock
79#undef MutexLockMaybe
80
81// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
82class LIBPROTOBUF_EXPORT MutexLock {
83 public:
84  explicit MutexLock(Mutex *mu) : mu_(mu) { this->mu_->Lock(); }
85  ~MutexLock() { this->mu_->Unlock(); }
86 private:
87  Mutex *const mu_;
88  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock);
89};
90
91// TODO(kenton):  Implement these?  Hard to implement portably.
92typedef MutexLock ReaderMutexLock;
93typedef MutexLock WriterMutexLock;
94
95// MutexLockMaybe is like MutexLock, but is a no-op when mu is NULL.
96class LIBPROTOBUF_EXPORT MutexLockMaybe {
97 public:
98  explicit MutexLockMaybe(Mutex *mu) :
99    mu_(mu) { if (this->mu_ != NULL) { this->mu_->Lock(); } }
100  ~MutexLockMaybe() { if (this->mu_ != NULL) { this->mu_->Unlock(); } }
101 private:
102  Mutex *const mu_;
103  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe);
104};
105
106#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
107template<typename T>
108class ThreadLocalStorage {
109 public:
110  ThreadLocalStorage() {
111    pthread_key_create(&key_, &ThreadLocalStorage::Delete);
112  }
113  ~ThreadLocalStorage() {
114    pthread_key_delete(key_);
115  }
116  T* Get() {
117    T* result = static_cast<T*>(pthread_getspecific(key_));
118    if (result == NULL) {
119      result = new T();
120      pthread_setspecific(key_, result);
121    }
122    return result;
123  }
124 private:
125  static void Delete(void* value) {
126    delete static_cast<T*>(value);
127  }
128  pthread_key_t key_;
129
130  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadLocalStorage);
131};
132#endif
133
134}  // namespace internal
135
136// We made these internal so that they would show up as such in the docs,
137// but we don't want to stick "internal::" in front of them everywhere.
138using internal::Mutex;
139using internal::MutexLock;
140using internal::ReaderMutexLock;
141using internal::WriterMutexLock;
142using internal::MutexLockMaybe;
143
144
145}  // namespace protobuf
146}  // namespace google
147
148#endif  // GOOGLE_PROTOBUF_STUBS_MUTEX_H_
149