2 This file is part of drd, a thread error detector.
4 Copyright (C) 2006-2020 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
;
66 void DRD_(mutex_initialize
)(struct mutex_info
* const p
,
67 const Addr mutex
, const MutexT mutex_type
)
70 tl_assert(p
->a1
== mutex
);
72 p
->cleanup
= (void(*)(DrdClientobj
*))mutex_cleanup
;
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;
84 void DRD_(mutex_ignore_ordering
)(const Addr mutex
)
86 struct mutex_info
* p
= DRD_(mutex_get
)(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
) : "(?)",
95 p
->ignore_ordering
= True
;
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
)
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
)(),
119 VG_(get_IP
)(VG_(get_running_tid
)()),
120 "Destroying locked mutex",
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
)(),
135 VG_(get_IP
)(VG_(get_running_tid
)()),
141 * Report that address 'mutex' is not the address of a mutex object of the
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
)(),
150 VG_(get_IP
)(VG_(get_running_tid
)()),
151 "Mutex type mismatch",
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
);
165 if (mutex_type
== mutex_type_unknown
|| p
->mutex_type
== mutex_type
)
169 wrong_mutex_type(mutex
);
174 if (DRD_(clientobj_present
)(mutex
, mutex
+ 1))
176 DRD_(not_a_mutex
)(mutex
);
180 p
= &(DRD_(clientobj_add
)(mutex
, ClientMutex
)->mutex
);
181 DRD_(mutex_initialize
)(p
, mutex
, mutex_type
);
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(). */
193 DRD_(mutex_init
)(const Addr mutex
, const MutexT mutex_type
)
195 struct mutex_info
* p
;
198 DRD_(trace_msg
)("[%u] mutex_init %s 0x%lx",
199 DRD_(thread_get_running_tid
)(),
200 DRD_(mutex_type_name
)(mutex_type
),
203 if (mutex_type
== mutex_type_invalid_mutex
)
205 DRD_(not_a_mutex
)(mutex
);
209 p
= DRD_(mutex_get
)(mutex
);
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
,
218 "Mutex reinitialization",
220 p
->mutex_type
= mutex_type
;
223 p
= DRD_(mutex_get_or_allocate
)(mutex
, mutex_type
);
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
);
236 DRD_(not_a_mutex
)(mutex
);
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
,
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
;
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
);
268 DRD_(not_a_mutex
)(mutex
);
274 if (mutex_type
== mutex_type_invalid_mutex
)
276 DRD_(not_a_mutex
)(mutex
);
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
)(),
289 VG_(get_IP
)(VG_(get_running_tid
)()),
290 "Recursive locking not allowed",
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
);
309 DRD_(trace_msg
)("[%u] %s %s 0x%lx rc %d owner %u%s",
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
)
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
);
328 DRD_(thread_new_segment
)(drd_tid
);
331 s_mutex_segment_creation_count
++;
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
,
345 "The impossible happened: mutex is locked"
346 " simultaneously by two threads",
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
;
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
);
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
,
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
,
415 "Mutex not locked by calling thread",
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
)
431 = { DRD_(thread_get_running_tid
)(),
432 mutex
, p
->acquired_at
, held
, s_mutex_lock_threshold_ms
};
433 VG_(maybe_record_error
)(vg_tid
,
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
);
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
);
458 DRD_(mutex_unlock
)(spinlock
, mutex_type_spinlock
);
462 DRD_(mutex_init
)(spinlock
, mutex_type_spinlock
);
466 const HChar
* DRD_(mutex_get_typename
)(struct mutex_info
* const p
)
470 return DRD_(mutex_type_name
)(p
->mutex_type
);
473 const HChar
* DRD_(mutex_type_name
)(const MutexT mt
)
477 case mutex_type_unknown
:
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
:
487 case mutex_type_spinlock
:
489 case mutex_type_cxa_guard
:
496 /** Return true if the specified mutex is locked by any thread. */
497 static Bool
mutex_is_locked(struct mutex_info
* const 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
);
508 return (p
->recursion_count
> 0 && p
->owner
== tid
);
513 int DRD_(mutex_get_recursion_count
)(const Addr mutex
)
515 struct mutex_info
* const p
= DRD_(mutex_get
)(mutex
);
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
)
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
)(),
534 VG_(get_IP
)(VG_(get_running_tid
)()),
535 "Mutex still locked at thread exit",
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
;