drd/drd_pthread_intercepts: Add a workaround for what is probably a compiler bug
[valgrind.git] / drd / drd_mutex.c
blobbc33fbb43334759172a4243818c238107721db11
1 /*
2 This file is part of drd, a thread error detector.
4 Copyright (C) 2006-2017 Bart Van Assche <bvanassche@acm.org>.
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.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
19 The GNU General Public License is contained in the file COPYING.
23 #include "drd_basics.h"
24 #include "drd_clientobj.h"
25 #include "drd_error.h"
26 #include "drd_mutex.h"
27 #include "pub_tool_vki.h"
28 #include "pub_tool_errormgr.h" /* VG_(maybe_record_error)() */
29 #include "pub_tool_libcassert.h" /* tl_assert() */
30 #include "pub_tool_libcbase.h" /* VG_(strlen) */
31 #include "pub_tool_libcprint.h" /* VG_(message)() */
32 #include "pub_tool_libcproc.h" /* VG_(read_millisecond_timer)() */
33 #include "pub_tool_machine.h" /* VG_(get_IP)() */
34 #include "pub_tool_threadstate.h" /* VG_(get_running_tid)() */
37 /* Local functions. */
39 static void mutex_cleanup(struct mutex_info* p);
40 static Bool mutex_is_locked(struct mutex_info* const p);
41 static void mutex_delete_thread(struct mutex_info* p, const DrdThreadId tid);
44 /* Local variables. */
46 static Bool s_trace_mutex;
47 static ULong s_mutex_lock_count;
48 static ULong s_mutex_segment_creation_count;
49 static UInt s_mutex_lock_threshold_ms;
52 /* Function definitions. */
54 void DRD_(mutex_set_trace)(const Bool trace_mutex)
56 tl_assert((!! trace_mutex) == trace_mutex);
57 s_trace_mutex = trace_mutex;
60 void DRD_(mutex_set_lock_threshold)(const UInt lock_threshold_ms)
62 s_mutex_lock_threshold_ms = lock_threshold_ms;
65 static
66 void DRD_(mutex_initialize)(struct mutex_info* const p,
67 const Addr mutex, const MutexT mutex_type)
69 tl_assert(mutex);
70 tl_assert(p->a1 == mutex);
72 p->cleanup = (void(*)(DrdClientobj*))mutex_cleanup;
73 p->delete_thread
74 = (void(*)(DrdClientobj*, DrdThreadId))mutex_delete_thread;
75 p->mutex_type = mutex_type;
76 p->recursion_count = 0;
77 p->ignore_ordering = False;
78 p->owner = DRD_INVALID_THREADID;
79 p->last_locked_segment = 0;
80 p->acquiry_time_ms = 0;
81 p->acquired_at = 0;
84 void DRD_(mutex_ignore_ordering)(const Addr mutex)
86 struct mutex_info* p = DRD_(mutex_get)(mutex);
88 if (s_trace_mutex)
89 DRD_(trace_msg)("[%u] mutex_ignore_ordering %s 0x%lx",
90 DRD_(thread_get_running_tid)(),
91 p ? DRD_(mutex_type_name)(p->mutex_type) : "(?)",
92 mutex);
94 if (p) {
95 p->ignore_ordering = True;
96 } else {
97 DRD_(not_a_mutex)(mutex);
101 /** Deallocate the memory that was allocated by mutex_initialize(). */
102 static void mutex_cleanup(struct mutex_info* p)
104 tl_assert(p);
106 if (s_trace_mutex)
107 DRD_(trace_msg)("[%u] mutex_destroy %s 0x%lx rc %d owner %u",
108 DRD_(thread_get_running_tid)(),
109 DRD_(mutex_get_typename)(p), p->a1,
110 p ? p->recursion_count : -1,
111 p ? p->owner : DRD_INVALID_THREADID);
113 if (mutex_is_locked(p))
115 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
116 p->a1, p->recursion_count, p->owner };
117 VG_(maybe_record_error)(VG_(get_running_tid)(),
118 MutexErr,
119 VG_(get_IP)(VG_(get_running_tid)()),
120 "Destroying locked mutex",
121 &MEI);
124 DRD_(sg_put)(p->last_locked_segment);
125 p->last_locked_segment = 0;
128 /** Report that address 'mutex' is not the address of a mutex object. */
129 void DRD_(not_a_mutex)(const Addr mutex)
131 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
132 mutex, -1, DRD_INVALID_THREADID };
133 VG_(maybe_record_error)(VG_(get_running_tid)(),
134 MutexErr,
135 VG_(get_IP)(VG_(get_running_tid)()),
136 "Not a mutex",
137 &MEI);
141 * Report that address 'mutex' is not the address of a mutex object of the
142 * expected type.
144 static void wrong_mutex_type(const Addr mutex)
146 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
147 mutex, -1, DRD_INVALID_THREADID };
148 VG_(maybe_record_error)(VG_(get_running_tid)(),
149 MutexErr,
150 VG_(get_IP)(VG_(get_running_tid)()),
151 "Mutex type mismatch",
152 &MEI);
155 static
156 struct mutex_info*
157 DRD_(mutex_get_or_allocate)(const Addr mutex, const MutexT mutex_type)
159 struct mutex_info* p;
161 tl_assert(offsetof(DrdClientobj, mutex) == 0);
162 p = &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex);
163 if (p)
165 if (mutex_type == mutex_type_unknown || p->mutex_type == mutex_type)
166 return p;
167 else
169 wrong_mutex_type(mutex);
170 return 0;
174 if (DRD_(clientobj_present)(mutex, mutex + 1))
176 DRD_(not_a_mutex)(mutex);
177 return 0;
180 p = &(DRD_(clientobj_add)(mutex, ClientMutex)->mutex);
181 DRD_(mutex_initialize)(p, mutex, mutex_type);
182 return p;
185 struct mutex_info* DRD_(mutex_get)(const Addr mutex)
187 tl_assert(offsetof(DrdClientobj, mutex) == 0);
188 return &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex);
191 /** Called before pthread_mutex_init(). */
192 struct mutex_info*
193 DRD_(mutex_init)(const Addr mutex, const MutexT mutex_type)
195 struct mutex_info* p;
197 if (s_trace_mutex)
198 DRD_(trace_msg)("[%u] mutex_init %s 0x%lx",
199 DRD_(thread_get_running_tid)(),
200 DRD_(mutex_type_name)(mutex_type),
201 mutex);
203 if (mutex_type == mutex_type_invalid_mutex)
205 DRD_(not_a_mutex)(mutex);
206 return 0;
209 p = DRD_(mutex_get)(mutex);
210 if (p)
212 const ThreadId vg_tid = VG_(get_running_tid)();
213 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
214 p->a1, p->recursion_count, p->owner };
215 VG_(maybe_record_error)(vg_tid,
216 MutexErr,
217 VG_(get_IP)(vg_tid),
218 "Mutex reinitialization",
219 &MEI);
220 p->mutex_type = mutex_type;
221 return p;
223 p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
225 return p;
228 /** Called after pthread_mutex_destroy(). */
229 void DRD_(mutex_post_destroy)(const Addr mutex)
231 struct mutex_info* p;
233 p = DRD_(mutex_get)(mutex);
234 if (p == 0)
236 DRD_(not_a_mutex)(mutex);
237 return;
240 DRD_(clientobj_remove)(mutex, ClientMutex);
244 * Called before pthread_mutex_lock() is invoked. If a data structure for the
245 * client-side object was not yet created, do this now. Also check whether an
246 * attempt is made to lock recursively a synchronization object that must not
247 * be locked recursively.
249 void DRD_(mutex_pre_lock)(const Addr mutex, MutexT mutex_type,
250 const Bool trylock)
252 struct mutex_info* p;
254 p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
255 if (p && mutex_type == mutex_type_unknown)
256 mutex_type = p->mutex_type;
258 if (s_trace_mutex)
259 DRD_(trace_msg)("[%u] %s %s 0x%lx rc %d owner %u",
260 DRD_(thread_get_running_tid)(),
261 trylock ? "pre_mutex_lock " : "mutex_trylock ",
262 p ? DRD_(mutex_get_typename)(p) : "(?)",
263 mutex, p ? p->recursion_count : -1,
264 p ? p->owner : DRD_INVALID_THREADID);
266 if (p == 0)
268 DRD_(not_a_mutex)(mutex);
269 return;
272 tl_assert(p);
274 if (mutex_type == mutex_type_invalid_mutex)
276 DRD_(not_a_mutex)(mutex);
277 return;
280 if (! trylock
281 && p->owner == DRD_(thread_get_running_tid)()
282 && p->recursion_count >= 1
283 && mutex_type != mutex_type_recursive_mutex)
285 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
286 p->a1, p->recursion_count, p->owner };
287 VG_(maybe_record_error)(VG_(get_running_tid)(),
288 MutexErr,
289 VG_(get_IP)(VG_(get_running_tid)()),
290 "Recursive locking not allowed",
291 &MEI);
296 * Update mutex_info state when locking the pthread_mutex_t mutex.
297 * Note: this function must be called after pthread_mutex_lock() has been
298 * called, or a race condition is triggered !
300 void DRD_(mutex_post_lock)(const Addr mutex, const Bool took_lock,
301 const Bool post_cond_wait)
303 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
304 struct mutex_info* p;
306 p = DRD_(mutex_get)(mutex);
308 if (s_trace_mutex)
309 DRD_(trace_msg)("[%u] %s %s 0x%lx rc %d owner %u%s",
310 drd_tid,
311 post_cond_wait ? "cond_post_wait " : "post_mutex_lock",
312 p ? DRD_(mutex_get_typename)(p) : "(?)",
313 mutex, p ? p->recursion_count : 0,
314 p ? p->owner : VG_INVALID_THREADID,
315 took_lock ? "" : " (locking failed)");
317 if (! p || ! took_lock)
318 return;
320 if (p->recursion_count == 0) {
321 if (!p->ignore_ordering) {
322 if (p->owner != drd_tid && p->owner != DRD_INVALID_THREADID) {
323 tl_assert(p->last_locked_segment);
325 DRD_(thread_new_segment_and_combine_vc)(drd_tid,
326 p->last_locked_segment);
327 } else {
328 DRD_(thread_new_segment)(drd_tid);
331 s_mutex_segment_creation_count++;
334 p->owner = drd_tid;
335 p->acquiry_time_ms = VG_(read_millisecond_timer)();
336 p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
337 s_mutex_lock_count++;
338 } else if (p->owner != drd_tid) {
339 const ThreadId vg_tid = VG_(get_running_tid)();
340 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
341 p->a1, p->recursion_count, p->owner };
342 VG_(maybe_record_error)(vg_tid,
343 MutexErr,
344 VG_(get_IP)(vg_tid),
345 "The impossible happened: mutex is locked"
346 " simultaneously by two threads",
347 &MEI);
348 p->owner = drd_tid;
350 p->recursion_count++;
354 * Update mutex_info state when unlocking the pthread_mutex_t mutex.
356 * @param[in] mutex Address of the client mutex.
357 * @param[in] mutex_type Mutex type.
359 * @return New value of the mutex recursion count.
361 * @note This function must be called before pthread_mutex_unlock() is called,
362 * or a race condition is triggered !
364 void DRD_(mutex_unlock)(const Addr mutex, MutexT mutex_type)
366 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
367 const ThreadId vg_tid = VG_(get_running_tid)();
368 struct mutex_info* p;
370 p = DRD_(mutex_get)(mutex);
371 if (p && mutex_type == mutex_type_unknown)
372 mutex_type = p->mutex_type;
374 if (s_trace_mutex) {
375 DRD_(trace_msg)("[%u] mutex_unlock %s 0x%lx rc %d",
376 drd_tid, p ? DRD_(mutex_get_typename)(p) : "(?)",
377 mutex, p ? p->recursion_count : 0);
380 if (p == 0 || mutex_type == mutex_type_invalid_mutex)
382 DRD_(not_a_mutex)(mutex);
383 return;
386 if (p->owner == DRD_INVALID_THREADID)
388 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
389 p->a1, p->recursion_count, p->owner };
390 VG_(maybe_record_error)(vg_tid,
391 MutexErr,
392 VG_(get_IP)(vg_tid),
393 "Mutex not locked",
394 &MEI);
395 return;
398 tl_assert(p);
399 if (p->mutex_type != mutex_type) {
400 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
401 p->a1, p->recursion_count, p->owner };
402 VG_(maybe_record_error)(vg_tid, MutexErr, VG_(get_IP)(vg_tid),
403 "Mutex type changed", &MEI);
405 tl_assert(p->mutex_type == mutex_type);
406 tl_assert(p->owner != DRD_INVALID_THREADID);
408 if (p->owner != drd_tid || p->recursion_count <= 0)
410 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
411 p->a1, p->recursion_count, p->owner };
412 VG_(maybe_record_error)(vg_tid,
413 MutexErr,
414 VG_(get_IP)(vg_tid),
415 "Mutex not locked by calling thread",
416 &MEI);
417 return;
419 tl_assert(p->recursion_count > 0);
420 p->recursion_count--;
421 tl_assert(p->recursion_count >= 0);
423 if (p->recursion_count == 0)
425 if (s_mutex_lock_threshold_ms > 0)
427 Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
428 if (held > s_mutex_lock_threshold_ms)
430 HoldtimeErrInfo HEI
431 = { DRD_(thread_get_running_tid)(),
432 mutex, p->acquired_at, held, s_mutex_lock_threshold_ms };
433 VG_(maybe_record_error)(vg_tid,
434 HoldtimeErr,
435 VG_(get_IP)(vg_tid),
436 "mutex",
437 &HEI);
441 /* This pthread_mutex_unlock() call really unlocks the mutex. Save the */
442 /* current vector clock of the thread such that it is available when */
443 /* this mutex is locked again. */
445 DRD_(thread_get_latest_segment)(&p->last_locked_segment, drd_tid);
446 if (!p->ignore_ordering)
447 DRD_(thread_new_segment)(drd_tid);
448 p->acquired_at = 0;
449 s_mutex_segment_creation_count++;
453 void DRD_(spinlock_init_or_unlock)(const Addr spinlock)
455 struct mutex_info* mutex_p = DRD_(mutex_get)(spinlock);
456 if (mutex_p)
458 DRD_(mutex_unlock)(spinlock, mutex_type_spinlock);
460 else
462 DRD_(mutex_init)(spinlock, mutex_type_spinlock);
466 const HChar* DRD_(mutex_get_typename)(struct mutex_info* const p)
468 tl_assert(p);
470 return DRD_(mutex_type_name)(p->mutex_type);
473 const HChar* DRD_(mutex_type_name)(const MutexT mt)
475 switch (mt)
477 case mutex_type_unknown:
478 return "mutex";
479 case mutex_type_invalid_mutex:
480 return "invalid mutex";
481 case mutex_type_recursive_mutex:
482 return "recursive mutex";
483 case mutex_type_errorcheck_mutex:
484 return "error checking mutex";
485 case mutex_type_default_mutex:
486 return "mutex";
487 case mutex_type_spinlock:
488 return "spinlock";
489 case mutex_type_cxa_guard:
490 return "cxa_guard";
492 tl_assert(0);
493 return "?";
496 /** Return true if the specified mutex is locked by any thread. */
497 static Bool mutex_is_locked(struct mutex_info* const p)
499 tl_assert(p);
500 return (p->recursion_count > 0);
503 Bool DRD_(mutex_is_locked_by)(const Addr mutex, const DrdThreadId tid)
505 struct mutex_info* const p = DRD_(mutex_get)(mutex);
506 if (p)
508 return (p->recursion_count > 0 && p->owner == tid);
510 return False;
513 int DRD_(mutex_get_recursion_count)(const Addr mutex)
515 struct mutex_info* const p = DRD_(mutex_get)(mutex);
516 tl_assert(p);
517 return p->recursion_count;
521 * Call this function when thread tid stops to exist, such that the
522 * "last owner" field can be cleared if it still refers to that thread.
524 static void mutex_delete_thread(struct mutex_info* p, const DrdThreadId tid)
526 tl_assert(p);
528 if (p->owner == tid && p->recursion_count > 0)
530 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
531 p->a1, p->recursion_count, p->owner };
532 VG_(maybe_record_error)(VG_(get_running_tid)(),
533 MutexErr,
534 VG_(get_IP)(VG_(get_running_tid)()),
535 "Mutex still locked at thread exit",
536 &MEI);
537 p->owner = VG_INVALID_THREADID;
541 ULong DRD_(get_mutex_lock_count)(void)
543 return s_mutex_lock_count;
546 ULong DRD_(get_mutex_segment_creation_count)(void)
548 return s_mutex_segment_creation_count;