blob: 16cd92ef36d3b57ab4f7cc8ad67878beed9e5bc8 [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()
bart4bb53d82008-02-28 19:06:34 +000032#include "pub_tool_libcprint.h" // VG_(message)()
sewardjaf44c822007-11-25 14:01:38 +000033#include "pub_tool_machine.h" // VG_(get_IP)()
34#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
35
36
sewardj347eeba2008-01-21 14:19:07 +000037// Local functions.
38
bart46d5f172008-02-28 19:49:37 +000039static void mutex_cleanup(struct mutex_info* p);
bart5357fcb2008-02-27 15:46:00 +000040static Bool mutex_is_locked(struct mutex_info* const p);
sewardj347eeba2008-01-21 14:19:07 +000041static void mutex_destroy(struct mutex_info* const p);
42
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{
79 if (mutex_is_locked(p))
80 {
81 MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
82 VG_(maybe_record_error)(VG_(get_running_tid)(),
83 MutexErr,
84 VG_(get_IP)(VG_(get_running_tid)()),
85 "Destroying locked mutex",
86 &MEI);
87 }
88
89 vc_cleanup(&p->vc);
90}
91
sewardjaf44c822007-11-25 14:01:38 +000092static
sewardj721ad7b2007-11-30 08:30:29 +000093struct mutex_info*
94mutex_get_or_allocate(const Addr mutex,
95 const SizeT size,
96 const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +000097{
bart4bb53d82008-02-28 19:06:34 +000098 struct mutex_info* p;
sewardj721ad7b2007-11-30 08:30:29 +000099
bart4bb53d82008-02-28 19:06:34 +0000100 tl_assert(offsetof(DrdClientobj, mutex) == 0);
101 p = &drd_clientobj_get(mutex, ClientMutex)->mutex;
102 if (p)
103 {
104 tl_assert(p->mutex_type == mutex_type);
105 tl_assert(p->a2 - p->a1 == size);
106 return p;
107 }
sewardj721ad7b2007-11-30 08:30:29 +0000108
bart4bb53d82008-02-28 19:06:34 +0000109 if (drd_clientobj_present(mutex, mutex + size))
sewardj721ad7b2007-11-30 08:30:29 +0000110 {
bart4bb53d82008-02-28 19:06:34 +0000111 GenericErrInfo GEI;
112 VG_(maybe_record_error)(VG_(get_running_tid)(),
113 GenericErr,
114 VG_(get_IP)(VG_(get_running_tid)()),
115 "Not a mutex",
116 &GEI);
117 return 0;
sewardj721ad7b2007-11-30 08:30:29 +0000118 }
bart4bb53d82008-02-28 19:06:34 +0000119
120 p = &drd_clientobj_add(mutex, mutex + size, ClientMutex)->mutex;
121 mutex_initialize(p, mutex, size, mutex_type);
122 return p;
sewardjaf44c822007-11-25 14:01:38 +0000123}
124
sewardj721ad7b2007-11-30 08:30:29 +0000125struct mutex_info*
126mutex_init(const Addr mutex, const SizeT size, const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000127{
128 struct mutex_info* mutex_p;
129
sewardjaf44c822007-11-25 14:01:38 +0000130 if (s_trace_mutex)
131 {
132 const ThreadId vg_tid = VG_(get_running_tid)();
133 const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(vg_tid);
134 VG_(message)(Vg_DebugMsg,
135 "drd_post_mutex_init tid = %d/%d, %s 0x%lx",
136 vg_tid, drd_tid,
sewardj347eeba2008-01-21 14:19:07 +0000137 mutex_type_name(mutex_type),
sewardjaf44c822007-11-25 14:01:38 +0000138 mutex);
139 }
140
sewardj347eeba2008-01-21 14:19:07 +0000141 mutex_p = mutex_get(mutex);
142 if (mutex_p)
143 {
144 const ThreadId vg_tid = VG_(get_running_tid)();
145 MutexErrInfo MEI
bart4bb53d82008-02-28 19:06:34 +0000146 = { mutex_p->a1, mutex_p->recursion_count, mutex_p->owner };
sewardj347eeba2008-01-21 14:19:07 +0000147 VG_(maybe_record_error)(vg_tid,
148 MutexErr,
149 VG_(get_IP)(vg_tid),
150 "Mutex reinitialization",
151 &MEI);
152 mutex_destroy(mutex_p);
153 }
154 mutex_p = mutex_get_or_allocate(mutex, size, mutex_type);
155
sewardjaf44c822007-11-25 14:01:38 +0000156 return mutex_p;
157}
158
sewardj347eeba2008-01-21 14:19:07 +0000159static void mutex_destroy(struct mutex_info* const p)
sewardjaf44c822007-11-25 14:01:38 +0000160{
161 if (s_trace_mutex)
162 {
163 const ThreadId vg_tid = VG_(get_running_tid)();
164 const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(vg_tid);
165 VG_(message)(Vg_DebugMsg,
166 "drd_pre_mutex_destroy tid = %d/%d, %s 0x%lx",
167 vg_tid, drd_tid,
168 mutex_get_typename(p),
bart4bb53d82008-02-28 19:06:34 +0000169 p->a1);
sewardjaf44c822007-11-25 14:01:38 +0000170 }
171
bart4bb53d82008-02-28 19:06:34 +0000172 drd_clientobj_remove(p->a1);
sewardjaf44c822007-11-25 14:01:38 +0000173}
174
bart46d5f172008-02-28 19:49:37 +0000175/** Called after pthread_mutex_destroy(). */
sewardj347eeba2008-01-21 14:19:07 +0000176void mutex_post_destroy(const Addr mutex)
177{
178 struct mutex_info* p;
179
180 p = mutex_get(mutex);
181 tl_assert(p);
182 if (p)
183 {
bart46d5f172008-02-28 19:49:37 +0000184 mutex_destroy(p);
sewardj347eeba2008-01-21 14:19:07 +0000185 }
186}
187
sewardjaf44c822007-11-25 14:01:38 +0000188struct mutex_info* mutex_get(const Addr mutex)
189{
bart4bb53d82008-02-28 19:06:34 +0000190 tl_assert(offsetof(DrdClientobj, mutex) == 0);
191 return &drd_clientobj_get(mutex, ClientMutex)->mutex;
sewardjaf44c822007-11-25 14:01:38 +0000192}
193
bart8bba1f72008-02-27 16:13:05 +0000194/** Called before pthread_mutex_lock() is invoked. If a data structure for
195 * the client-side object was not yet created, do this now. Also check whether
196 * an attempt is made to lock recursively a synchronization object that must
197 * not be locked recursively.
198 */
199void mutex_pre_lock(const Addr mutex, const SizeT size, MutexT mutex_type)
200{
bart635cb162008-02-28 08:30:43 +0000201 struct mutex_info* p;
202
203 p = mutex_get(mutex);
bart8bba1f72008-02-27 16:13:05 +0000204 if (p == 0)
205 {
206 mutex_init(mutex, size, mutex_type);
207 p = mutex_get(mutex);
208 }
bart635cb162008-02-28 08:30:43 +0000209
bart8bba1f72008-02-27 16:13:05 +0000210 tl_assert(p);
211
212 if (p->owner == thread_get_running_tid()
213 && p->recursion_count >= 1
214 && mutex_type != mutex_type_recursive_mutex)
215 {
bart4bb53d82008-02-28 19:06:34 +0000216 MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
bart8bba1f72008-02-27 16:13:05 +0000217 VG_(maybe_record_error)(VG_(get_running_tid)(),
218 MutexErr,
219 VG_(get_IP)(VG_(get_running_tid)()),
220 "Recursive locking not allowed",
221 &MEI);
222 }
223}
224
sewardjaf44c822007-11-25 14:01:38 +0000225/**
226 * Update mutex_info state when locking the pthread_mutex_t mutex.
227 * Note: this function must be called after pthread_mutex_lock() has been
228 * called, or a race condition is triggered !
229 */
bart8bba1f72008-02-27 16:13:05 +0000230int mutex_post_lock(const Addr mutex, const SizeT size, MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000231{
232 const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(VG_(get_running_tid)());
sewardj721ad7b2007-11-30 08:30:29 +0000233 struct mutex_info* const p = mutex_get_or_allocate(mutex, size, mutex_type);
sewardjaf44c822007-11-25 14:01:38 +0000234
235 if (s_trace_mutex)
236 {
237 const ThreadId tid = DrdThreadIdToVgThreadId(drd_tid);
238 VG_(message)(Vg_DebugMsg,
239 "drd_post_mutex_lock tid = %d/%d, %s 0x%lx rc %d owner %d",
240 tid,
241 drd_tid,
242 mutex_get_typename(p),
243 mutex,
244 p ? p->recursion_count : 0,
245 p ? p->owner : VG_INVALID_THREADID);
246 }
247
bart635cb162008-02-28 08:30:43 +0000248 if (mutex_type == mutex_type_invalid_mutex)
249 {
250 GenericErrInfo GEI;
251 VG_(maybe_record_error)(VG_(get_running_tid)(),
252 GenericErr,
253 VG_(get_IP)(VG_(get_running_tid)()),
254 "Invalid mutex",
255 &GEI);
256 }
257
bartab7a6442008-02-25 19:46:14 +0000258 if (p == 0)
259 {
barte883bc82008-02-26 19:13:04 +0000260 GenericErrInfo GEI;
bartab7a6442008-02-25 19:46:14 +0000261 VG_(maybe_record_error)(VG_(get_running_tid)(),
barte883bc82008-02-26 19:13:04 +0000262 GenericErr,
bartab7a6442008-02-25 19:46:14 +0000263 VG_(get_IP)(VG_(get_running_tid)()),
264 "Not a mutex",
barte883bc82008-02-26 19:13:04 +0000265 &GEI);
bartab7a6442008-02-25 19:46:14 +0000266 return 0;
267 }
268
bart5357fcb2008-02-27 15:46:00 +0000269#if 0
sewardj721ad7b2007-11-30 08:30:29 +0000270 tl_assert(mutex_type == mutex_type_mutex
271 || mutex_type == mutex_type_spinlock);
bart5357fcb2008-02-27 15:46:00 +0000272#endif
273
sewardj721ad7b2007-11-30 08:30:29 +0000274 tl_assert(p->mutex_type == mutex_type);
bart4bb53d82008-02-28 19:06:34 +0000275 tl_assert(p->a2 - p->a1 == size);
sewardj721ad7b2007-11-30 08:30:29 +0000276
sewardjaf44c822007-11-25 14:01:38 +0000277 if (p->recursion_count == 0)
278 {
279 p->owner = drd_tid;
280 s_mutex_lock_count++;
281 }
282 else if (p->owner != drd_tid)
283 {
284 VG_(message)(Vg_DebugMsg,
285 "The impossible happened: mutex 0x%lx is locked"
286 " simultaneously by two threads (recursion count %d,"
287 " owners %d and %d) !",
bart4bb53d82008-02-28 19:06:34 +0000288 p->a1, p->recursion_count, p->owner, drd_tid);
sewardj347eeba2008-01-21 14:19:07 +0000289 p->owner = drd_tid;
sewardjaf44c822007-11-25 14:01:38 +0000290 }
291 p->recursion_count++;
292
293 if (p->recursion_count == 1)
294 {
bartab7a6442008-02-25 19:46:14 +0000295 const DrdThreadId last_owner = p->owner;
296
sewardjaf44c822007-11-25 14:01:38 +0000297 if (last_owner != drd_tid && last_owner != DRD_INVALID_THREADID)
298 thread_combine_vc2(drd_tid, mutex_get_last_vc(mutex));
299 thread_new_segment(drd_tid);
300 }
301
302 return p->recursion_count;
303}
304
305/**
306 * Update mutex_info state when unlocking the pthread_mutex_t mutex.
307 * Note: this function must be called before pthread_mutex_unlock() is called,
308 * or a race condition is triggered !
309 * @param mutex Pointer to pthread_mutex_t data structure in the client space.
310 * @param tid ThreadId of the thread calling pthread_mutex_unlock().
311 * @param vc Pointer to the current vector clock of thread tid.
312 */
sewardj721ad7b2007-11-30 08:30:29 +0000313int mutex_unlock(const Addr mutex, const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000314{
315 const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(VG_(get_running_tid)());
316 const ThreadId vg_tid = DrdThreadIdToVgThreadId(drd_tid);
317 const VectorClock* const vc = thread_get_vc(drd_tid);
318 struct mutex_info* const p = mutex_get(mutex);
319
320 if (s_trace_mutex)
321 {
322 VG_(message)(Vg_DebugMsg,
323 "drd_pre_mutex_unlock tid = %d/%d, %s 0x%lx rc %d",
324 vg_tid, drd_tid,
325 mutex_get_typename(p),
326 mutex,
327 p->recursion_count,
328 p->owner);
329 }
330
bart635cb162008-02-28 08:30:43 +0000331 if (mutex_type == mutex_type_invalid_mutex)
332 {
333 GenericErrInfo GEI;
334 VG_(maybe_record_error)(VG_(get_running_tid)(),
335 GenericErr,
336 VG_(get_IP)(VG_(get_running_tid)()),
337 "Invalid mutex",
338 &GEI);
339 }
340
bart5357fcb2008-02-27 15:46:00 +0000341 if (p == 0)
bartab7a6442008-02-25 19:46:14 +0000342 {
barte883bc82008-02-26 19:13:04 +0000343 GenericErrInfo GEI;
bartab7a6442008-02-25 19:46:14 +0000344 VG_(maybe_record_error)(vg_tid,
barte883bc82008-02-26 19:13:04 +0000345 GenericErr,
bartab7a6442008-02-25 19:46:14 +0000346 VG_(get_IP)(vg_tid),
347 "Not a mutex",
barte883bc82008-02-26 19:13:04 +0000348 &GEI);
bartab7a6442008-02-25 19:46:14 +0000349 return 0;
350 }
351
bart5357fcb2008-02-27 15:46:00 +0000352 if (p->owner == DRD_INVALID_THREADID)
353 {
bart4bb53d82008-02-28 19:06:34 +0000354 MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
bart5357fcb2008-02-27 15:46:00 +0000355 VG_(maybe_record_error)(vg_tid,
356 MutexErr,
357 VG_(get_IP)(vg_tid),
358 "Mutex not locked",
359 &MEI);
360 return 0;
361 }
362
sewardjaf44c822007-11-25 14:01:38 +0000363 tl_assert(p);
bart5357fcb2008-02-27 15:46:00 +0000364 if (p->mutex_type != mutex_type)
365 {
366 VG_(message)(Vg_DebugMsg, "??? mutex %p: type changed from %d into %d",
bart4bb53d82008-02-28 19:06:34 +0000367 p->a1, p->mutex_type, mutex_type);
bart5357fcb2008-02-27 15:46:00 +0000368 }
sewardj721ad7b2007-11-30 08:30:29 +0000369 tl_assert(p->mutex_type == mutex_type);
sewardjaf44c822007-11-25 14:01:38 +0000370 tl_assert(p->owner != DRD_INVALID_THREADID);
bart5357fcb2008-02-27 15:46:00 +0000371#if 0
sewardj721ad7b2007-11-30 08:30:29 +0000372 tl_assert(mutex_type == mutex_type_mutex
373 || mutex_type == mutex_type_spinlock);
bart5357fcb2008-02-27 15:46:00 +0000374#endif
sewardj721ad7b2007-11-30 08:30:29 +0000375
sewardjaf44c822007-11-25 14:01:38 +0000376 if (p->owner != drd_tid)
377 {
bart4bb53d82008-02-28 19:06:34 +0000378 MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
sewardjaf44c822007-11-25 14:01:38 +0000379 VG_(maybe_record_error)(vg_tid,
380 MutexErr,
381 VG_(get_IP)(vg_tid),
382 "Mutex not unlocked by owner thread",
383 &MEI);
384 }
385 p->recursion_count--;
sewardj347eeba2008-01-21 14:19:07 +0000386 if (p->recursion_count < 0)
387 {
388 MutexErrInfo MEI
bart4bb53d82008-02-28 19:06:34 +0000389 = { p->a1, p->recursion_count, p->owner };
sewardj347eeba2008-01-21 14:19:07 +0000390 VG_(maybe_record_error)(vg_tid,
391 MutexErr,
392 VG_(get_IP)(vg_tid),
393 "Attempt to unlock a mutex that is not locked",
394 &MEI);
395 p->recursion_count = 0;
396 }
397
sewardjaf44c822007-11-25 14:01:38 +0000398 if (p->recursion_count == 0)
399 {
400 /* This pthread_mutex_unlock() call really unlocks the mutex. Save the */
401 /* current vector clock of the thread such that it is available when */
402 /* this mutex is locked again. */
bart301c3112008-02-24 18:22:37 +0000403 vc_assign(&p->vc, vc);
sewardjaf44c822007-11-25 14:01:38 +0000404
405 thread_new_segment(drd_tid);
406 }
407 return p->recursion_count;
408}
409
410const char* mutex_get_typename(struct mutex_info* const p)
411{
412 tl_assert(p);
sewardj721ad7b2007-11-30 08:30:29 +0000413
sewardj347eeba2008-01-21 14:19:07 +0000414 return mutex_type_name(p->mutex_type);
415}
416
417const char* mutex_type_name(const MutexT mt)
418{
419 switch (mt)
sewardjaf44c822007-11-25 14:01:38 +0000420 {
bart635cb162008-02-28 08:30:43 +0000421 case mutex_type_invalid_mutex:
422 return "invalid mutex";
bart5357fcb2008-02-27 15:46:00 +0000423 case mutex_type_recursive_mutex:
424 return "recursive mutex";
425 case mutex_type_errorcheck_mutex:
426 return "error checking mutex";
427 case mutex_type_default_mutex:
sewardjaf44c822007-11-25 14:01:38 +0000428 return "mutex";
sewardj721ad7b2007-11-30 08:30:29 +0000429 case mutex_type_spinlock:
sewardjaf44c822007-11-25 14:01:38 +0000430 return "spinlock";
431 default:
432 tl_assert(0);
433 }
434 return "?";
435}
436
bart5357fcb2008-02-27 15:46:00 +0000437/** Return true if the specified mutex is locked by any thread. */
438static Bool mutex_is_locked(struct mutex_info* const p)
439{
440 tl_assert(p);
441 return (p->recursion_count > 0);
442}
443
sewardjaf44c822007-11-25 14:01:38 +0000444Bool mutex_is_locked_by(const Addr mutex, const DrdThreadId tid)
445{
446 struct mutex_info* const p = mutex_get(mutex);
sewardjaf44c822007-11-25 14:01:38 +0000447 if (p)
448 {
449 return (p->recursion_count > 0 && p->owner == tid);
450 }
451 return False;
452}
453
454const VectorClock* mutex_get_last_vc(const Addr mutex)
455{
456 struct mutex_info* const p = mutex_get(mutex);
457 return p ? &p->vc : 0;
458}
459
460int mutex_get_recursion_count(const Addr mutex)
461{
462 struct mutex_info* const p = mutex_get(mutex);
463 tl_assert(p);
464 return p->recursion_count;
465}
466
467/**
bart301c3112008-02-24 18:22:37 +0000468 * Call this function when thread tid stops to exist, such that the
sewardjaf44c822007-11-25 14:01:38 +0000469 * "last owner" field can be cleared if it still refers to that thread.
sewardjaf44c822007-11-25 14:01:38 +0000470 */
bart301c3112008-02-24 18:22:37 +0000471void mutex_thread_delete(const DrdThreadId tid)
sewardjaf44c822007-11-25 14:01:38 +0000472{
bart4bb53d82008-02-28 19:06:34 +0000473 struct mutex_info* p;
474
475 drd_clientobj_resetiter();
476 for ( ; (p = &drd_clientobj_next(ClientMutex)->mutex) != 0; )
sewardjaf44c822007-11-25 14:01:38 +0000477 {
bart4bb53d82008-02-28 19:06:34 +0000478 if (p->owner == tid && p->recursion_count > 0)
sewardjaf44c822007-11-25 14:01:38 +0000479 {
bart5357fcb2008-02-27 15:46:00 +0000480 MutexErrInfo MEI
bart4bb53d82008-02-28 19:06:34 +0000481 = { p->a1, p->recursion_count, p->owner };
bart5357fcb2008-02-27 15:46:00 +0000482 VG_(maybe_record_error)(VG_(get_running_tid)(),
483 MutexErr,
484 VG_(get_IP)(VG_(get_running_tid)()),
485 "Mutex still locked at thread exit",
486 &MEI);
sewardjaf44c822007-11-25 14:01:38 +0000487 p->owner = VG_INVALID_THREADID;
488 }
489 }
490}
491
sewardjaf44c822007-11-25 14:01:38 +0000492ULong get_mutex_lock_count(void)
493{
494 return s_mutex_lock_count;
495}
sewardj347eeba2008-01-21 14:19:07 +0000496
497
498/*
499 * Local variables:
500 * c-basic-offset: 3
501 * End:
502 */