root/trunk/libffado/src/libutil/PosixMutex.cpp

Revision 1211, 5.2 kB (checked in by ppalmers, 14 years ago)

merge libffado-2.0 r1199:1206 back to trunk (svn merge -r 1199:1206 svn+ssh://ffadosvn@ffado.org/ffado/branches/libffado-2.0)

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "PosixMutex.h"
25 #include <errno.h>
26
27 // disable collision tracing for non-debug builds
28 #ifndef DEBUG
29     #undef DEBUG_LOCK_COLLISION_TRACING
30     #define DEBUG_LOCK_COLLISION_TRACING 0
31 #endif
32
33 // check whether backtracing is enabled
34 #if DEBUG_LOCK_COLLISION_TRACING
35     #define DEBUG_LOCK_COLLISION_TRACING_INDEX 2
36     #define DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN 64
37     #if DEBUG_BACKTRACE_SUPPORT
38     // ok
39     #else
40         #error cannot enable lock tracing without backtrace support
41     #endif
42 #endif
43
44 namespace Util
45 {
46
47 IMPL_DEBUG_MODULE( PosixMutex, PosixMutex, DEBUG_LEVEL_NORMAL );
48
49 PosixMutex::PosixMutex()
50 {
51     pthread_mutexattr_t attr;
52     pthread_mutexattr_init(&attr);
53     #ifdef DEBUG
54         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
55     #else
56         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
57     #endif
58     pthread_mutex_init(&m_mutex, &attr);
59     pthread_mutexattr_destroy(&attr);
60
61     #if DEBUG_LOCK_COLLISION_TRACING
62     m_locked_by = NULL;
63     #endif
64 }
65
66 PosixMutex::~PosixMutex()
67 {
68     pthread_mutex_destroy(&m_mutex);
69 }
70
71 void
72 PosixMutex::Lock()
73 {
74     int err;
75     debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, "(%p) lock\n", this);
76     #if DEBUG_LOCK_COLLISION_TRACING
77     if(TryLock()) {
78         // locking succeeded
79         m_locked_by = debugBacktraceGet( DEBUG_LOCK_COLLISION_TRACING_INDEX );
80
81         char name[ DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN ];
82         name[0] = 0;
83         debugGetFunctionNameFromAddr(m_locked_by, name, DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN);
84
85         debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE,
86                     "(%p) %s obtained lock\n",
87                     this, name);
88         return;
89     } else {
90         void *lock_try_by = debugBacktraceGet( DEBUG_LOCK_COLLISION_TRACING_INDEX );
91
92         char name1[ DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN ];
93         name1[0] = 0;
94         debugGetFunctionNameFromAddr(lock_try_by, name1, DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN);
95         char name2[ DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN ];
96         name2[0] = 0;
97         debugGetFunctionNameFromAddr(m_locked_by, name2, DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN);
98
99         debugWarning("(%p) lock collision: %s wants lock, %s has lock\n",
100                     this, name1, name2);
101         if((err = pthread_mutex_lock(&m_mutex))) {
102             if (err == EDEADLK) {
103                 debugError("Resource deadlock detected\n");
104                 debugPrintBacktrace(10);
105             } else {
106                 debugError("Error locking the mutex: %d\n", err);
107             }
108         } else {
109             debugWarning("(%p) lock collision: %s got lock (from %s?)\n",
110                         this, name1, name2);
111         }
112     }
113     #else
114     #ifdef DEBUG
115     if((err = pthread_mutex_lock(&m_mutex))) {
116         if (err == EDEADLK) {
117             debugError("Resource deadlock detected\n");
118             debugPrintBacktrace(10);
119         } else {
120             debugError("Error locking the mutex: %d\n", err);
121         }
122     }
123     #else
124     pthread_mutex_lock(&m_mutex);
125     #endif
126     #endif
127 }
128
129 bool
130 PosixMutex::TryLock()
131 {
132     debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, "(%p) trying to lock\n", this);
133     return pthread_mutex_trylock(&m_mutex) == 0;
134 }
135
136 bool
137 PosixMutex::isLocked()
138 {
139     debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, "(%p) checking lock\n", this);
140     int res=pthread_mutex_trylock(&m_mutex);
141     if(res == 0) {
142         pthread_mutex_unlock(&m_mutex);
143         return false;
144     } else {
145         if(res != EBUSY) {
146             debugError("Bogus error code: %d\n", res);
147         }
148         return true;
149     }
150 }
151
152 void
153 PosixMutex::Unlock()
154 {
155     debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, "(%p) unlock\n", this);
156     #if DEBUG_LOCK_COLLISION_TRACING
157     // unlocking
158     m_locked_by = NULL;
159     void *unlocker = debugBacktraceGet( DEBUG_LOCK_COLLISION_TRACING_INDEX );
160     char name[ DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN ];
161     name[0] = 0;
162     debugGetFunctionNameFromAddr(unlocker, name, DEBUG_LOCK_COLLISION_TRACING_NAME_MAXLEN);
163     debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE,
164                 "(%p) %s releases lock\n",
165                 this, name);
166     #endif
167
168     #ifdef DEBUG
169     int err;
170     if((err = pthread_mutex_unlock(&m_mutex))) {
171         debugError("Error unlocking the mutex: %d\n", err);
172     }
173     #else
174     pthread_mutex_unlock(&m_mutex);
175     #endif
176 }
177
178 void
179 PosixMutex::show()
180 {
181     debugOutput(DEBUG_LEVEL_NORMAL, "(%p) mutex (%s)\n", this, (isLocked() ? "Locked" : "Unlocked"));
182 }
183
184
185 } // end of namespace
Note: See TracBrowser for help on using the browser.