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
36enum MutexAction
37{
38    eMutexActionInitialized,
39    eMutexActionDestroyed,
40    eMutexActionAssertInitialized
41};
42
43static bool
44error_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
89using 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//----------------------------------------------------------------------
98Mutex::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//----------------------------------------------------------------------
109Mutex::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//----------------------------------------------------------------------
121Mutex::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//----------------------------------------------------------------------
133Mutex::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//----------------------------------------------------------------------
142void
143Mutex::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
155void
156Mutex::Locker::Unlock ()
157{
158    if (m_mutex_ptr)
159    {
160        m_mutex_ptr->Unlock ();
161        m_mutex_ptr = NULL;
162    }
163}
164
165bool
166Mutex::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//----------------------------------------------------------------------
185Mutex::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//----------------------------------------------------------------------
202Mutex::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//----------------------------------------------------------------------
239Mutex::~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//----------------------------------------------------------------------
258pthread_mutex_t *
259Mutex::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//----------------------------------------------------------------------
272int
273Mutex::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//----------------------------------------------------------------------
303int
304Mutex::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//----------------------------------------------------------------------
324int
325Mutex::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
345int
346TrackingMutex::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
357int
358LoggingMutex::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
367int
368LoggingMutex::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
377int
378LoggingMutex::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