Home | History | Annotate | Download | only in drd
      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