Home | History | Annotate | Download | only in drd
      1 /* -*- mode: C; c-basic-offset: 3; indent-tabs-mode: nil; -*- */
      2 /*
      3   This file is part of drd, a thread error detector.
      4 
      5   Copyright (C) 2006-2011 Bart Van Assche <bvanassche (at) acm.org>.
      6 
      7   This program is free software; you can redistribute it and/or
      8   modify it under the terms of the GNU General Public License as
      9   published by the Free Software Foundation; either version 2 of the
     10   License, or (at your option) any later version.
     11 
     12   This program is distributed in the hope that it will be useful, but
     13   WITHOUT ANY WARRANTY; without even the implied warranty of
     14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15   General Public License for more details.
     16 
     17   You should have received a copy of the GNU General Public License
     18   along with this program; if not, write to the Free Software
     19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     20   02111-1307, USA.
     21 
     22   The GNU General Public License is contained in the file COPYING.
     23 */
     24 
     25 
     26 #include "drd_basics.h"
     27 #include "drd_clientobj.h"
     28 #include "drd_error.h"
     29 #include "drd_mutex.h"
     30 #include "pub_tool_vki.h"
     31 #include "pub_tool_errormgr.h"    /* VG_(maybe_record_error)()     */
     32 #include "pub_tool_libcassert.h"  /* tl_assert()                   */
     33 #include "pub_tool_libcbase.h"    /* VG_(strlen)                   */
     34 #include "pub_tool_libcprint.h"   /* VG_(message)()                */
     35 #include "pub_tool_libcproc.h"    /* VG_(read_millisecond_timer)() */
     36 #include "pub_tool_machine.h"     /* VG_(get_IP)()                 */
     37 #include "pub_tool_threadstate.h" /* VG_(get_running_tid)()        */
     38 
     39 
     40 /* Local functions. */
     41 
     42 static void mutex_cleanup(struct mutex_info* p);
     43 static Bool mutex_is_locked(struct mutex_info* const p);
     44 static void mutex_delete_thread(struct mutex_info* p, const DrdThreadId tid);
     45 
     46 
     47 /* Local variables. */
     48 
     49 static Bool s_trace_mutex;
     50 static ULong s_mutex_lock_count;
     51 static ULong s_mutex_segment_creation_count;
     52 static UInt s_mutex_lock_threshold_ms;
     53 
     54 
     55 /* Function definitions. */
     56 
     57 void DRD_(mutex_set_trace)(const Bool trace_mutex)
     58 {
     59    tl_assert(!! trace_mutex == trace_mutex);
     60    s_trace_mutex = trace_mutex;
     61 }
     62 
     63 void DRD_(mutex_set_lock_threshold)(const UInt lock_threshold_ms)
     64 {
     65    s_mutex_lock_threshold_ms = lock_threshold_ms;
     66 }
     67 
     68 static
     69 void DRD_(mutex_initialize)(struct mutex_info* const p,
     70                             const Addr mutex, const MutexT mutex_type)
     71 {
     72    tl_assert(mutex);
     73    tl_assert(p->a1 == mutex);
     74 
     75    p->cleanup             = (void(*)(DrdClientobj*))mutex_cleanup;
     76    p->delete_thread
     77       = (void(*)(DrdClientobj*, DrdThreadId))mutex_delete_thread;
     78    p->mutex_type          = mutex_type;
     79    p->recursion_count     = 0;
     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 /** Deallocate the memory that was allocated by mutex_initialize(). */
     87 static void mutex_cleanup(struct mutex_info* p)
     88 {
     89    tl_assert(p);
     90 
     91    if (s_trace_mutex)
     92       DRD_(trace_msg)("[%d] mutex_destroy   %s 0x%lx rc %d owner %d",
     93                       DRD_(thread_get_running_tid)(),
     94                       DRD_(mutex_get_typename)(p), p->a1,
     95                       p ? p->recursion_count : -1,
     96                       p ? p->owner : DRD_INVALID_THREADID);
     97 
     98    if (mutex_is_locked(p))
     99    {
    100       MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
    101                            p->a1, p->recursion_count, p->owner };
    102       VG_(maybe_record_error)(VG_(get_running_tid)(),
    103                               MutexErr,
    104                               VG_(get_IP)(VG_(get_running_tid)()),
    105                               "Destroying locked mutex",
    106                               &MEI);
    107    }
    108 
    109    DRD_(sg_put)(p->last_locked_segment);
    110    p->last_locked_segment = 0;
    111 }
    112 
    113 /** Report that address 'mutex' is not the address of a mutex object. */
    114 void DRD_(not_a_mutex)(const Addr mutex)
    115 {
    116    MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
    117                         mutex, -1, DRD_INVALID_THREADID };
    118    VG_(maybe_record_error)(VG_(get_running_tid)(),
    119                            MutexErr,
    120                            VG_(get_IP)(VG_(get_running_tid)()),
    121                            "Not a mutex",
    122                            &MEI);
    123 }
    124 
    125 /**
    126  * Report that address 'mutex' is not the address of a mutex object of the
    127  * expected type.
    128  */
    129 static void wrong_mutex_type(const Addr mutex)
    130 {
    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                            "Mutex type mismatch",
    137                            &MEI);
    138 }
    139 
    140 static
    141 struct mutex_info*
    142 DRD_(mutex_get_or_allocate)(const Addr mutex, const MutexT mutex_type)
    143 {
    144    struct mutex_info* p;
    145 
    146    tl_assert(offsetof(DrdClientobj, mutex) == 0);
    147    p = &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex);
    148    if (p)
    149    {
    150       if (mutex_type == mutex_type_unknown || p->mutex_type == mutex_type)
    151 	 return p;
    152       else
    153       {
    154 	 wrong_mutex_type(mutex);
    155 	 return 0;
    156       }
    157    }
    158 
    159    if (DRD_(clientobj_present)(mutex, mutex + 1))
    160    {
    161       DRD_(not_a_mutex)(mutex);
    162       return 0;
    163    }
    164 
    165    p = &(DRD_(clientobj_add)(mutex, ClientMutex)->mutex);
    166    DRD_(mutex_initialize)(p, mutex, mutex_type);
    167    return p;
    168 }
    169 
    170 struct mutex_info* DRD_(mutex_get)(const Addr mutex)
    171 {
    172    tl_assert(offsetof(DrdClientobj, mutex) == 0);
    173    return &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex);
    174 }
    175 
    176 /** Called before pthread_mutex_init(). */
    177 struct mutex_info*
    178 DRD_(mutex_init)(const Addr mutex, const MutexT mutex_type)
    179 {
    180    struct mutex_info* p;
    181 
    182    if (s_trace_mutex)
    183       DRD_(trace_msg)("[%d] mutex_init      %s 0x%lx",
    184                       DRD_(thread_get_running_tid)(),
    185                       DRD_(mutex_type_name)(mutex_type),
    186                       mutex);
    187 
    188    if (mutex_type == mutex_type_invalid_mutex)
    189    {
    190       DRD_(not_a_mutex)(mutex);
    191       return 0;
    192    }
    193 
    194    p = DRD_(mutex_get)(mutex);
    195    if (p)
    196    {
    197       const ThreadId vg_tid = VG_(get_running_tid)();
    198       MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
    199                            p->a1, p->recursion_count, p->owner };
    200       VG_(maybe_record_error)(vg_tid,
    201                               MutexErr,
    202                               VG_(get_IP)(vg_tid),
    203                               "Mutex reinitialization",
    204                               &MEI);
    205       p->mutex_type = mutex_type;
    206       return p;
    207    }
    208    p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
    209 
    210    return p;
    211 }
    212 
    213 /** Called after pthread_mutex_destroy(). */
    214 void DRD_(mutex_post_destroy)(const Addr mutex)
    215 {
    216    struct mutex_info* p;
    217 
    218    p = DRD_(mutex_get)(mutex);
    219    if (p == 0)
    220    {
    221       DRD_(not_a_mutex)(mutex);
    222       return;
    223    }
    224 
    225    DRD_(clientobj_remove)(mutex, ClientMutex);
    226 }
    227 
    228 /**
    229  * Called before pthread_mutex_lock() is invoked. If a data structure for the
    230  * client-side object was not yet created, do this now. Also check whether an
    231  * attempt is made to lock recursively a synchronization object that must not
    232  * be locked recursively.
    233  */
    234 void DRD_(mutex_pre_lock)(const Addr mutex, MutexT mutex_type,
    235                           const Bool trylock)
    236 {
    237    struct mutex_info* p;
    238 
    239    p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
    240    if (p && mutex_type == mutex_type_unknown)
    241       mutex_type = p->mutex_type;
    242 
    243    if (s_trace_mutex)
    244       DRD_(trace_msg)("[%d] %s %s 0x%lx rc %d owner %d",
    245                       DRD_(thread_get_running_tid)(),
    246                       trylock ? "pre_mutex_lock " : "mutex_trylock  ",
    247                       p ? DRD_(mutex_get_typename)(p) : "(?)",
    248                       mutex, p ? p->recursion_count : -1,
    249                       p ? p->owner : DRD_INVALID_THREADID);
    250 
    251    if (p == 0)
    252    {
    253       DRD_(not_a_mutex)(mutex);
    254       return;
    255    }
    256 
    257    tl_assert(p);
    258 
    259    if (mutex_type == mutex_type_invalid_mutex)
    260    {
    261       DRD_(not_a_mutex)(mutex);
    262       return;
    263    }
    264 
    265    if (! trylock
    266        && p->owner == DRD_(thread_get_running_tid)()
    267        && p->recursion_count >= 1
    268        && mutex_type != mutex_type_recursive_mutex)
    269    {
    270       MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
    271                            p->a1, p->recursion_count, p->owner };
    272       VG_(maybe_record_error)(VG_(get_running_tid)(),
    273                               MutexErr,
    274                               VG_(get_IP)(VG_(get_running_tid)()),
    275                               "Recursive locking not allowed",
    276                               &MEI);
    277    }
    278 }
    279 
    280 /**
    281  * Update mutex_info state when locking the pthread_mutex_t mutex.
    282  * Note: this function must be called after pthread_mutex_lock() has been
    283  * called, or a race condition is triggered !
    284  */
    285 void DRD_(mutex_post_lock)(const Addr mutex, const Bool took_lock,
    286                            const Bool post_cond_wait)
    287 {
    288    const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
    289    struct mutex_info* p;
    290 
    291    p = DRD_(mutex_get)(mutex);
    292 
    293    if (s_trace_mutex)
    294       DRD_(trace_msg)("[%d] %s %s 0x%lx rc %d owner %d%s",
    295                       drd_tid,
    296                       post_cond_wait ? "cond_post_wait " : "post_mutex_lock",
    297                       p ? DRD_(mutex_get_typename)(p) : "(?)",
    298                       mutex, p ? p->recursion_count : 0,
    299                       p ? p->owner : VG_INVALID_THREADID,
    300                       took_lock ? "" : " (locking failed)");
    301 
    302    if (! p || ! took_lock)
    303       return;
    304 
    305    if (p->recursion_count == 0) {
    306       if (p->owner != drd_tid && p->owner != DRD_INVALID_THREADID)
    307       {
    308          tl_assert(p->last_locked_segment);
    309 
    310          DRD_(thread_new_segment_and_combine_vc)(drd_tid,
    311                                                  p->last_locked_segment);
    312       }
    313       else
    314          DRD_(thread_new_segment)(drd_tid);
    315 
    316       s_mutex_segment_creation_count++;
    317 
    318       p->owner           = drd_tid;
    319       p->acquiry_time_ms = VG_(read_millisecond_timer)();
    320       p->acquired_at     = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
    321       s_mutex_lock_count++;
    322    } else if (p->owner != drd_tid) {
    323       const ThreadId vg_tid = VG_(get_running_tid)();
    324       MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
    325                            p->a1, p->recursion_count, p->owner };
    326       VG_(maybe_record_error)(vg_tid,
    327                               MutexErr,
    328                               VG_(get_IP)(vg_tid),
    329                               "The impossible happened: mutex is locked"
    330                               " simultaneously by two threads",
    331                               &MEI);
    332       p->owner = drd_tid;
    333    }
    334    p->recursion_count++;
    335 }
    336 
    337 /**
    338  * Update mutex_info state when unlocking the pthread_mutex_t mutex.
    339  *
    340  * @param[in] mutex      Address of the client mutex.
    341  * @param[in] mutex_type Mutex type.
    342  *
    343  * @return New value of the mutex recursion count.
    344  *
    345  * @note This function must be called before pthread_mutex_unlock() is called,
    346  *       or a race condition is triggered !
    347  */
    348 void DRD_(mutex_unlock)(const Addr mutex, MutexT mutex_type)
    349 {
    350    const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
    351    const ThreadId vg_tid = VG_(get_running_tid)();
    352    struct mutex_info* p;
    353 
    354    p = DRD_(mutex_get)(mutex);
    355    if (p && mutex_type == mutex_type_unknown)
    356       mutex_type = p->mutex_type;
    357 
    358    if (s_trace_mutex) {
    359       DRD_(trace_msg)("[%d] mutex_unlock    %s 0x%lx rc %d",
    360                       drd_tid, p ? DRD_(mutex_get_typename)(p) : "(?)",
    361                       mutex, p ? p->recursion_count : 0);
    362    }
    363 
    364    if (p == 0 || mutex_type == mutex_type_invalid_mutex)
    365    {
    366       DRD_(not_a_mutex)(mutex);
    367       return;
    368    }
    369 
    370    if (p->owner == DRD_INVALID_THREADID)
    371    {
    372       MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
    373                            p->a1, p->recursion_count, p->owner };
    374       VG_(maybe_record_error)(vg_tid,
    375                               MutexErr,
    376                               VG_(get_IP)(vg_tid),
    377                               "Mutex not locked",
    378                               &MEI);
    379       return;
    380    }
    381 
    382    tl_assert(p);
    383    if (p->mutex_type != mutex_type) {
    384       MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
    385                            p->a1, p->recursion_count, p->owner };
    386       VG_(maybe_record_error)(vg_tid, MutexErr, VG_(get_IP)(vg_tid),
    387                               "Mutex type changed", &MEI);
    388    }
    389    tl_assert(p->mutex_type == mutex_type);
    390    tl_assert(p->owner != DRD_INVALID_THREADID);
    391 
    392    if (p->owner != drd_tid || p->recursion_count <= 0)
    393    {
    394       MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
    395                            p->a1, p->recursion_count, p->owner };
    396       VG_(maybe_record_error)(vg_tid,
    397                               MutexErr,
    398                               VG_(get_IP)(vg_tid),
    399                               "Mutex not locked by calling thread",
    400                               &MEI);
    401       return;
    402    }
    403    tl_assert(p->recursion_count > 0);
    404    p->recursion_count--;
    405    tl_assert(p->recursion_count >= 0);
    406 
    407    if (p->recursion_count == 0)
    408    {
    409       if (s_mutex_lock_threshold_ms > 0)
    410       {
    411          Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
    412          if (held > s_mutex_lock_threshold_ms)
    413          {
    414             HoldtimeErrInfo HEI
    415                = { DRD_(thread_get_running_tid)(),
    416                    mutex, p->acquired_at, held, s_mutex_lock_threshold_ms };
    417             VG_(maybe_record_error)(vg_tid,
    418                                     HoldtimeErr,
    419                                     VG_(get_IP)(vg_tid),
    420                                     "mutex",
    421                                     &HEI);
    422          }
    423       }
    424 
    425       /* This pthread_mutex_unlock() call really unlocks the mutex. Save the */
    426       /* current vector clock of the thread such that it is available when  */
    427       /* this mutex is locked again.                                        */
    428 
    429       DRD_(thread_get_latest_segment)(&p->last_locked_segment, drd_tid);
    430       DRD_(thread_new_segment)(drd_tid);
    431       p->acquired_at = 0;
    432       s_mutex_segment_creation_count++;
    433    }
    434 }
    435 
    436 void DRD_(spinlock_init_or_unlock)(const Addr spinlock)
    437 {
    438    struct mutex_info* mutex_p = DRD_(mutex_get)(spinlock);
    439    if (mutex_p)
    440    {
    441       DRD_(mutex_unlock)(spinlock, mutex_type_spinlock);
    442    }
    443    else
    444    {
    445       DRD_(mutex_init)(spinlock, mutex_type_spinlock);
    446    }
    447 }
    448 
    449 const char* DRD_(mutex_get_typename)(struct mutex_info* const p)
    450 {
    451    tl_assert(p);
    452 
    453    return DRD_(mutex_type_name)(p->mutex_type);
    454 }
    455 
    456 const char* DRD_(mutex_type_name)(const MutexT mt)
    457 {
    458    switch (mt)
    459    {
    460    case mutex_type_unknown:
    461       return "mutex";
    462    case mutex_type_invalid_mutex:
    463       return "invalid mutex";
    464    case mutex_type_recursive_mutex:
    465       return "recursive mutex";
    466    case mutex_type_errorcheck_mutex:
    467       return "error checking mutex";
    468    case mutex_type_default_mutex:
    469       return "mutex";
    470    case mutex_type_spinlock:
    471       return "spinlock";
    472    }
    473    tl_assert(0);
    474    return "?";
    475 }
    476 
    477 /** Return true if the specified mutex is locked by any thread. */
    478 static Bool mutex_is_locked(struct mutex_info* const p)
    479 {
    480    tl_assert(p);
    481    return (p->recursion_count > 0);
    482 }
    483 
    484 Bool DRD_(mutex_is_locked_by)(const Addr mutex, const DrdThreadId tid)
    485 {
    486    struct mutex_info* const p = DRD_(mutex_get)(mutex);
    487    if (p)
    488    {
    489       return (p->recursion_count > 0 && p->owner == tid);
    490    }
    491    return False;
    492 }
    493 
    494 int DRD_(mutex_get_recursion_count)(const Addr mutex)
    495 {
    496    struct mutex_info* const p = DRD_(mutex_get)(mutex);
    497    tl_assert(p);
    498    return p->recursion_count;
    499 }
    500 
    501 /**
    502  * Call this function when thread tid stops to exist, such that the
    503  * "last owner" field can be cleared if it still refers to that thread.
    504  */
    505 static void mutex_delete_thread(struct mutex_info* p, const DrdThreadId tid)
    506 {
    507    tl_assert(p);
    508 
    509    if (p->owner == tid && p->recursion_count > 0)
    510    {
    511       MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
    512                            p->a1, p->recursion_count, p->owner };
    513       VG_(maybe_record_error)(VG_(get_running_tid)(),
    514                               MutexErr,
    515                               VG_(get_IP)(VG_(get_running_tid)()),
    516                               "Mutex still locked at thread exit",
    517                               &MEI);
    518       p->owner = VG_INVALID_THREADID;
    519    }
    520 }
    521 
    522 ULong DRD_(get_mutex_lock_count)(void)
    523 {
    524    return s_mutex_lock_count;
    525 }
    526 
    527 ULong DRD_(get_mutex_segment_creation_count)(void)
    528 {
    529    return s_mutex_segment_creation_count;
    530 }
    531