blob: 55598ae7d0a70bdeb0a29b1a3a3b4ef5f6c389f8 [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,
60 const Addr mutex,
sewardj721ad7b2007-11-30 08:30:29 +000061 const SizeT size,
62 const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +000063{
64 tl_assert(mutex != 0);
65 tl_assert(size > 0);
66
bart4bb53d82008-02-28 19:06:34 +000067 tl_assert(p->a1 == mutex);
68 tl_assert(p->a2 == mutex + size);
bart46d5f172008-02-28 19:49:37 +000069 p->cleanup = (void(*)(DrdClientobj*))&mutex_cleanup;
sewardj721ad7b2007-11-30 08:30:29 +000070 p->mutex_type = mutex_type;
sewardjaf44c822007-11-25 14:01:38 +000071 p->recursion_count = 0;
72 p->owner = DRD_INVALID_THREADID;
73 vc_init(&p->vc, 0, 0);
74}
75
bart46d5f172008-02-28 19:49:37 +000076/** Deallocate the memory that was allocated by mutex_initialize(). */
77static void mutex_cleanup(struct mutex_info* p)
78{
bartb78312c2008-02-29 11:00:17 +000079 if (s_trace_mutex)
80 {
bart3b1ee452008-02-29 19:28:15 +000081 VG_(message)(Vg_UserMsg,
82 "[%d/%d] mutex_destroy %s 0x%lx",
83 VG_(get_running_tid)(),
84 thread_get_running_tid(),
bartb78312c2008-02-29 11:00:17 +000085 mutex_get_typename(p),
86 p->a1);
87 }
88
bart46d5f172008-02-28 19:49:37 +000089 if (mutex_is_locked(p))
90 {
91 MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
92 VG_(maybe_record_error)(VG_(get_running_tid)(),
93 MutexErr,
94 VG_(get_IP)(VG_(get_running_tid)()),
95 "Destroying locked mutex",
96 &MEI);
97 }
98
99 vc_cleanup(&p->vc);
100}
101
sewardjaf44c822007-11-25 14:01:38 +0000102static
sewardj721ad7b2007-11-30 08:30:29 +0000103struct mutex_info*
104mutex_get_or_allocate(const Addr mutex,
105 const SizeT size,
106 const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000107{
bart4bb53d82008-02-28 19:06:34 +0000108 struct mutex_info* p;
sewardj721ad7b2007-11-30 08:30:29 +0000109
bart4bb53d82008-02-28 19:06:34 +0000110 tl_assert(offsetof(DrdClientobj, mutex) == 0);
bart72b751c2008-03-01 13:44:24 +0000111 p = &clientobj_get(mutex, ClientMutex)->mutex;
bart4bb53d82008-02-28 19:06:34 +0000112 if (p)
113 {
114 tl_assert(p->mutex_type == mutex_type);
115 tl_assert(p->a2 - p->a1 == size);
116 return p;
117 }
sewardj721ad7b2007-11-30 08:30:29 +0000118
bart72b751c2008-03-01 13:44:24 +0000119 if (clientobj_present(mutex, mutex + size))
sewardj721ad7b2007-11-30 08:30:29 +0000120 {
bart5bd9f2d2008-03-03 20:31:58 +0000121 GenericErrInfo GEI;
122 VG_(maybe_record_error)(VG_(get_running_tid)(),
123 GenericErr,
124 VG_(get_IP)(VG_(get_running_tid)()),
125 "Not a mutex",
126 &GEI);
127 return 0;
sewardj721ad7b2007-11-30 08:30:29 +0000128 }
bart4bb53d82008-02-28 19:06:34 +0000129
bart72b751c2008-03-01 13:44:24 +0000130 p = &clientobj_add(mutex, mutex + size, ClientMutex)->mutex;
bart4bb53d82008-02-28 19:06:34 +0000131 mutex_initialize(p, mutex, size, mutex_type);
132 return p;
sewardjaf44c822007-11-25 14:01:38 +0000133}
134
bart3b1ee452008-02-29 19:28:15 +0000135struct mutex_info* mutex_get(const Addr mutex)
136{
137 tl_assert(offsetof(DrdClientobj, mutex) == 0);
bart72b751c2008-03-01 13:44:24 +0000138 return &clientobj_get(mutex, ClientMutex)->mutex;
bart3b1ee452008-02-29 19:28:15 +0000139}
140
bart00344642008-03-01 15:27:41 +0000141/** Called before pthread_mutex_init(). */
sewardj721ad7b2007-11-30 08:30:29 +0000142struct mutex_info*
143mutex_init(const Addr mutex, const SizeT size, const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000144{
bart00344642008-03-01 15:27:41 +0000145 struct mutex_info* p;
sewardjaf44c822007-11-25 14:01:38 +0000146
sewardjaf44c822007-11-25 14:01:38 +0000147 if (s_trace_mutex)
148 {
bart3b1ee452008-02-29 19:28:15 +0000149 VG_(message)(Vg_UserMsg,
150 "[%d/%d] mutex_init %s 0x%lx",
151 VG_(get_running_tid)(),
152 thread_get_running_tid(),
sewardj347eeba2008-01-21 14:19:07 +0000153 mutex_type_name(mutex_type),
sewardjaf44c822007-11-25 14:01:38 +0000154 mutex);
155 }
156
bart00344642008-03-01 15:27:41 +0000157 if (mutex_type == mutex_type_invalid_mutex)
158 {
159 GenericErrInfo GEI;
160 VG_(maybe_record_error)(VG_(get_running_tid)(),
161 GenericErr,
162 VG_(get_IP)(VG_(get_running_tid)()),
bart777f7fe2008-03-02 17:43:18 +0000163 "Not a mutex",
bart00344642008-03-01 15:27:41 +0000164 &GEI);
165 return 0;
166 }
167
168 p = mutex_get(mutex);
169 if (p)
sewardj347eeba2008-01-21 14:19:07 +0000170 {
171 const ThreadId vg_tid = VG_(get_running_tid)();
172 MutexErrInfo MEI
bart00344642008-03-01 15:27:41 +0000173 = { p->a1, p->recursion_count, p->owner };
sewardj347eeba2008-01-21 14:19:07 +0000174 VG_(maybe_record_error)(vg_tid,
175 MutexErr,
176 VG_(get_IP)(vg_tid),
177 "Mutex reinitialization",
178 &MEI);
bart00344642008-03-01 15:27:41 +0000179 return p;
sewardj347eeba2008-01-21 14:19:07 +0000180 }
bart00344642008-03-01 15:27:41 +0000181 p = mutex_get_or_allocate(mutex, size, mutex_type);
sewardj347eeba2008-01-21 14:19:07 +0000182
bart00344642008-03-01 15:27:41 +0000183 return p;
sewardjaf44c822007-11-25 14:01:38 +0000184}
185
bart46d5f172008-02-28 19:49:37 +0000186/** Called after pthread_mutex_destroy(). */
sewardj347eeba2008-01-21 14:19:07 +0000187void mutex_post_destroy(const Addr mutex)
188{
bart72b751c2008-03-01 13:44:24 +0000189 struct mutex_info* p;
sewardj347eeba2008-01-21 14:19:07 +0000190
bart72b751c2008-03-01 13:44:24 +0000191 p = mutex_get(mutex);
192 if (p == 0)
193 {
194 GenericErrInfo GEI;
195 VG_(maybe_record_error)(VG_(get_running_tid)(),
196 GenericErr,
197 VG_(get_IP)(VG_(get_running_tid)()),
198 "Not a mutex",
199 &GEI);
200 return;
201 }
202
203 clientobj_remove(mutex, ClientMutex);
sewardj347eeba2008-01-21 14:19:07 +0000204}
205
bart8bba1f72008-02-27 16:13:05 +0000206/** Called before pthread_mutex_lock() is invoked. If a data structure for
207 * the client-side object was not yet created, do this now. Also check whether
208 * an attempt is made to lock recursively a synchronization object that must
209 * not be locked recursively.
210 */
211void mutex_pre_lock(const Addr mutex, const SizeT size, MutexT mutex_type)
212{
bart635cb162008-02-28 08:30:43 +0000213 struct mutex_info* p;
214
215 p = mutex_get(mutex);
bart00344642008-03-01 15:27:41 +0000216
217 if (s_trace_mutex)
218 {
219 VG_(message)(Vg_UserMsg,
220 "[%d/%d] pre_mutex_lock %s 0x%lx rc %d owner %d",
221 VG_(get_running_tid)(),
222 thread_get_running_tid(),
223 p ? mutex_get_typename(p) : "(?)",
224 mutex,
225 p ? p->recursion_count : 0,
226 p ? p->owner : VG_INVALID_THREADID);
227 }
228
229 if (mutex_type == mutex_type_invalid_mutex)
230 {
231 GenericErrInfo GEI;
232 VG_(maybe_record_error)(VG_(get_running_tid)(),
233 GenericErr,
234 VG_(get_IP)(VG_(get_running_tid)()),
bart777f7fe2008-03-02 17:43:18 +0000235 "Not a mutex",
bart00344642008-03-01 15:27:41 +0000236 &GEI);
237 return;
238 }
239
bart8bba1f72008-02-27 16:13:05 +0000240 if (p == 0)
241 {
bart00344642008-03-01 15:27:41 +0000242 p = mutex_init(mutex, size, mutex_type);
bart8bba1f72008-02-27 16:13:05 +0000243 }
bart635cb162008-02-28 08:30:43 +0000244
bart8bba1f72008-02-27 16:13:05 +0000245 tl_assert(p);
246
247 if (p->owner == thread_get_running_tid()
248 && p->recursion_count >= 1
249 && mutex_type != mutex_type_recursive_mutex)
250 {
bart4bb53d82008-02-28 19:06:34 +0000251 MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
bart8bba1f72008-02-27 16:13:05 +0000252 VG_(maybe_record_error)(VG_(get_running_tid)(),
253 MutexErr,
254 VG_(get_IP)(VG_(get_running_tid)()),
255 "Recursive locking not allowed",
256 &MEI);
257 }
258}
259
sewardjaf44c822007-11-25 14:01:38 +0000260/**
261 * Update mutex_info state when locking the pthread_mutex_t mutex.
262 * Note: this function must be called after pthread_mutex_lock() has been
263 * called, or a race condition is triggered !
264 */
bart777f7fe2008-03-02 17:43:18 +0000265void mutex_post_lock(const Addr mutex, const Bool took_lock)
sewardjaf44c822007-11-25 14:01:38 +0000266{
bart3b1ee452008-02-29 19:28:15 +0000267 const DrdThreadId drd_tid = thread_get_running_tid();
bart00344642008-03-01 15:27:41 +0000268 struct mutex_info* p;
269
270 p = mutex_get(mutex);
sewardjaf44c822007-11-25 14:01:38 +0000271
272 if (s_trace_mutex)
273 {
bart3b1ee452008-02-29 19:28:15 +0000274 VG_(message)(Vg_UserMsg,
275 "[%d/%d] post_mutex_lock %s 0x%lx rc %d owner %d",
276 VG_(get_running_tid)(),
sewardjaf44c822007-11-25 14:01:38 +0000277 drd_tid,
bart00344642008-03-01 15:27:41 +0000278 p ? mutex_get_typename(p) : "(?)",
sewardjaf44c822007-11-25 14:01:38 +0000279 mutex,
280 p ? p->recursion_count : 0,
281 p ? p->owner : VG_INVALID_THREADID);
282 }
283
bart777f7fe2008-03-02 17:43:18 +0000284 if (! p || ! took_lock)
bart5bd9f2d2008-03-03 20:31:58 +0000285 return;
bart5357fcb2008-02-27 15:46:00 +0000286
sewardjaf44c822007-11-25 14:01:38 +0000287 if (p->recursion_count == 0)
288 {
bart5bd9f2d2008-03-03 20:31:58 +0000289 const DrdThreadId last_owner = p->owner;
290
291 if (last_owner != drd_tid && last_owner != DRD_INVALID_THREADID)
292 thread_combine_vc2(drd_tid, mutex_get_last_vc(mutex));
293 thread_new_segment(drd_tid);
294
sewardjaf44c822007-11-25 14:01:38 +0000295 p->owner = drd_tid;
296 s_mutex_lock_count++;
297 }
298 else if (p->owner != drd_tid)
299 {
bart3b1ee452008-02-29 19:28:15 +0000300 VG_(message)(Vg_UserMsg,
sewardjaf44c822007-11-25 14:01:38 +0000301 "The impossible happened: mutex 0x%lx is locked"
302 " simultaneously by two threads (recursion count %d,"
303 " owners %d and %d) !",
bart4bb53d82008-02-28 19:06:34 +0000304 p->a1, p->recursion_count, p->owner, drd_tid);
sewardj347eeba2008-01-21 14:19:07 +0000305 p->owner = drd_tid;
sewardjaf44c822007-11-25 14:01:38 +0000306 }
307 p->recursion_count++;
sewardjaf44c822007-11-25 14:01:38 +0000308}
309
310/**
311 * Update mutex_info state when unlocking the pthread_mutex_t mutex.
312 * Note: this function must be called before pthread_mutex_unlock() is called,
313 * or a race condition is triggered !
bartb78312c2008-02-29 11:00:17 +0000314 * @return New value of the mutex recursion count.
sewardjaf44c822007-11-25 14:01:38 +0000315 * @param mutex Pointer to pthread_mutex_t data structure in the client space.
316 * @param tid ThreadId of the thread calling pthread_mutex_unlock().
317 * @param vc Pointer to the current vector clock of thread tid.
318 */
bart777f7fe2008-03-02 17:43:18 +0000319void mutex_unlock(const Addr mutex, const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000320{
bartb78312c2008-02-29 11:00:17 +0000321 const DrdThreadId drd_tid = thread_get_running_tid();
322 const ThreadId vg_tid = VG_(get_running_tid)();
sewardjaf44c822007-11-25 14:01:38 +0000323 const VectorClock* const vc = thread_get_vc(drd_tid);
324 struct mutex_info* const p = mutex_get(mutex);
325
bart777f7fe2008-03-02 17:43:18 +0000326 if (s_trace_mutex)
sewardjaf44c822007-11-25 14:01:38 +0000327 {
bart3b1ee452008-02-29 19:28:15 +0000328 VG_(message)(Vg_UserMsg,
329 "[%d/%d] mutex_unlock %s 0x%lx rc %d",
330 vg_tid,
331 drd_tid,
bart777f7fe2008-03-02 17:43:18 +0000332 p ? mutex_get_typename(p) : "?",
sewardjaf44c822007-11-25 14:01:38 +0000333 mutex,
bart777f7fe2008-03-02 17:43:18 +0000334 p ? p->recursion_count : 0,
335 p ? p->owner : 0);
sewardjaf44c822007-11-25 14:01:38 +0000336 }
337
bart777f7fe2008-03-02 17:43:18 +0000338 if (p == 0 || mutex_type == mutex_type_invalid_mutex)
bartab7a6442008-02-25 19:46:14 +0000339 {
bart5bd9f2d2008-03-03 20:31:58 +0000340 GenericErrInfo GEI;
341 VG_(maybe_record_error)(vg_tid,
342 GenericErr,
343 VG_(get_IP)(vg_tid),
344 "Not a mutex",
345 &GEI);
346 return;
bartab7a6442008-02-25 19:46:14 +0000347 }
348
bart5357fcb2008-02-27 15:46:00 +0000349 if (p->owner == DRD_INVALID_THREADID)
350 {
bart4bb53d82008-02-28 19:06:34 +0000351 MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
bart5357fcb2008-02-27 15:46:00 +0000352 VG_(maybe_record_error)(vg_tid,
353 MutexErr,
354 VG_(get_IP)(vg_tid),
355 "Mutex not locked",
356 &MEI);
bart5bd9f2d2008-03-03 20:31:58 +0000357 return;
bart5357fcb2008-02-27 15:46:00 +0000358 }
359
sewardjaf44c822007-11-25 14:01:38 +0000360 tl_assert(p);
bart5357fcb2008-02-27 15:46:00 +0000361 if (p->mutex_type != mutex_type)
362 {
bart3b1ee452008-02-29 19:28:15 +0000363 VG_(message)(Vg_UserMsg, "??? mutex %p: type changed from %d into %d",
bart5bd9f2d2008-03-03 20:31:58 +0000364 p->a1, p->mutex_type, mutex_type);
bart5357fcb2008-02-27 15:46:00 +0000365 }
sewardj721ad7b2007-11-30 08:30:29 +0000366 tl_assert(p->mutex_type == mutex_type);
sewardjaf44c822007-11-25 14:01:38 +0000367 tl_assert(p->owner != DRD_INVALID_THREADID);
sewardj721ad7b2007-11-30 08:30:29 +0000368
bart777f7fe2008-03-02 17:43:18 +0000369 if (p->owner != drd_tid || p->recursion_count <= 0)
sewardjaf44c822007-11-25 14:01:38 +0000370 {
bart4bb53d82008-02-28 19:06:34 +0000371 MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
sewardjaf44c822007-11-25 14:01:38 +0000372 VG_(maybe_record_error)(vg_tid,
373 MutexErr,
374 VG_(get_IP)(vg_tid),
bart777f7fe2008-03-02 17:43:18 +0000375 "Mutex not locked by calling thread",
sewardjaf44c822007-11-25 14:01:38 +0000376 &MEI);
bart777f7fe2008-03-02 17:43:18 +0000377 return;
sewardjaf44c822007-11-25 14:01:38 +0000378 }
bart777f7fe2008-03-02 17:43:18 +0000379 tl_assert(p->recursion_count > 0);
sewardjaf44c822007-11-25 14:01:38 +0000380 p->recursion_count--;
bart777f7fe2008-03-02 17:43:18 +0000381 tl_assert(p->recursion_count >= 0);
sewardj347eeba2008-01-21 14:19:07 +0000382
sewardjaf44c822007-11-25 14:01:38 +0000383 if (p->recursion_count == 0)
384 {
385 /* This pthread_mutex_unlock() call really unlocks the mutex. Save the */
386 /* current vector clock of the thread such that it is available when */
387 /* this mutex is locked again. */
bart301c3112008-02-24 18:22:37 +0000388 vc_assign(&p->vc, vc);
sewardjaf44c822007-11-25 14:01:38 +0000389
390 thread_new_segment(drd_tid);
391 }
sewardjaf44c822007-11-25 14:01:38 +0000392}
393
394const char* mutex_get_typename(struct mutex_info* const p)
395{
396 tl_assert(p);
sewardj721ad7b2007-11-30 08:30:29 +0000397
sewardj347eeba2008-01-21 14:19:07 +0000398 return mutex_type_name(p->mutex_type);
399}
400
401const char* mutex_type_name(const MutexT mt)
402{
403 switch (mt)
sewardjaf44c822007-11-25 14:01:38 +0000404 {
bart635cb162008-02-28 08:30:43 +0000405 case mutex_type_invalid_mutex:
406 return "invalid mutex";
bart5357fcb2008-02-27 15:46:00 +0000407 case mutex_type_recursive_mutex:
408 return "recursive mutex";
409 case mutex_type_errorcheck_mutex:
410 return "error checking mutex";
411 case mutex_type_default_mutex:
sewardjaf44c822007-11-25 14:01:38 +0000412 return "mutex";
sewardj721ad7b2007-11-30 08:30:29 +0000413 case mutex_type_spinlock:
sewardjaf44c822007-11-25 14:01:38 +0000414 return "spinlock";
415 default:
416 tl_assert(0);
417 }
418 return "?";
419}
420
bart5357fcb2008-02-27 15:46:00 +0000421/** Return true if the specified mutex is locked by any thread. */
422static Bool mutex_is_locked(struct mutex_info* const p)
423{
424 tl_assert(p);
425 return (p->recursion_count > 0);
426}
427
sewardjaf44c822007-11-25 14:01:38 +0000428Bool mutex_is_locked_by(const Addr mutex, const DrdThreadId tid)
429{
430 struct mutex_info* const p = mutex_get(mutex);
sewardjaf44c822007-11-25 14:01:38 +0000431 if (p)
432 {
433 return (p->recursion_count > 0 && p->owner == tid);
434 }
435 return False;
436}
437
438const VectorClock* mutex_get_last_vc(const Addr mutex)
439{
440 struct mutex_info* const p = mutex_get(mutex);
441 return p ? &p->vc : 0;
442}
443
444int mutex_get_recursion_count(const Addr mutex)
445{
446 struct mutex_info* const p = mutex_get(mutex);
447 tl_assert(p);
448 return p->recursion_count;
449}
450
451/**
bart301c3112008-02-24 18:22:37 +0000452 * Call this function when thread tid stops to exist, such that the
sewardjaf44c822007-11-25 14:01:38 +0000453 * "last owner" field can be cleared if it still refers to that thread.
sewardjaf44c822007-11-25 14:01:38 +0000454 */
bart301c3112008-02-24 18:22:37 +0000455void mutex_thread_delete(const DrdThreadId tid)
sewardjaf44c822007-11-25 14:01:38 +0000456{
bart4bb53d82008-02-28 19:06:34 +0000457 struct mutex_info* p;
458
bart72b751c2008-03-01 13:44:24 +0000459 clientobj_resetiter();
460 for ( ; (p = &clientobj_next(ClientMutex)->mutex) != 0; )
sewardjaf44c822007-11-25 14:01:38 +0000461 {
bart4bb53d82008-02-28 19:06:34 +0000462 if (p->owner == tid && p->recursion_count > 0)
sewardjaf44c822007-11-25 14:01:38 +0000463 {
bart5357fcb2008-02-27 15:46:00 +0000464 MutexErrInfo MEI
bart4bb53d82008-02-28 19:06:34 +0000465 = { p->a1, p->recursion_count, p->owner };
bart5357fcb2008-02-27 15:46:00 +0000466 VG_(maybe_record_error)(VG_(get_running_tid)(),
467 MutexErr,
468 VG_(get_IP)(VG_(get_running_tid)()),
469 "Mutex still locked at thread exit",
470 &MEI);
sewardjaf44c822007-11-25 14:01:38 +0000471 p->owner = VG_INVALID_THREADID;
472 }
473 }
474}
475
sewardjaf44c822007-11-25 14:01:38 +0000476ULong get_mutex_lock_count(void)
477{
478 return s_mutex_lock_count;
479}
sewardj347eeba2008-01-21 14:19:07 +0000480
481
482/*
483 * Local variables:
bart5bd9f2d2008-03-03 20:31:58 +0000484 * c-basic-offset: 2
sewardj347eeba2008-01-21 14:19:07 +0000485 * End:
486 */