blob: df79cbe03fce9d2309f3597d8f7cfb00bc67939b [file] [log] [blame]
sewardjaf44c822007-11-25 14:01:38 +00001/*
2 This file is part of drd, a data race detector.
3
sewardj85642922008-01-14 11:54:56 +00004 Copyright (C) 2006-2008 Bart Van Assche
sewardjaf44c822007-11-25 14:01:38 +00005 bart.vanassche@gmail.com
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307, USA.
21
22 The GNU General Public License is contained in the file COPYING.
23*/
24
25
bart4bb53d82008-02-28 19:06:34 +000026#include "drd_clientobj.h"
sewardjaf44c822007-11-25 14:01:38 +000027#include "drd_error.h"
28#include "drd_mutex.h"
sewardj721ad7b2007-11-30 08:30:29 +000029#include "priv_drd_clientreq.h"
sewardjaf44c822007-11-25 14:01:38 +000030#include "pub_tool_errormgr.h" // VG_(maybe_record_error)()
31#include "pub_tool_libcassert.h" // tl_assert()
bart5bd9f2d2008-03-03 20:31:58 +000032#include "pub_tool_libcbase.h" // VG_(strlen)
bart4bb53d82008-02-28 19:06:34 +000033#include "pub_tool_libcprint.h" // VG_(message)()
sewardjaf44c822007-11-25 14:01:38 +000034#include "pub_tool_machine.h" // VG_(get_IP)()
35#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
36
37
sewardj347eeba2008-01-21 14:19:07 +000038// Local functions.
39
bart46d5f172008-02-28 19:49:37 +000040static void mutex_cleanup(struct mutex_info* p);
bart5357fcb2008-02-27 15:46:00 +000041static Bool mutex_is_locked(struct mutex_info* const p);
sewardj347eeba2008-01-21 14:19:07 +000042
43
sewardjaf44c822007-11-25 14:01:38 +000044// Local variables.
45
46static Bool s_trace_mutex;
47static ULong s_mutex_lock_count;
sewardjaf44c822007-11-25 14:01:38 +000048
49
50// Function definitions.
51
52void mutex_set_trace(const Bool trace_mutex)
53{
54 tl_assert(!! trace_mutex == trace_mutex);
55 s_trace_mutex = trace_mutex;
56}
57
58static
59void mutex_initialize(struct mutex_info* const p,
bart0268dfa2008-03-11 20:10:21 +000060 const Addr mutex, const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +000061{
62 tl_assert(mutex != 0);
sewardjaf44c822007-11-25 14:01:38 +000063
bart4bb53d82008-02-28 19:06:34 +000064 tl_assert(p->a1 == mutex);
bart46d5f172008-02-28 19:49:37 +000065 p->cleanup = (void(*)(DrdClientobj*))&mutex_cleanup;
sewardj721ad7b2007-11-30 08:30:29 +000066 p->mutex_type = mutex_type;
sewardjaf44c822007-11-25 14:01:38 +000067 p->recursion_count = 0;
68 p->owner = DRD_INVALID_THREADID;
69 vc_init(&p->vc, 0, 0);
70}
71
bart46d5f172008-02-28 19:49:37 +000072/** Deallocate the memory that was allocated by mutex_initialize(). */
73static void mutex_cleanup(struct mutex_info* p)
74{
bartb78312c2008-02-29 11:00:17 +000075 if (s_trace_mutex)
76 {
bart3b1ee452008-02-29 19:28:15 +000077 VG_(message)(Vg_UserMsg,
78 "[%d/%d] mutex_destroy %s 0x%lx",
79 VG_(get_running_tid)(),
80 thread_get_running_tid(),
bartb78312c2008-02-29 11:00:17 +000081 mutex_get_typename(p),
82 p->a1);
83 }
84
bart46d5f172008-02-28 19:49:37 +000085 if (mutex_is_locked(p))
86 {
87 MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
88 VG_(maybe_record_error)(VG_(get_running_tid)(),
89 MutexErr,
90 VG_(get_IP)(VG_(get_running_tid)()),
91 "Destroying locked mutex",
92 &MEI);
93 }
94
95 vc_cleanup(&p->vc);
96}
97
sewardjaf44c822007-11-25 14:01:38 +000098static
sewardj721ad7b2007-11-30 08:30:29 +000099struct mutex_info*
bart0268dfa2008-03-11 20:10:21 +0000100mutex_get_or_allocate(const Addr mutex, const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000101{
bart4bb53d82008-02-28 19:06:34 +0000102 struct mutex_info* p;
sewardj721ad7b2007-11-30 08:30:29 +0000103
bart4bb53d82008-02-28 19:06:34 +0000104 tl_assert(offsetof(DrdClientobj, mutex) == 0);
bart72b751c2008-03-01 13:44:24 +0000105 p = &clientobj_get(mutex, ClientMutex)->mutex;
bart4bb53d82008-02-28 19:06:34 +0000106 if (p)
107 {
bart4bb53d82008-02-28 19:06:34 +0000108 return p;
109 }
sewardj721ad7b2007-11-30 08:30:29 +0000110
bart0268dfa2008-03-11 20:10:21 +0000111 if (clientobj_present(mutex, mutex + 1))
sewardj721ad7b2007-11-30 08:30:29 +0000112 {
bart5bd9f2d2008-03-03 20:31:58 +0000113 GenericErrInfo GEI;
114 VG_(maybe_record_error)(VG_(get_running_tid)(),
115 GenericErr,
116 VG_(get_IP)(VG_(get_running_tid)()),
117 "Not a mutex",
118 &GEI);
119 return 0;
sewardj721ad7b2007-11-30 08:30:29 +0000120 }
bart4bb53d82008-02-28 19:06:34 +0000121
bart0268dfa2008-03-11 20:10:21 +0000122 p = &clientobj_add(mutex, ClientMutex)->mutex;
123 mutex_initialize(p, mutex, mutex_type);
bart4bb53d82008-02-28 19:06:34 +0000124 return p;
sewardjaf44c822007-11-25 14:01:38 +0000125}
126
bart3b1ee452008-02-29 19:28:15 +0000127struct mutex_info* mutex_get(const Addr mutex)
128{
129 tl_assert(offsetof(DrdClientobj, mutex) == 0);
bart72b751c2008-03-01 13:44:24 +0000130 return &clientobj_get(mutex, ClientMutex)->mutex;
bart3b1ee452008-02-29 19:28:15 +0000131}
132
bart00344642008-03-01 15:27:41 +0000133/** Called before pthread_mutex_init(). */
sewardj721ad7b2007-11-30 08:30:29 +0000134struct mutex_info*
bart0268dfa2008-03-11 20:10:21 +0000135mutex_init(const Addr mutex, const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000136{
bart00344642008-03-01 15:27:41 +0000137 struct mutex_info* p;
sewardjaf44c822007-11-25 14:01:38 +0000138
sewardjaf44c822007-11-25 14:01:38 +0000139 if (s_trace_mutex)
140 {
bart3b1ee452008-02-29 19:28:15 +0000141 VG_(message)(Vg_UserMsg,
142 "[%d/%d] mutex_init %s 0x%lx",
143 VG_(get_running_tid)(),
144 thread_get_running_tid(),
sewardj347eeba2008-01-21 14:19:07 +0000145 mutex_type_name(mutex_type),
sewardjaf44c822007-11-25 14:01:38 +0000146 mutex);
147 }
148
bart00344642008-03-01 15:27:41 +0000149 if (mutex_type == mutex_type_invalid_mutex)
150 {
151 GenericErrInfo GEI;
152 VG_(maybe_record_error)(VG_(get_running_tid)(),
153 GenericErr,
154 VG_(get_IP)(VG_(get_running_tid)()),
bart777f7fe2008-03-02 17:43:18 +0000155 "Not a mutex",
bart00344642008-03-01 15:27:41 +0000156 &GEI);
157 return 0;
158 }
159
160 p = mutex_get(mutex);
161 if (p)
sewardj347eeba2008-01-21 14:19:07 +0000162 {
163 const ThreadId vg_tid = VG_(get_running_tid)();
164 MutexErrInfo MEI
bart00344642008-03-01 15:27:41 +0000165 = { p->a1, p->recursion_count, p->owner };
sewardj347eeba2008-01-21 14:19:07 +0000166 VG_(maybe_record_error)(vg_tid,
167 MutexErr,
168 VG_(get_IP)(vg_tid),
169 "Mutex reinitialization",
170 &MEI);
bart00344642008-03-01 15:27:41 +0000171 return p;
sewardj347eeba2008-01-21 14:19:07 +0000172 }
bart0268dfa2008-03-11 20:10:21 +0000173 p = mutex_get_or_allocate(mutex, mutex_type);
sewardj347eeba2008-01-21 14:19:07 +0000174
bart00344642008-03-01 15:27:41 +0000175 return p;
sewardjaf44c822007-11-25 14:01:38 +0000176}
177
bart46d5f172008-02-28 19:49:37 +0000178/** Called after pthread_mutex_destroy(). */
sewardj347eeba2008-01-21 14:19:07 +0000179void mutex_post_destroy(const Addr mutex)
180{
bart72b751c2008-03-01 13:44:24 +0000181 struct mutex_info* p;
sewardj347eeba2008-01-21 14:19:07 +0000182
bart72b751c2008-03-01 13:44:24 +0000183 p = mutex_get(mutex);
184 if (p == 0)
185 {
186 GenericErrInfo GEI;
187 VG_(maybe_record_error)(VG_(get_running_tid)(),
188 GenericErr,
189 VG_(get_IP)(VG_(get_running_tid)()),
190 "Not a mutex",
191 &GEI);
192 return;
193 }
194
195 clientobj_remove(mutex, ClientMutex);
sewardj347eeba2008-01-21 14:19:07 +0000196}
197
bart8bba1f72008-02-27 16:13:05 +0000198/** Called before pthread_mutex_lock() is invoked. If a data structure for
199 * the client-side object was not yet created, do this now. Also check whether
200 * an attempt is made to lock recursively a synchronization object that must
201 * not be locked recursively.
202 */
bart0268dfa2008-03-11 20:10:21 +0000203void mutex_pre_lock(const Addr mutex, MutexT mutex_type)
bart8bba1f72008-02-27 16:13:05 +0000204{
bart635cb162008-02-28 08:30:43 +0000205 struct mutex_info* p;
206
bart0268dfa2008-03-11 20:10:21 +0000207 p = mutex_get_or_allocate(mutex, mutex_type);
208
209 tl_assert(p);
bart00344642008-03-01 15:27:41 +0000210
211 if (s_trace_mutex)
212 {
213 VG_(message)(Vg_UserMsg,
214 "[%d/%d] pre_mutex_lock %s 0x%lx rc %d owner %d",
215 VG_(get_running_tid)(),
216 thread_get_running_tid(),
bart0268dfa2008-03-11 20:10:21 +0000217 mutex_get_typename(p),
bart00344642008-03-01 15:27:41 +0000218 mutex,
bart0268dfa2008-03-11 20:10:21 +0000219 p->recursion_count,
220 p->owner);
bart00344642008-03-01 15:27:41 +0000221 }
222
223 if (mutex_type == mutex_type_invalid_mutex)
224 {
225 GenericErrInfo GEI;
226 VG_(maybe_record_error)(VG_(get_running_tid)(),
227 GenericErr,
228 VG_(get_IP)(VG_(get_running_tid)()),
bart777f7fe2008-03-02 17:43:18 +0000229 "Not a mutex",
bart00344642008-03-01 15:27:41 +0000230 &GEI);
231 return;
232 }
233
bart8bba1f72008-02-27 16:13:05 +0000234 if (p->owner == thread_get_running_tid()
235 && p->recursion_count >= 1
236 && mutex_type != mutex_type_recursive_mutex)
237 {
bart4bb53d82008-02-28 19:06:34 +0000238 MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
bart8bba1f72008-02-27 16:13:05 +0000239 VG_(maybe_record_error)(VG_(get_running_tid)(),
240 MutexErr,
241 VG_(get_IP)(VG_(get_running_tid)()),
242 "Recursive locking not allowed",
243 &MEI);
244 }
245}
246
sewardjaf44c822007-11-25 14:01:38 +0000247/**
248 * Update mutex_info state when locking the pthread_mutex_t mutex.
249 * Note: this function must be called after pthread_mutex_lock() has been
250 * called, or a race condition is triggered !
251 */
bart777f7fe2008-03-02 17:43:18 +0000252void mutex_post_lock(const Addr mutex, const Bool took_lock)
sewardjaf44c822007-11-25 14:01:38 +0000253{
bart3b1ee452008-02-29 19:28:15 +0000254 const DrdThreadId drd_tid = thread_get_running_tid();
bart00344642008-03-01 15:27:41 +0000255 struct mutex_info* p;
256
257 p = mutex_get(mutex);
sewardjaf44c822007-11-25 14:01:38 +0000258
259 if (s_trace_mutex)
260 {
bart3b1ee452008-02-29 19:28:15 +0000261 VG_(message)(Vg_UserMsg,
262 "[%d/%d] post_mutex_lock %s 0x%lx rc %d owner %d",
263 VG_(get_running_tid)(),
sewardjaf44c822007-11-25 14:01:38 +0000264 drd_tid,
bart00344642008-03-01 15:27:41 +0000265 p ? mutex_get_typename(p) : "(?)",
sewardjaf44c822007-11-25 14:01:38 +0000266 mutex,
267 p ? p->recursion_count : 0,
268 p ? p->owner : VG_INVALID_THREADID);
269 }
270
bart777f7fe2008-03-02 17:43:18 +0000271 if (! p || ! took_lock)
bart5bd9f2d2008-03-03 20:31:58 +0000272 return;
bart5357fcb2008-02-27 15:46:00 +0000273
sewardjaf44c822007-11-25 14:01:38 +0000274 if (p->recursion_count == 0)
275 {
bart5bd9f2d2008-03-03 20:31:58 +0000276 const DrdThreadId last_owner = p->owner;
277
278 if (last_owner != drd_tid && last_owner != DRD_INVALID_THREADID)
279 thread_combine_vc2(drd_tid, mutex_get_last_vc(mutex));
280 thread_new_segment(drd_tid);
281
sewardjaf44c822007-11-25 14:01:38 +0000282 p->owner = drd_tid;
283 s_mutex_lock_count++;
284 }
285 else if (p->owner != drd_tid)
286 {
bart3b1ee452008-02-29 19:28:15 +0000287 VG_(message)(Vg_UserMsg,
sewardjaf44c822007-11-25 14:01:38 +0000288 "The impossible happened: mutex 0x%lx is locked"
289 " simultaneously by two threads (recursion count %d,"
290 " owners %d and %d) !",
bart4bb53d82008-02-28 19:06:34 +0000291 p->a1, p->recursion_count, p->owner, drd_tid);
sewardj347eeba2008-01-21 14:19:07 +0000292 p->owner = drd_tid;
sewardjaf44c822007-11-25 14:01:38 +0000293 }
294 p->recursion_count++;
sewardjaf44c822007-11-25 14:01:38 +0000295}
296
297/**
298 * Update mutex_info state when unlocking the pthread_mutex_t mutex.
299 * Note: this function must be called before pthread_mutex_unlock() is called,
300 * or a race condition is triggered !
bartb78312c2008-02-29 11:00:17 +0000301 * @return New value of the mutex recursion count.
sewardjaf44c822007-11-25 14:01:38 +0000302 * @param mutex Pointer to pthread_mutex_t data structure in the client space.
303 * @param tid ThreadId of the thread calling pthread_mutex_unlock().
304 * @param vc Pointer to the current vector clock of thread tid.
305 */
bart777f7fe2008-03-02 17:43:18 +0000306void mutex_unlock(const Addr mutex, const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000307{
bartb78312c2008-02-29 11:00:17 +0000308 const DrdThreadId drd_tid = thread_get_running_tid();
309 const ThreadId vg_tid = VG_(get_running_tid)();
sewardjaf44c822007-11-25 14:01:38 +0000310 const VectorClock* const vc = thread_get_vc(drd_tid);
311 struct mutex_info* const p = mutex_get(mutex);
312
bart777f7fe2008-03-02 17:43:18 +0000313 if (s_trace_mutex)
sewardjaf44c822007-11-25 14:01:38 +0000314 {
bart3b1ee452008-02-29 19:28:15 +0000315 VG_(message)(Vg_UserMsg,
316 "[%d/%d] mutex_unlock %s 0x%lx rc %d",
317 vg_tid,
318 drd_tid,
bart777f7fe2008-03-02 17:43:18 +0000319 p ? mutex_get_typename(p) : "?",
sewardjaf44c822007-11-25 14:01:38 +0000320 mutex,
bart777f7fe2008-03-02 17:43:18 +0000321 p ? p->recursion_count : 0,
322 p ? p->owner : 0);
sewardjaf44c822007-11-25 14:01:38 +0000323 }
324
bart777f7fe2008-03-02 17:43:18 +0000325 if (p == 0 || mutex_type == mutex_type_invalid_mutex)
bartab7a6442008-02-25 19:46:14 +0000326 {
bart5bd9f2d2008-03-03 20:31:58 +0000327 GenericErrInfo GEI;
328 VG_(maybe_record_error)(vg_tid,
329 GenericErr,
330 VG_(get_IP)(vg_tid),
331 "Not a mutex",
332 &GEI);
333 return;
bartab7a6442008-02-25 19:46:14 +0000334 }
335
bart5357fcb2008-02-27 15:46:00 +0000336 if (p->owner == DRD_INVALID_THREADID)
337 {
bart4bb53d82008-02-28 19:06:34 +0000338 MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
bart5357fcb2008-02-27 15:46:00 +0000339 VG_(maybe_record_error)(vg_tid,
340 MutexErr,
341 VG_(get_IP)(vg_tid),
342 "Mutex not locked",
343 &MEI);
bart5bd9f2d2008-03-03 20:31:58 +0000344 return;
bart5357fcb2008-02-27 15:46:00 +0000345 }
346
sewardjaf44c822007-11-25 14:01:38 +0000347 tl_assert(p);
bart5357fcb2008-02-27 15:46:00 +0000348 if (p->mutex_type != mutex_type)
349 {
bart3b1ee452008-02-29 19:28:15 +0000350 VG_(message)(Vg_UserMsg, "??? mutex %p: type changed from %d into %d",
bart5bd9f2d2008-03-03 20:31:58 +0000351 p->a1, p->mutex_type, mutex_type);
bart5357fcb2008-02-27 15:46:00 +0000352 }
sewardj721ad7b2007-11-30 08:30:29 +0000353 tl_assert(p->mutex_type == mutex_type);
sewardjaf44c822007-11-25 14:01:38 +0000354 tl_assert(p->owner != DRD_INVALID_THREADID);
sewardj721ad7b2007-11-30 08:30:29 +0000355
bart777f7fe2008-03-02 17:43:18 +0000356 if (p->owner != drd_tid || p->recursion_count <= 0)
sewardjaf44c822007-11-25 14:01:38 +0000357 {
bart4bb53d82008-02-28 19:06:34 +0000358 MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
sewardjaf44c822007-11-25 14:01:38 +0000359 VG_(maybe_record_error)(vg_tid,
360 MutexErr,
361 VG_(get_IP)(vg_tid),
bart777f7fe2008-03-02 17:43:18 +0000362 "Mutex not locked by calling thread",
sewardjaf44c822007-11-25 14:01:38 +0000363 &MEI);
bart777f7fe2008-03-02 17:43:18 +0000364 return;
sewardjaf44c822007-11-25 14:01:38 +0000365 }
bart777f7fe2008-03-02 17:43:18 +0000366 tl_assert(p->recursion_count > 0);
sewardjaf44c822007-11-25 14:01:38 +0000367 p->recursion_count--;
bart777f7fe2008-03-02 17:43:18 +0000368 tl_assert(p->recursion_count >= 0);
sewardj347eeba2008-01-21 14:19:07 +0000369
sewardjaf44c822007-11-25 14:01:38 +0000370 if (p->recursion_count == 0)
371 {
372 /* This pthread_mutex_unlock() call really unlocks the mutex. Save the */
373 /* current vector clock of the thread such that it is available when */
374 /* this mutex is locked again. */
bart301c3112008-02-24 18:22:37 +0000375 vc_assign(&p->vc, vc);
sewardjaf44c822007-11-25 14:01:38 +0000376
377 thread_new_segment(drd_tid);
378 }
sewardjaf44c822007-11-25 14:01:38 +0000379}
380
381const char* mutex_get_typename(struct mutex_info* const p)
382{
383 tl_assert(p);
sewardj721ad7b2007-11-30 08:30:29 +0000384
sewardj347eeba2008-01-21 14:19:07 +0000385 return mutex_type_name(p->mutex_type);
386}
387
388const char* mutex_type_name(const MutexT mt)
389{
390 switch (mt)
sewardjaf44c822007-11-25 14:01:38 +0000391 {
bart635cb162008-02-28 08:30:43 +0000392 case mutex_type_invalid_mutex:
393 return "invalid mutex";
bart5357fcb2008-02-27 15:46:00 +0000394 case mutex_type_recursive_mutex:
395 return "recursive mutex";
396 case mutex_type_errorcheck_mutex:
397 return "error checking mutex";
398 case mutex_type_default_mutex:
sewardjaf44c822007-11-25 14:01:38 +0000399 return "mutex";
sewardj721ad7b2007-11-30 08:30:29 +0000400 case mutex_type_spinlock:
sewardjaf44c822007-11-25 14:01:38 +0000401 return "spinlock";
402 default:
403 tl_assert(0);
404 }
405 return "?";
406}
407
bart5357fcb2008-02-27 15:46:00 +0000408/** Return true if the specified mutex is locked by any thread. */
409static Bool mutex_is_locked(struct mutex_info* const p)
410{
411 tl_assert(p);
412 return (p->recursion_count > 0);
413}
414
sewardjaf44c822007-11-25 14:01:38 +0000415Bool mutex_is_locked_by(const Addr mutex, const DrdThreadId tid)
416{
417 struct mutex_info* const p = mutex_get(mutex);
sewardjaf44c822007-11-25 14:01:38 +0000418 if (p)
419 {
420 return (p->recursion_count > 0 && p->owner == tid);
421 }
422 return False;
423}
424
425const VectorClock* mutex_get_last_vc(const Addr mutex)
426{
427 struct mutex_info* const p = mutex_get(mutex);
428 return p ? &p->vc : 0;
429}
430
431int mutex_get_recursion_count(const Addr mutex)
432{
433 struct mutex_info* const p = mutex_get(mutex);
434 tl_assert(p);
435 return p->recursion_count;
436}
437
438/**
bart301c3112008-02-24 18:22:37 +0000439 * Call this function when thread tid stops to exist, such that the
sewardjaf44c822007-11-25 14:01:38 +0000440 * "last owner" field can be cleared if it still refers to that thread.
sewardjaf44c822007-11-25 14:01:38 +0000441 */
bart301c3112008-02-24 18:22:37 +0000442void mutex_thread_delete(const DrdThreadId tid)
sewardjaf44c822007-11-25 14:01:38 +0000443{
bart4bb53d82008-02-28 19:06:34 +0000444 struct mutex_info* p;
445
bart72b751c2008-03-01 13:44:24 +0000446 clientobj_resetiter();
447 for ( ; (p = &clientobj_next(ClientMutex)->mutex) != 0; )
sewardjaf44c822007-11-25 14:01:38 +0000448 {
bart4bb53d82008-02-28 19:06:34 +0000449 if (p->owner == tid && p->recursion_count > 0)
sewardjaf44c822007-11-25 14:01:38 +0000450 {
bart5357fcb2008-02-27 15:46:00 +0000451 MutexErrInfo MEI
bart4bb53d82008-02-28 19:06:34 +0000452 = { p->a1, p->recursion_count, p->owner };
bart5357fcb2008-02-27 15:46:00 +0000453 VG_(maybe_record_error)(VG_(get_running_tid)(),
454 MutexErr,
455 VG_(get_IP)(VG_(get_running_tid)()),
456 "Mutex still locked at thread exit",
457 &MEI);
sewardjaf44c822007-11-25 14:01:38 +0000458 p->owner = VG_INVALID_THREADID;
459 }
460 }
461}
462
sewardjaf44c822007-11-25 14:01:38 +0000463ULong get_mutex_lock_count(void)
464{
465 return s_mutex_lock_count;
466}
sewardj347eeba2008-01-21 14:19:07 +0000467
468
469/*
470 * Local variables:
bart5bd9f2d2008-03-03 20:31:58 +0000471 * c-basic-offset: 2
sewardj347eeba2008-01-21 14:19:07 +0000472 * End:
473 */