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