1 /* 2 This file is part of drd, a thread error detector. 3 4 Copyright (C) 2006-2015 Bart Van Assche <bvanassche (at) 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 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 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 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->ignore_ordering = False; 80 p->owner = DRD_INVALID_THREADID; 81 p->last_locked_segment = 0; 82 p->acquiry_time_ms = 0; 83 p->acquired_at = 0; 84 } 85 86 void DRD_(mutex_ignore_ordering)(const Addr mutex) 87 { 88 struct mutex_info* p = DRD_(mutex_get)(mutex); 89 90 if (s_trace_mutex) 91 DRD_(trace_msg)("[%u] mutex_ignore_ordering %s 0x%lx", 92 DRD_(thread_get_running_tid)(), 93 p ? DRD_(mutex_type_name)(p->mutex_type) : "(?)", 94 mutex); 95 96 if (p) { 97 p->ignore_ordering = True; 98 } else { 99 DRD_(not_a_mutex)(mutex); 100 } 101 } 102 103 /** Deallocate the memory that was allocated by mutex_initialize(). */ 104 static void mutex_cleanup(struct mutex_info* p) 105 { 106 tl_assert(p); 107 108 if (s_trace_mutex) 109 DRD_(trace_msg)("[%u] mutex_destroy %s 0x%lx rc %d owner %u", 110 DRD_(thread_get_running_tid)(), 111 DRD_(mutex_get_typename)(p), p->a1, 112 p ? p->recursion_count : -1, 113 p ? p->owner : DRD_INVALID_THREADID); 114 115 if (mutex_is_locked(p)) 116 { 117 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(), 118 p->a1, p->recursion_count, p->owner }; 119 VG_(maybe_record_error)(VG_(get_running_tid)(), 120 MutexErr, 121 VG_(get_IP)(VG_(get_running_tid)()), 122 "Destroying locked mutex", 123 &MEI); 124 } 125 126 DRD_(sg_put)(p->last_locked_segment); 127 p->last_locked_segment = 0; 128 } 129 130 /** Report that address 'mutex' is not the address of a mutex object. */ 131 void DRD_(not_a_mutex)(const Addr mutex) 132 { 133 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(), 134 mutex, -1, DRD_INVALID_THREADID }; 135 VG_(maybe_record_error)(VG_(get_running_tid)(), 136 MutexErr, 137 VG_(get_IP)(VG_(get_running_tid)()), 138 "Not a mutex", 139 &MEI); 140 } 141 142 /** 143 * Report that address 'mutex' is not the address of a mutex object of the 144 * expected type. 145 */ 146 static void wrong_mutex_type(const Addr mutex) 147 { 148 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(), 149 mutex, -1, DRD_INVALID_THREADID }; 150 VG_(maybe_record_error)(VG_(get_running_tid)(), 151 MutexErr, 152 VG_(get_IP)(VG_(get_running_tid)()), 153 "Mutex type mismatch", 154 &MEI); 155 } 156 157 static 158 struct mutex_info* 159 DRD_(mutex_get_or_allocate)(const Addr mutex, const MutexT mutex_type) 160 { 161 struct mutex_info* p; 162 163 tl_assert(offsetof(DrdClientobj, mutex) == 0); 164 p = &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex); 165 if (p) 166 { 167 if (mutex_type == mutex_type_unknown || p->mutex_type == mutex_type) 168 return p; 169 else 170 { 171 wrong_mutex_type(mutex); 172 return 0; 173 } 174 } 175 176 if (DRD_(clientobj_present)(mutex, mutex + 1)) 177 { 178 DRD_(not_a_mutex)(mutex); 179 return 0; 180 } 181 182 p = &(DRD_(clientobj_add)(mutex, ClientMutex)->mutex); 183 DRD_(mutex_initialize)(p, mutex, mutex_type); 184 return p; 185 } 186 187 struct mutex_info* DRD_(mutex_get)(const Addr mutex) 188 { 189 tl_assert(offsetof(DrdClientobj, mutex) == 0); 190 return &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex); 191 } 192 193 /** Called before pthread_mutex_init(). */ 194 struct mutex_info* 195 DRD_(mutex_init)(const Addr mutex, const MutexT mutex_type) 196 { 197 struct mutex_info* p; 198 199 if (s_trace_mutex) 200 DRD_(trace_msg)("[%u] mutex_init %s 0x%lx", 201 DRD_(thread_get_running_tid)(), 202 DRD_(mutex_type_name)(mutex_type), 203 mutex); 204 205 if (mutex_type == mutex_type_invalid_mutex) 206 { 207 DRD_(not_a_mutex)(mutex); 208 return 0; 209 } 210 211 p = DRD_(mutex_get)(mutex); 212 if (p) 213 { 214 const ThreadId vg_tid = VG_(get_running_tid)(); 215 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(), 216 p->a1, p->recursion_count, p->owner }; 217 VG_(maybe_record_error)(vg_tid, 218 MutexErr, 219 VG_(get_IP)(vg_tid), 220 "Mutex reinitialization", 221 &MEI); 222 p->mutex_type = mutex_type; 223 return p; 224 } 225 p = DRD_(mutex_get_or_allocate)(mutex, mutex_type); 226 227 return p; 228 } 229 230 /** Called after pthread_mutex_destroy(). */ 231 void DRD_(mutex_post_destroy)(const Addr mutex) 232 { 233 struct mutex_info* p; 234 235 p = DRD_(mutex_get)(mutex); 236 if (p == 0) 237 { 238 DRD_(not_a_mutex)(mutex); 239 return; 240 } 241 242 DRD_(clientobj_remove)(mutex, ClientMutex); 243 } 244 245 /** 246 * Called before pthread_mutex_lock() is invoked. If a data structure for the 247 * client-side object was not yet created, do this now. Also check whether an 248 * attempt is made to lock recursively a synchronization object that must not 249 * be locked recursively. 250 */ 251 void DRD_(mutex_pre_lock)(const Addr mutex, MutexT mutex_type, 252 const Bool trylock) 253 { 254 struct mutex_info* p; 255 256 p = DRD_(mutex_get_or_allocate)(mutex, mutex_type); 257 if (p && mutex_type == mutex_type_unknown) 258 mutex_type = p->mutex_type; 259 260 if (s_trace_mutex) 261 DRD_(trace_msg)("[%u] %s %s 0x%lx rc %d owner %u", 262 DRD_(thread_get_running_tid)(), 263 trylock ? "pre_mutex_lock " : "mutex_trylock ", 264 p ? DRD_(mutex_get_typename)(p) : "(?)", 265 mutex, p ? p->recursion_count : -1, 266 p ? p->owner : DRD_INVALID_THREADID); 267 268 if (p == 0) 269 { 270 DRD_(not_a_mutex)(mutex); 271 return; 272 } 273 274 tl_assert(p); 275 276 if (mutex_type == mutex_type_invalid_mutex) 277 { 278 DRD_(not_a_mutex)(mutex); 279 return; 280 } 281 282 if (! trylock 283 && p->owner == DRD_(thread_get_running_tid)() 284 && p->recursion_count >= 1 285 && mutex_type != mutex_type_recursive_mutex) 286 { 287 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(), 288 p->a1, p->recursion_count, p->owner }; 289 VG_(maybe_record_error)(VG_(get_running_tid)(), 290 MutexErr, 291 VG_(get_IP)(VG_(get_running_tid)()), 292 "Recursive locking not allowed", 293 &MEI); 294 } 295 } 296 297 /** 298 * Update mutex_info state when locking the pthread_mutex_t mutex. 299 * Note: this function must be called after pthread_mutex_lock() has been 300 * called, or a race condition is triggered ! 301 */ 302 void DRD_(mutex_post_lock)(const Addr mutex, const Bool took_lock, 303 const Bool post_cond_wait) 304 { 305 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)(); 306 struct mutex_info* p; 307 308 p = DRD_(mutex_get)(mutex); 309 310 if (s_trace_mutex) 311 DRD_(trace_msg)("[%u] %s %s 0x%lx rc %d owner %u%s", 312 drd_tid, 313 post_cond_wait ? "cond_post_wait " : "post_mutex_lock", 314 p ? DRD_(mutex_get_typename)(p) : "(?)", 315 mutex, p ? p->recursion_count : 0, 316 p ? p->owner : VG_INVALID_THREADID, 317 took_lock ? "" : " (locking failed)"); 318 319 if (! p || ! took_lock) 320 return; 321 322 if (p->recursion_count == 0) { 323 if (!p->ignore_ordering) { 324 if (p->owner != drd_tid && p->owner != DRD_INVALID_THREADID) { 325 tl_assert(p->last_locked_segment); 326 327 DRD_(thread_new_segment_and_combine_vc)(drd_tid, 328 p->last_locked_segment); 329 } else { 330 DRD_(thread_new_segment)(drd_tid); 331 } 332 333 s_mutex_segment_creation_count++; 334 } 335 336 p->owner = drd_tid; 337 p->acquiry_time_ms = VG_(read_millisecond_timer)(); 338 p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0); 339 s_mutex_lock_count++; 340 } else if (p->owner != drd_tid) { 341 const ThreadId vg_tid = VG_(get_running_tid)(); 342 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(), 343 p->a1, p->recursion_count, p->owner }; 344 VG_(maybe_record_error)(vg_tid, 345 MutexErr, 346 VG_(get_IP)(vg_tid), 347 "The impossible happened: mutex is locked" 348 " simultaneously by two threads", 349 &MEI); 350 p->owner = drd_tid; 351 } 352 p->recursion_count++; 353 } 354 355 /** 356 * Update mutex_info state when unlocking the pthread_mutex_t mutex. 357 * 358 * @param[in] mutex Address of the client mutex. 359 * @param[in] mutex_type Mutex type. 360 * 361 * @return New value of the mutex recursion count. 362 * 363 * @note This function must be called before pthread_mutex_unlock() is called, 364 * or a race condition is triggered ! 365 */ 366 void DRD_(mutex_unlock)(const Addr mutex, MutexT mutex_type) 367 { 368 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)(); 369 const ThreadId vg_tid = VG_(get_running_tid)(); 370 struct mutex_info* p; 371 372 p = DRD_(mutex_get)(mutex); 373 if (p && mutex_type == mutex_type_unknown) 374 mutex_type = p->mutex_type; 375 376 if (s_trace_mutex) { 377 DRD_(trace_msg)("[%u] mutex_unlock %s 0x%lx rc %d", 378 drd_tid, p ? DRD_(mutex_get_typename)(p) : "(?)", 379 mutex, p ? p->recursion_count : 0); 380 } 381 382 if (p == 0 || mutex_type == mutex_type_invalid_mutex) 383 { 384 DRD_(not_a_mutex)(mutex); 385 return; 386 } 387 388 if (p->owner == DRD_INVALID_THREADID) 389 { 390 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(), 391 p->a1, p->recursion_count, p->owner }; 392 VG_(maybe_record_error)(vg_tid, 393 MutexErr, 394 VG_(get_IP)(vg_tid), 395 "Mutex not locked", 396 &MEI); 397 return; 398 } 399 400 tl_assert(p); 401 if (p->mutex_type != mutex_type) { 402 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(), 403 p->a1, p->recursion_count, p->owner }; 404 VG_(maybe_record_error)(vg_tid, MutexErr, VG_(get_IP)(vg_tid), 405 "Mutex type changed", &MEI); 406 } 407 tl_assert(p->mutex_type == mutex_type); 408 tl_assert(p->owner != DRD_INVALID_THREADID); 409 410 if (p->owner != drd_tid || p->recursion_count <= 0) 411 { 412 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(), 413 p->a1, p->recursion_count, p->owner }; 414 VG_(maybe_record_error)(vg_tid, 415 MutexErr, 416 VG_(get_IP)(vg_tid), 417 "Mutex not locked by calling thread", 418 &MEI); 419 return; 420 } 421 tl_assert(p->recursion_count > 0); 422 p->recursion_count--; 423 tl_assert(p->recursion_count >= 0); 424 425 if (p->recursion_count == 0) 426 { 427 if (s_mutex_lock_threshold_ms > 0) 428 { 429 Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms; 430 if (held > s_mutex_lock_threshold_ms) 431 { 432 HoldtimeErrInfo HEI 433 = { DRD_(thread_get_running_tid)(), 434 mutex, p->acquired_at, held, s_mutex_lock_threshold_ms }; 435 VG_(maybe_record_error)(vg_tid, 436 HoldtimeErr, 437 VG_(get_IP)(vg_tid), 438 "mutex", 439 &HEI); 440 } 441 } 442 443 /* This pthread_mutex_unlock() call really unlocks the mutex. Save the */ 444 /* current vector clock of the thread such that it is available when */ 445 /* this mutex is locked again. */ 446 447 DRD_(thread_get_latest_segment)(&p->last_locked_segment, drd_tid); 448 if (!p->ignore_ordering) 449 DRD_(thread_new_segment)(drd_tid); 450 p->acquired_at = 0; 451 s_mutex_segment_creation_count++; 452 } 453 } 454 455 void DRD_(spinlock_init_or_unlock)(const Addr spinlock) 456 { 457 struct mutex_info* mutex_p = DRD_(mutex_get)(spinlock); 458 if (mutex_p) 459 { 460 DRD_(mutex_unlock)(spinlock, mutex_type_spinlock); 461 } 462 else 463 { 464 DRD_(mutex_init)(spinlock, mutex_type_spinlock); 465 } 466 } 467 468 const HChar* DRD_(mutex_get_typename)(struct mutex_info* const p) 469 { 470 tl_assert(p); 471 472 return DRD_(mutex_type_name)(p->mutex_type); 473 } 474 475 const HChar* DRD_(mutex_type_name)(const MutexT mt) 476 { 477 switch (mt) 478 { 479 case mutex_type_unknown: 480 return "mutex"; 481 case mutex_type_invalid_mutex: 482 return "invalid mutex"; 483 case mutex_type_recursive_mutex: 484 return "recursive mutex"; 485 case mutex_type_errorcheck_mutex: 486 return "error checking mutex"; 487 case mutex_type_default_mutex: 488 return "mutex"; 489 case mutex_type_spinlock: 490 return "spinlock"; 491 case mutex_type_cxa_guard: 492 return "cxa_guard"; 493 } 494 tl_assert(0); 495 return "?"; 496 } 497 498 /** Return true if the specified mutex is locked by any thread. */ 499 static Bool mutex_is_locked(struct mutex_info* const p) 500 { 501 tl_assert(p); 502 return (p->recursion_count > 0); 503 } 504 505 Bool DRD_(mutex_is_locked_by)(const Addr mutex, const DrdThreadId tid) 506 { 507 struct mutex_info* const p = DRD_(mutex_get)(mutex); 508 if (p) 509 { 510 return (p->recursion_count > 0 && p->owner == tid); 511 } 512 return False; 513 } 514 515 int DRD_(mutex_get_recursion_count)(const Addr mutex) 516 { 517 struct mutex_info* const p = DRD_(mutex_get)(mutex); 518 tl_assert(p); 519 return p->recursion_count; 520 } 521 522 /** 523 * Call this function when thread tid stops to exist, such that the 524 * "last owner" field can be cleared if it still refers to that thread. 525 */ 526 static void mutex_delete_thread(struct mutex_info* p, const DrdThreadId tid) 527 { 528 tl_assert(p); 529 530 if (p->owner == tid && p->recursion_count > 0) 531 { 532 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(), 533 p->a1, p->recursion_count, p->owner }; 534 VG_(maybe_record_error)(VG_(get_running_tid)(), 535 MutexErr, 536 VG_(get_IP)(VG_(get_running_tid)()), 537 "Mutex still locked at thread exit", 538 &MEI); 539 p->owner = VG_INVALID_THREADID; 540 } 541 } 542 543 ULong DRD_(get_mutex_lock_count)(void) 544 { 545 return s_mutex_lock_count; 546 } 547 548 ULong DRD_(get_mutex_segment_creation_count)(void) 549 { 550 return s_mutex_segment_creation_count; 551 } 552