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
41 namespace google {
42 namespace protobuf {
43 namespace 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.
48 class 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.
82 class LIBPROTOBUF_EXPORT MutexLock {
83  public:
MutexLock(Mutex * mu)84   explicit MutexLock(Mutex *mu) : mu_(mu) { this->mu_->Lock(); }
~MutexLock()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.
92 typedef MutexLock ReaderMutexLock;
93 typedef MutexLock WriterMutexLock;
94 
95 // MutexLockMaybe is like MutexLock, but is a no-op when mu is NULL.
96 class LIBPROTOBUF_EXPORT MutexLockMaybe {
97  public:
MutexLockMaybe(Mutex * mu)98   explicit MutexLockMaybe(Mutex *mu) :
99     mu_(mu) { if (this->mu_ != NULL) { this->mu_->Lock(); } }
~MutexLockMaybe()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)
107 template<typename T>
108 class ThreadLocalStorage {
109  public:
ThreadLocalStorage()110   ThreadLocalStorage() {
111     pthread_key_create(&key_, &ThreadLocalStorage::Delete);
112   }
~ThreadLocalStorage()113   ~ThreadLocalStorage() {
114     pthread_key_delete(key_);
115   }
Get()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:
Delete(void * value)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.
138 using internal::Mutex;
139 using internal::MutexLock;
140 using internal::ReaderMutexLock;
141 using internal::WriterMutexLock;
142 using internal::MutexLockMaybe;
143 
144 
145 }  // namespace protobuf
146 }  // namespace google
147 
148 #endif  // GOOGLE_PROTOBUF_STUBS_MUTEX_H_
149