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_clientobj.h"
     27 #include "drd_hb.h"
     28 #include "drd_error.h"
     29 #include "pub_tool_errormgr.h"    /* VG_(maybe_record_error)() */
     30 #include "pub_tool_libcassert.h"  /* tl_assert()               */
     31 #include "pub_tool_libcprint.h"   /* VG_(printf)()             */
     32 #include "pub_tool_machine.h"     /* VG_(get_IP)()             */
     33 #include "pub_tool_mallocfree.h"  /* VG_(malloc)(), VG_(free)()*/
     34 #include "pub_tool_threadstate.h" /* VG_(get_running_tid)()    */
     35 
     36 
     37 /* Type definitions. */
     38 
     39 /** Per-thread hb information. */
     40 struct hb_thread_info
     41 {
     42    UWord       tid; // A DrdThreadId declared as UWord because
     43                     // this member variable is the key of an OSet.
     44    Segment*    sg;  // Segment created before most recent
     45                     // ANNOTATE_HAPPENS_BEFORE().
     46 };
     47 
     48 
     49 /* Local functions. */
     50 
     51 static void DRD_(hb_cleanup)(struct hb_info* p);
     52 
     53 
     54 /* Local variables. */
     55 
     56 static Bool DRD_(s_trace_hb);
     57 
     58 
     59 /* Function definitions. */
     60 
     61 void DRD_(hb_set_trace)(const Bool trace_hb)
     62 {
     63    DRD_(s_trace_hb) = trace_hb;
     64 }
     65 
     66 /**
     67  * Initialize the structure *p with the specified thread ID.
     68  */
     69 static
     70 void DRD_(hb_thread_initialize)(struct hb_thread_info* const p,
     71                                   const DrdThreadId tid)
     72 {
     73    p->tid  = tid;
     74    p->sg   = 0;
     75 }
     76 
     77 /**
     78  * Deallocate the memory that is owned by members of struct hb_thread_info.
     79  */
     80 static void DRD_(hb_thread_destroy)(struct hb_thread_info* const p)
     81 {
     82    tl_assert(p);
     83    DRD_(sg_put)(p->sg);
     84 }
     85 
     86 static
     87 void DRD_(hb_initialize)(struct hb_info* const p, const Addr hb)
     88 {
     89    tl_assert(hb != 0);
     90    tl_assert(p->a1   == hb);
     91    tl_assert(p->type == ClientHbvar);
     92 
     93    p->cleanup       = (void(*)(DrdClientobj*))(DRD_(hb_cleanup));
     94    p->delete_thread = 0;
     95    p->oset          = VG_(OSetGen_Create)(0, 0, VG_(malloc), "drd.hb",
     96                                           VG_(free));
     97 }
     98 
     99 /**
    100  * Free the memory that was allocated by hb_initialize(). Called by
    101  * DRD_(clientobj_remove)().
    102  */
    103 static void DRD_(hb_cleanup)(struct hb_info* p)
    104 {
    105    struct hb_thread_info* r;
    106 
    107    tl_assert(p);
    108    VG_(OSetGen_ResetIter)(p->oset);
    109    for ( ; (r = VG_(OSetGen_Next)(p->oset)) != 0; )
    110       DRD_(hb_thread_destroy)(r);
    111    VG_(OSetGen_Destroy)(p->oset);
    112 }
    113 
    114 /**
    115  * Report that the synchronization object at address 'addr' is of the
    116  * wrong type.
    117  */
    118 static void wrong_type(const Addr addr)
    119 {
    120    GenericErrInfo gei = {
    121       .tid  = DRD_(thread_get_running_tid)(),
    122       .addr = addr,
    123    };
    124    VG_(maybe_record_error)(VG_(get_running_tid)(),
    125                            GenericErr,
    126                            VG_(get_IP)(VG_(get_running_tid)()),
    127                            "wrong type of synchronization object",
    128                            &gei);
    129 }
    130 
    131 struct hb_info* DRD_(hb_get_or_allocate)(const Addr hb)
    132 {
    133    struct hb_info *p;
    134 
    135    tl_assert(offsetof(DrdClientobj, hb) == 0);
    136    p = &(DRD_(clientobj_get)(hb, ClientHbvar)->hb);
    137    if (p)
    138       return p;
    139 
    140    if (DRD_(clientobj_present)(hb, hb + 1))
    141    {
    142       wrong_type(hb);
    143       return 0;
    144    }
    145 
    146    p = &(DRD_(clientobj_add)(hb, ClientHbvar)->hb);
    147    DRD_(hb_initialize)(p, hb);
    148    return p;
    149 }
    150 
    151 struct hb_info* DRD_(hb_get)(const Addr hb)
    152 {
    153    tl_assert(offsetof(DrdClientobj, hb) == 0);
    154    return &(DRD_(clientobj_get)(hb, ClientHbvar)->hb);
    155 }
    156 
    157 /** Called because of a happens-before annotation. */
    158 void DRD_(hb_happens_before)(const DrdThreadId tid, Addr const hb)
    159 {
    160    const ThreadId vg_tid = VG_(get_running_tid)();
    161    const DrdThreadId drd_tid = DRD_(VgThreadIdToDrdThreadId)(vg_tid);
    162    const UWord word_tid = tid;
    163    struct hb_info* p;
    164    struct hb_thread_info* q;
    165 
    166    p = DRD_(hb_get_or_allocate)(hb);
    167    if (DRD_(s_trace_hb))
    168       DRD_(trace_msg)("[%d] happens_before 0x%lx",
    169                       DRD_(thread_get_running_tid)(), hb);
    170 
    171    if (!p)
    172       return;
    173 
    174    /* Allocate the per-thread data structure if necessary. */
    175    q = VG_(OSetGen_Lookup)(p->oset, &word_tid);
    176    if (!q)
    177    {
    178       q = VG_(OSetGen_AllocNode)(p->oset, sizeof(*q));
    179       DRD_(hb_thread_initialize)(q, tid);
    180       VG_(OSetGen_Insert)(p->oset, q);
    181       tl_assert(VG_(OSetGen_Lookup)(p->oset, &word_tid) == q);
    182    }
    183 
    184    /*
    185     * Store a pointer to the latest segment of the current thread in the
    186     * per-thread data structure.
    187     */
    188    DRD_(thread_get_latest_segment)(&q->sg, tid);
    189    DRD_(thread_new_segment)(drd_tid);
    190 }
    191 
    192 /** Called because of a happens-after annotation. */
    193 void DRD_(hb_happens_after)(const DrdThreadId tid, const Addr hb)
    194 {
    195    struct hb_info* p;
    196    struct hb_thread_info* q;
    197    VectorClock old_vc;
    198 
    199    p = DRD_(hb_get_or_allocate)(hb);
    200 
    201    if (DRD_(s_trace_hb))
    202       DRD_(trace_msg)("[%d] happens_after  0x%lx",
    203                       DRD_(thread_get_running_tid)(), hb);
    204 
    205    if (!p)
    206       return;
    207 
    208    DRD_(thread_new_segment)(tid);
    209 
    210    /*
    211     * Combine all vector clocks that were stored because of happens-before
    212     * annotations with the vector clock of the current thread.
    213     */
    214    DRD_(vc_copy)(&old_vc, &DRD_(g_threadinfo)[tid].last->vc);
    215    VG_(OSetGen_ResetIter)(p->oset);
    216    for ( ; (q = VG_(OSetGen_Next)(p->oset)) != 0; )
    217    {
    218       if (q->tid != tid)
    219       {
    220          tl_assert(q->sg);
    221          DRD_(vc_combine)(&DRD_(g_threadinfo)[tid].last->vc, &q->sg->vc);
    222       }
    223    }
    224    DRD_(thread_update_conflict_set)(tid, &old_vc);
    225    DRD_(vc_cleanup)(&old_vc);
    226 }
    227 
    228 /** Called because of a happens-done annotation. */
    229 void DRD_(hb_happens_done)(const DrdThreadId tid, const Addr hb)
    230 {
    231    struct hb_info* p;
    232 
    233    if (DRD_(s_trace_hb))
    234       DRD_(trace_msg)("[%d] happens_done  0x%lx",
    235                       DRD_(thread_get_running_tid)(), hb);
    236 
    237    p = DRD_(hb_get)(hb);
    238    if (!p)
    239    {
    240       GenericErrInfo gei = {
    241 	 .tid = DRD_(thread_get_running_tid)(),
    242 	 .addr = hb,
    243       };
    244       VG_(maybe_record_error)(VG_(get_running_tid)(),
    245                               GenericErr,
    246                               VG_(get_IP)(VG_(get_running_tid)()),
    247                               "missing happens-before annotation",
    248                               &gei);
    249       return;
    250    }
    251 
    252    DRD_(clientobj_remove)(p->a1, ClientHbvar);
    253 }
    254