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