1 /*
2 This file is part of drd, a thread error detector.
3
4 Copyright (C) 2006-2012 Bart Van Assche <bvanassche@acm.org>.
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307, USA.
20
21 The GNU General Public License is contained in the file COPYING.
22 */
23
24
25 #include "drd_basics.h"
26 #include "drd_clientobj.h"
27 #include "drd_error.h"
28 #include "drd_mutex.h"
29 #include "pub_tool_vki.h"
30 #include "pub_tool_errormgr.h" /* VG_(maybe_record_error)() */
31 #include "pub_tool_libcassert.h" /* tl_assert() */
32 #include "pub_tool_libcbase.h" /* VG_(strlen) */
33 #include "pub_tool_libcprint.h" /* VG_(message)() */
34 #include "pub_tool_libcproc.h" /* VG_(read_millisecond_timer)() */
35 #include "pub_tool_machine.h" /* VG_(get_IP)() */
36 #include "pub_tool_threadstate.h" /* VG_(get_running_tid)() */
37
38
39 /* Local functions. */
40
41 static void mutex_cleanup(struct mutex_info* p);
42 static Bool mutex_is_locked(struct mutex_info* const p);
43 static void mutex_delete_thread(struct mutex_info* p, const DrdThreadId tid);
44
45
46 /* Local variables. */
47
48 static Bool s_trace_mutex;
49 static ULong s_mutex_lock_count;
50 static ULong s_mutex_segment_creation_count;
51 static UInt s_mutex_lock_threshold_ms;
52
53
54 /* Function definitions. */
55
DRD_(mutex_set_trace)56 void DRD_(mutex_set_trace)(const Bool trace_mutex)
57 {
58 tl_assert(!! trace_mutex == trace_mutex);
59 s_trace_mutex = trace_mutex;
60 }
61
DRD_(mutex_set_lock_threshold)62 void DRD_(mutex_set_lock_threshold)(const UInt lock_threshold_ms)
63 {
64 s_mutex_lock_threshold_ms = lock_threshold_ms;
65 }
66
67 static
DRD_(mutex_initialize)68 void DRD_(mutex_initialize)(struct mutex_info* const p,
69 const Addr mutex, const MutexT mutex_type)
70 {
71 tl_assert(mutex);
72 tl_assert(p->a1 == mutex);
73
74 p->cleanup = (void(*)(DrdClientobj*))mutex_cleanup;
75 p->delete_thread
76 = (void(*)(DrdClientobj*, DrdThreadId))mutex_delete_thread;
77 p->mutex_type = mutex_type;
78 p->recursion_count = 0;
79 p->owner = DRD_INVALID_THREADID;
80 p->last_locked_segment = 0;
81 p->acquiry_time_ms = 0;
82 p->acquired_at = 0;
83 }
84
85 /** Deallocate the memory that was allocated by mutex_initialize(). */
mutex_cleanup(struct mutex_info * p)86 static void mutex_cleanup(struct mutex_info* p)
87 {
88 tl_assert(p);
89
90 if (s_trace_mutex)
91 DRD_(trace_msg)("[%d] mutex_destroy %s 0x%lx rc %d owner %d",
92 DRD_(thread_get_running_tid)(),
93 DRD_(mutex_get_typename)(p), p->a1,
94 p ? p->recursion_count : -1,
95 p ? p->owner : DRD_INVALID_THREADID);
96
97 if (mutex_is_locked(p))
98 {
99 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
100 p->a1, p->recursion_count, p->owner };
101 VG_(maybe_record_error)(VG_(get_running_tid)(),
102 MutexErr,
103 VG_(get_IP)(VG_(get_running_tid)()),
104 "Destroying locked mutex",
105 &MEI);
106 }
107
108 DRD_(sg_put)(p->last_locked_segment);
109 p->last_locked_segment = 0;
110 }
111
112 /** Report that address 'mutex' is not the address of a mutex object. */
DRD_(not_a_mutex)113 void DRD_(not_a_mutex)(const Addr mutex)
114 {
115 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
116 mutex, -1, DRD_INVALID_THREADID };
117 VG_(maybe_record_error)(VG_(get_running_tid)(),
118 MutexErr,
119 VG_(get_IP)(VG_(get_running_tid)()),
120 "Not a mutex",
121 &MEI);
122 }
123
124 /**
125 * Report that address 'mutex' is not the address of a mutex object of the
126 * expected type.
127 */
wrong_mutex_type(const Addr mutex)128 static void wrong_mutex_type(const Addr mutex)
129 {
130 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
131 mutex, -1, DRD_INVALID_THREADID };
132 VG_(maybe_record_error)(VG_(get_running_tid)(),
133 MutexErr,
134 VG_(get_IP)(VG_(get_running_tid)()),
135 "Mutex type mismatch",
136 &MEI);
137 }
138
139 static
140 struct mutex_info*
DRD_(mutex_get_or_allocate)141 DRD_(mutex_get_or_allocate)(const Addr mutex, const MutexT mutex_type)
142 {
143 struct mutex_info* p;
144
145 tl_assert(offsetof(DrdClientobj, mutex) == 0);
146 p = &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex);
147 if (p)
148 {
149 if (mutex_type == mutex_type_unknown || p->mutex_type == mutex_type)
150 return p;
151 else
152 {
153 wrong_mutex_type(mutex);
154 return 0;
155 }
156 }
157
158 if (DRD_(clientobj_present)(mutex, mutex + 1))
159 {
160 DRD_(not_a_mutex)(mutex);
161 return 0;
162 }
163
164 p = &(DRD_(clientobj_add)(mutex, ClientMutex)->mutex);
165 DRD_(mutex_initialize)(p, mutex, mutex_type);
166 return p;
167 }
168
DRD_(mutex_get)169 struct mutex_info* DRD_(mutex_get)(const Addr mutex)
170 {
171 tl_assert(offsetof(DrdClientobj, mutex) == 0);
172 return &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex);
173 }
174
175 /** Called before pthread_mutex_init(). */
176 struct mutex_info*
DRD_(mutex_init)177 DRD_(mutex_init)(const Addr mutex, const MutexT mutex_type)
178 {
179 struct mutex_info* p;
180
181 if (s_trace_mutex)
182 DRD_(trace_msg)("[%d] mutex_init %s 0x%lx",
183 DRD_(thread_get_running_tid)(),
184 DRD_(mutex_type_name)(mutex_type),
185 mutex);
186
187 if (mutex_type == mutex_type_invalid_mutex)
188 {
189 DRD_(not_a_mutex)(mutex);
190 return 0;
191 }
192
193 p = DRD_(mutex_get)(mutex);
194 if (p)
195 {
196 const ThreadId vg_tid = VG_(get_running_tid)();
197 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
198 p->a1, p->recursion_count, p->owner };
199 VG_(maybe_record_error)(vg_tid,
200 MutexErr,
201 VG_(get_IP)(vg_tid),
202 "Mutex reinitialization",
203 &MEI);
204 p->mutex_type = mutex_type;
205 return p;
206 }
207 p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
208
209 return p;
210 }
211
212 /** Called after pthread_mutex_destroy(). */
DRD_(mutex_post_destroy)213 void DRD_(mutex_post_destroy)(const Addr mutex)
214 {
215 struct mutex_info* p;
216
217 p = DRD_(mutex_get)(mutex);
218 if (p == 0)
219 {
220 DRD_(not_a_mutex)(mutex);
221 return;
222 }
223
224 DRD_(clientobj_remove)(mutex, ClientMutex);
225 }
226
227 /**
228 * Called before pthread_mutex_lock() is invoked. If a data structure for the
229 * client-side object was not yet created, do this now. Also check whether an
230 * attempt is made to lock recursively a synchronization object that must not
231 * be locked recursively.
232 */
DRD_(mutex_pre_lock)233 void DRD_(mutex_pre_lock)(const Addr mutex, MutexT mutex_type,
234 const Bool trylock)
235 {
236 struct mutex_info* p;
237
238 p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
239 if (p && mutex_type == mutex_type_unknown)
240 mutex_type = p->mutex_type;
241
242 if (s_trace_mutex)
243 DRD_(trace_msg)("[%d] %s %s 0x%lx rc %d owner %d",
244 DRD_(thread_get_running_tid)(),
245 trylock ? "pre_mutex_lock " : "mutex_trylock ",
246 p ? DRD_(mutex_get_typename)(p) : "(?)",
247 mutex, p ? p->recursion_count : -1,
248 p ? p->owner : DRD_INVALID_THREADID);
249
250 if (p == 0)
251 {
252 DRD_(not_a_mutex)(mutex);
253 return;
254 }
255
256 tl_assert(p);
257
258 if (mutex_type == mutex_type_invalid_mutex)
259 {
260 DRD_(not_a_mutex)(mutex);
261 return;
262 }
263
264 if (! trylock
265 && p->owner == DRD_(thread_get_running_tid)()
266 && p->recursion_count >= 1
267 && mutex_type != mutex_type_recursive_mutex)
268 {
269 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
270 p->a1, p->recursion_count, p->owner };
271 VG_(maybe_record_error)(VG_(get_running_tid)(),
272 MutexErr,
273 VG_(get_IP)(VG_(get_running_tid)()),
274 "Recursive locking not allowed",
275 &MEI);
276 }
277 }
278
279 /**
280 * Update mutex_info state when locking the pthread_mutex_t mutex.
281 * Note: this function must be called after pthread_mutex_lock() has been
282 * called, or a race condition is triggered !
283 */
DRD_(mutex_post_lock)284 void DRD_(mutex_post_lock)(const Addr mutex, const Bool took_lock,
285 const Bool post_cond_wait)
286 {
287 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
288 struct mutex_info* p;
289
290 p = DRD_(mutex_get)(mutex);
291
292 if (s_trace_mutex)
293 DRD_(trace_msg)("[%d] %s %s 0x%lx rc %d owner %d%s",
294 drd_tid,
295 post_cond_wait ? "cond_post_wait " : "post_mutex_lock",
296 p ? DRD_(mutex_get_typename)(p) : "(?)",
297 mutex, p ? p->recursion_count : 0,
298 p ? p->owner : VG_INVALID_THREADID,
299 took_lock ? "" : " (locking failed)");
300
301 if (! p || ! took_lock)
302 return;
303
304 if (p->recursion_count == 0) {
305 if (p->owner != drd_tid && p->owner != DRD_INVALID_THREADID)
306 {
307 tl_assert(p->last_locked_segment);
308
309 DRD_(thread_new_segment_and_combine_vc)(drd_tid,
310 p->last_locked_segment);
311 }
312 else
313 DRD_(thread_new_segment)(drd_tid);
314
315 s_mutex_segment_creation_count++;
316
317 p->owner = drd_tid;
318 p->acquiry_time_ms = VG_(read_millisecond_timer)();
319 p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
320 s_mutex_lock_count++;
321 } else if (p->owner != drd_tid) {
322 const ThreadId vg_tid = VG_(get_running_tid)();
323 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
324 p->a1, p->recursion_count, p->owner };
325 VG_(maybe_record_error)(vg_tid,
326 MutexErr,
327 VG_(get_IP)(vg_tid),
328 "The impossible happened: mutex is locked"
329 " simultaneously by two threads",
330 &MEI);
331 p->owner = drd_tid;
332 }
333 p->recursion_count++;
334 }
335
336 /**
337 * Update mutex_info state when unlocking the pthread_mutex_t mutex.
338 *
339 * @param[in] mutex Address of the client mutex.
340 * @param[in] mutex_type Mutex type.
341 *
342 * @return New value of the mutex recursion count.
343 *
344 * @note This function must be called before pthread_mutex_unlock() is called,
345 * or a race condition is triggered !
346 */
DRD_(mutex_unlock)347 void DRD_(mutex_unlock)(const Addr mutex, MutexT mutex_type)
348 {
349 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
350 const ThreadId vg_tid = VG_(get_running_tid)();
351 struct mutex_info* p;
352
353 p = DRD_(mutex_get)(mutex);
354 if (p && mutex_type == mutex_type_unknown)
355 mutex_type = p->mutex_type;
356
357 if (s_trace_mutex) {
358 DRD_(trace_msg)("[%d] mutex_unlock %s 0x%lx rc %d",
359 drd_tid, p ? DRD_(mutex_get_typename)(p) : "(?)",
360 mutex, p ? p->recursion_count : 0);
361 }
362
363 if (p == 0 || mutex_type == mutex_type_invalid_mutex)
364 {
365 DRD_(not_a_mutex)(mutex);
366 return;
367 }
368
369 if (p->owner == DRD_INVALID_THREADID)
370 {
371 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
372 p->a1, p->recursion_count, p->owner };
373 VG_(maybe_record_error)(vg_tid,
374 MutexErr,
375 VG_(get_IP)(vg_tid),
376 "Mutex not locked",
377 &MEI);
378 return;
379 }
380
381 tl_assert(p);
382 if (p->mutex_type != mutex_type) {
383 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
384 p->a1, p->recursion_count, p->owner };
385 VG_(maybe_record_error)(vg_tid, MutexErr, VG_(get_IP)(vg_tid),
386 "Mutex type changed", &MEI);
387 }
388 tl_assert(p->mutex_type == mutex_type);
389 tl_assert(p->owner != DRD_INVALID_THREADID);
390
391 if (p->owner != drd_tid || p->recursion_count <= 0)
392 {
393 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
394 p->a1, p->recursion_count, p->owner };
395 VG_(maybe_record_error)(vg_tid,
396 MutexErr,
397 VG_(get_IP)(vg_tid),
398 "Mutex not locked by calling thread",
399 &MEI);
400 return;
401 }
402 tl_assert(p->recursion_count > 0);
403 p->recursion_count--;
404 tl_assert(p->recursion_count >= 0);
405
406 if (p->recursion_count == 0)
407 {
408 if (s_mutex_lock_threshold_ms > 0)
409 {
410 Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
411 if (held > s_mutex_lock_threshold_ms)
412 {
413 HoldtimeErrInfo HEI
414 = { DRD_(thread_get_running_tid)(),
415 mutex, p->acquired_at, held, s_mutex_lock_threshold_ms };
416 VG_(maybe_record_error)(vg_tid,
417 HoldtimeErr,
418 VG_(get_IP)(vg_tid),
419 "mutex",
420 &HEI);
421 }
422 }
423
424 /* This pthread_mutex_unlock() call really unlocks the mutex. Save the */
425 /* current vector clock of the thread such that it is available when */
426 /* this mutex is locked again. */
427
428 DRD_(thread_get_latest_segment)(&p->last_locked_segment, drd_tid);
429 DRD_(thread_new_segment)(drd_tid);
430 p->acquired_at = 0;
431 s_mutex_segment_creation_count++;
432 }
433 }
434
DRD_(spinlock_init_or_unlock)435 void DRD_(spinlock_init_or_unlock)(const Addr spinlock)
436 {
437 struct mutex_info* mutex_p = DRD_(mutex_get)(spinlock);
438 if (mutex_p)
439 {
440 DRD_(mutex_unlock)(spinlock, mutex_type_spinlock);
441 }
442 else
443 {
444 DRD_(mutex_init)(spinlock, mutex_type_spinlock);
445 }
446 }
447
DRD_(mutex_get_typename)448 const char* DRD_(mutex_get_typename)(struct mutex_info* const p)
449 {
450 tl_assert(p);
451
452 return DRD_(mutex_type_name)(p->mutex_type);
453 }
454
DRD_(mutex_type_name)455 const char* DRD_(mutex_type_name)(const MutexT mt)
456 {
457 switch (mt)
458 {
459 case mutex_type_unknown:
460 return "mutex";
461 case mutex_type_invalid_mutex:
462 return "invalid mutex";
463 case mutex_type_recursive_mutex:
464 return "recursive mutex";
465 case mutex_type_errorcheck_mutex:
466 return "error checking mutex";
467 case mutex_type_default_mutex:
468 return "mutex";
469 case mutex_type_spinlock:
470 return "spinlock";
471 }
472 tl_assert(0);
473 return "?";
474 }
475
476 /** Return true if the specified mutex is locked by any thread. */
mutex_is_locked(struct mutex_info * const p)477 static Bool mutex_is_locked(struct mutex_info* const p)
478 {
479 tl_assert(p);
480 return (p->recursion_count > 0);
481 }
482
DRD_(mutex_is_locked_by)483 Bool DRD_(mutex_is_locked_by)(const Addr mutex, const DrdThreadId tid)
484 {
485 struct mutex_info* const p = DRD_(mutex_get)(mutex);
486 if (p)
487 {
488 return (p->recursion_count > 0 && p->owner == tid);
489 }
490 return False;
491 }
492
DRD_(mutex_get_recursion_count)493 int DRD_(mutex_get_recursion_count)(const Addr mutex)
494 {
495 struct mutex_info* const p = DRD_(mutex_get)(mutex);
496 tl_assert(p);
497 return p->recursion_count;
498 }
499
500 /**
501 * Call this function when thread tid stops to exist, such that the
502 * "last owner" field can be cleared if it still refers to that thread.
503 */
mutex_delete_thread(struct mutex_info * p,const DrdThreadId tid)504 static void mutex_delete_thread(struct mutex_info* p, const DrdThreadId tid)
505 {
506 tl_assert(p);
507
508 if (p->owner == tid && p->recursion_count > 0)
509 {
510 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
511 p->a1, p->recursion_count, p->owner };
512 VG_(maybe_record_error)(VG_(get_running_tid)(),
513 MutexErr,
514 VG_(get_IP)(VG_(get_running_tid)()),
515 "Mutex still locked at thread exit",
516 &MEI);
517 p->owner = VG_INVALID_THREADID;
518 }
519 }
520
DRD_(get_mutex_lock_count)521 ULong DRD_(get_mutex_lock_count)(void)
522 {
523 return s_mutex_lock_count;
524 }
525
DRD_(get_mutex_segment_creation_count)526 ULong DRD_(get_mutex_segment_creation_count)(void)
527 {
528 return s_mutex_segment_creation_count;
529 }
530