1 /* 2 This file is part of drd, a thread error detector. 3 4 Copyright (C) 2006-2013 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->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(). */ 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. */ 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 */ 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* 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 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* 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(). */ 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 */ 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 */ 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 */ 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 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 448 const HChar* 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 455 const HChar* 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. */ 477 static Bool mutex_is_locked(struct mutex_info* const p) 478 { 479 tl_assert(p); 480 return (p->recursion_count > 0); 481 } 482 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 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 */ 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 521 ULong DRD_(get_mutex_lock_count)(void) 522 { 523 return s_mutex_lock_count; 524 } 525 526 ULong DRD_(get_mutex_segment_creation_count)(void) 527 { 528 return s_mutex_segment_creation_count; 529 } 530