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