• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Mutex.cpp -----------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Host/Mutex.h"
11 #include "lldb/Host/Host.h"
12 
13 #include <string.h>
14 #include <stdio.h>
15 #include <unistd.h>
16 
17 #if 0
18 // This logging is way too verbose to enable even for a log channel.
19 // This logging can be enabled by changing the "#if 0", but should be
20 // reverted prior to checking in.
21 #include <cstdio>
22 #define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__)
23 #else
24 #define DEBUG_LOG(fmt, ...)
25 #endif
26 
27 // Enable extra mutex error checking
28 #ifdef LLDB_CONFIGURATION_DEBUG
29 #define ENABLE_MUTEX_ERROR_CHECKING 1
30 #include <inttypes.h>
31 #endif
32 
33 #if ENABLE_MUTEX_ERROR_CHECKING
34 #include <set>
35 
36 enum MutexAction
37 {
38     eMutexActionInitialized,
39     eMutexActionDestroyed,
40     eMutexActionAssertInitialized
41 };
42 
43 static bool
error_check_mutex(pthread_mutex_t * m,MutexAction action)44 error_check_mutex (pthread_mutex_t *m, MutexAction action)
45 {
46     typedef std::set<pthread_mutex_t *> mutex_set;
47     static pthread_mutex_t g_mutex_set_mutex = PTHREAD_MUTEX_INITIALIZER;
48     static mutex_set g_initialized_mutex_set;
49     static mutex_set g_destroyed_mutex_set;
50 
51     bool success = true;
52     int err;
53     // Manually call lock so we don't to any of this error checking
54     err = ::pthread_mutex_lock (&g_mutex_set_mutex);
55     assert(err == 0);
56     switch (action)
57     {
58         case eMutexActionInitialized:
59             // Make sure this isn't already in our initialized mutex set...
60             assert (g_initialized_mutex_set.find(m) == g_initialized_mutex_set.end());
61             // Remove this from the destroyed set in case it was ever in there
62             g_destroyed_mutex_set.erase(m);
63             // Add the mutex to the initialized set
64             g_initialized_mutex_set.insert(m);
65             break;
66 
67         case eMutexActionDestroyed:
68             // Make sure this isn't already in our destroyed mutex set...
69             assert (g_destroyed_mutex_set.find(m) == g_destroyed_mutex_set.end());
70             // Remove this from the initialized so we can put it into the destroyed set
71             g_initialized_mutex_set.erase(m);
72             // Add the mutex to the destroyed set
73             g_destroyed_mutex_set.insert(m);
74             break;
75         case eMutexActionAssertInitialized:
76             // This function will return true if "m" is in the initialized mutex set
77             success = g_initialized_mutex_set.find(m) != g_initialized_mutex_set.end();
78             assert (success);
79             break;
80     }
81     // Manually call unlock so we don't to any of this error checking
82     err = ::pthread_mutex_unlock (&g_mutex_set_mutex);
83     assert(err == 0);
84     return success;
85 }
86 
87 #endif
88 
89 using namespace lldb_private;
90 
91 //----------------------------------------------------------------------
92 // Default constructor.
93 //
94 // This will create a scoped mutex locking object that doesn't have
95 // a mutex to lock. One will need to be provided using the Reset()
96 // method.
97 //----------------------------------------------------------------------
Locker()98 Mutex::Locker::Locker () :
99     m_mutex_ptr(NULL)
100 {
101 }
102 
103 //----------------------------------------------------------------------
104 // Constructor with a Mutex object.
105 //
106 // This will create a scoped mutex locking object that extracts the
107 // mutex owned by "m" and locks it.
108 //----------------------------------------------------------------------
Locker(Mutex & m)109 Mutex::Locker::Locker (Mutex& m) :
110     m_mutex_ptr(NULL)
111 {
112     Lock (m);
113 }
114 
115 //----------------------------------------------------------------------
116 // Constructor with a Mutex object pointer.
117 //
118 // This will create a scoped mutex locking object that extracts the
119 // mutex owned by "m" and locks it.
120 //----------------------------------------------------------------------
Locker(Mutex * m)121 Mutex::Locker::Locker (Mutex* m) :
122     m_mutex_ptr(NULL)
123 {
124     if (m)
125         Lock (m);
126 }
127 
128 //----------------------------------------------------------------------
129 // Destructor
130 //
131 // Unlocks any owned mutex object (if it is valid).
132 //----------------------------------------------------------------------
~Locker()133 Mutex::Locker::~Locker ()
134 {
135     Unlock();
136 }
137 
138 //----------------------------------------------------------------------
139 // Unlock the current mutex in this object (if this owns a valid
140 // mutex) and lock the new "mutex" object if it is non-NULL.
141 //----------------------------------------------------------------------
142 void
Lock(Mutex & mutex)143 Mutex::Locker::Lock (Mutex &mutex)
144 {
145     // We already have this mutex locked or both are NULL...
146     if (m_mutex_ptr == &mutex)
147         return;
148 
149     Unlock ();
150 
151     m_mutex_ptr = &mutex;
152     m_mutex_ptr->Lock();
153 }
154 
155 void
Unlock()156 Mutex::Locker::Unlock ()
157 {
158     if (m_mutex_ptr)
159     {
160         m_mutex_ptr->Unlock ();
161         m_mutex_ptr = NULL;
162     }
163 }
164 
165 bool
TryLock(Mutex & mutex,const char * failure_message)166 Mutex::Locker::TryLock (Mutex &mutex, const char *failure_message)
167 {
168     // We already have this mutex locked!
169     if (m_mutex_ptr == &mutex)
170         return true;
171 
172     Unlock ();
173 
174     if (mutex.TryLock(failure_message) == 0)
175         m_mutex_ptr = &mutex;
176 
177     return m_mutex_ptr != NULL;
178 }
179 
180 //----------------------------------------------------------------------
181 // Default constructor.
182 //
183 // Creates a pthread mutex with no attributes.
184 //----------------------------------------------------------------------
Mutex()185 Mutex::Mutex () :
186     m_mutex()
187 {
188     int err;
189     err = ::pthread_mutex_init (&m_mutex, NULL);
190 #if ENABLE_MUTEX_ERROR_CHECKING
191     if (err == 0)
192         error_check_mutex (&m_mutex, eMutexActionInitialized);
193 #endif
194     assert(err == 0);
195 }
196 
197 //----------------------------------------------------------------------
198 // Default constructor.
199 //
200 // Creates a pthread mutex with "type" as the mutex type.
201 //----------------------------------------------------------------------
Mutex(Mutex::Type type)202 Mutex::Mutex (Mutex::Type type) :
203     m_mutex()
204 {
205     int err;
206     ::pthread_mutexattr_t attr;
207     err = ::pthread_mutexattr_init (&attr);
208     assert(err == 0);
209     switch (type)
210     {
211     case eMutexTypeNormal:
212 #if ENABLE_MUTEX_ERROR_CHECKING
213         err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK);
214 #else
215         err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL);
216 #endif
217         break;
218 
219     case eMutexTypeRecursive:
220         err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
221         break;
222     }
223     assert(err == 0);
224     err = ::pthread_mutex_init (&m_mutex, &attr);
225 #if ENABLE_MUTEX_ERROR_CHECKING
226     if (err == 0)
227         error_check_mutex (&m_mutex, eMutexActionInitialized);
228 #endif
229     assert(err == 0);
230     err = ::pthread_mutexattr_destroy (&attr);
231     assert(err == 0);
232 }
233 
234 //----------------------------------------------------------------------
235 // Destructor.
236 //
237 // Destroys the mutex owned by this object.
238 //----------------------------------------------------------------------
~Mutex()239 Mutex::~Mutex()
240 {
241     int err = ::pthread_mutex_destroy (&m_mutex);
242     assert(err == 0);
243 #if ENABLE_MUTEX_ERROR_CHECKING
244     if (err == 0)
245         error_check_mutex (&m_mutex, eMutexActionDestroyed);
246     else
247     {
248         Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_destroy() => err = %i (%s)", __PRETTY_FUNCTION__, err, strerror(err));
249         assert(err == 0);
250     }
251     memset (&m_mutex, '\xba', sizeof(m_mutex));
252 #endif
253 }
254 
255 //----------------------------------------------------------------------
256 // Mutex get accessor.
257 //----------------------------------------------------------------------
258 pthread_mutex_t *
GetMutex()259 Mutex::GetMutex()
260 {
261     return &m_mutex;
262 }
263 
264 //----------------------------------------------------------------------
265 // Locks the mutex owned by this object, if the mutex is already
266 // locked, the calling thread will block until the mutex becomes
267 // available.
268 //
269 // RETURNS
270 //  The error code from the pthread_mutex_lock() function call.
271 //----------------------------------------------------------------------
272 int
Lock()273 Mutex::Lock()
274 {
275     DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p)...\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex);
276 
277 #if ENABLE_MUTEX_ERROR_CHECKING
278     error_check_mutex (&m_mutex, eMutexActionAssertInitialized);
279 #endif
280 
281     int err = ::pthread_mutex_lock (&m_mutex);
282 
283 
284 #if ENABLE_MUTEX_ERROR_CHECKING
285     if (err)
286     {
287         Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_lock(%p) => err = %i (%s)", __PRETTY_FUNCTION__, &m_mutex, err, strerror(err));
288         assert(err == 0);
289     }
290 #endif
291     DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err);
292     return err;
293 }
294 
295 //----------------------------------------------------------------------
296 // Attempts to lock the mutex owned by this object without blocking.
297 // If the mutex is already locked, TryLock() will not block waiting
298 // for the mutex, but will return an error condition.
299 //
300 // RETURNS
301 //  The error code from the pthread_mutex_trylock() function call.
302 //----------------------------------------------------------------------
303 int
TryLock(const char * failure_message)304 Mutex::TryLock(const char *failure_message)
305 {
306 #if ENABLE_MUTEX_ERROR_CHECKING
307     error_check_mutex (&m_mutex, eMutexActionAssertInitialized);
308 #endif
309 
310     int err = ::pthread_mutex_trylock (&m_mutex);
311     DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_trylock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err);
312     return err;
313 }
314 
315 //----------------------------------------------------------------------
316 // If the current thread holds the lock on the owned mutex, then
317 // Unlock() will unlock the mutex. Calling Unlock() on this object
318 // that the calling thread does not hold will result in undefined
319 // behavior.
320 //
321 // RETURNS
322 //  The error code from the pthread_mutex_unlock() function call.
323 //----------------------------------------------------------------------
324 int
Unlock()325 Mutex::Unlock()
326 {
327 #if ENABLE_MUTEX_ERROR_CHECKING
328     error_check_mutex (&m_mutex, eMutexActionAssertInitialized);
329 #endif
330 
331     int err = ::pthread_mutex_unlock (&m_mutex);
332 
333 #if ENABLE_MUTEX_ERROR_CHECKING
334     if (err)
335     {
336         Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_unlock(%p) => err = %i (%s)", __PRETTY_FUNCTION__, &m_mutex, err, strerror(err));
337         assert(err == 0);
338     }
339 #endif
340     DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_unlock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err);
341     return err;
342 }
343 
344 #ifdef LLDB_CONFIGURATION_DEBUG
345 int
Unlock()346 TrackingMutex::Unlock ()
347 {
348     if (!m_failure_message.empty())
349         Host::SetCrashDescriptionWithFormat ("Unlocking lock (on thread %p) that thread: %p failed to get: %s",
350                                              pthread_self(),
351                                              m_thread_that_tried,
352                                              m_failure_message.c_str());
353     assert (m_failure_message.empty());
354     return Mutex::Unlock();
355 }
356 
357 int
Lock()358 LoggingMutex::Lock ()
359 {
360     printf("locking mutex %p by [%4.4" PRIx64 "/%4.4" PRIx64 "]...", this, Host::GetCurrentProcessID(), Host::GetCurrentThreadID());
361     int x = Mutex::Lock();
362     m_locked = true;
363     printf("%d\n",x);
364     return x;
365 }
366 
367 int
Unlock()368 LoggingMutex::Unlock ()
369 {
370     printf("unlocking mutex %p by [%4.4" PRIx64 "/%4.4" PRIx64 "]...", this, Host::GetCurrentProcessID(), Host::GetCurrentThreadID());
371     int x = Mutex::Unlock();
372     m_locked = false;
373     printf("%d\n",x);
374     return x;
375 }
376 
377 int
TryLock(const char * failure_message)378 LoggingMutex::TryLock (const char *failure_message)
379 {
380     printf("trylocking mutex %p by [%4.4" PRIx64 "/%4.4" PRIx64 "]...", this, Host::GetCurrentProcessID(), Host::GetCurrentThreadID());
381     int x = Mutex::TryLock(failure_message);
382     if (x == 0)
383         m_locked = true;
384     printf("%d\n",x);
385     return x;
386 }
387 
388 #endif
389 
390 
391