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_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    {
    169       VG_(message)(Vg_UserMsg,
    170                    "[%d] happens_before 0x%lx\n",
    171                    DRD_(thread_get_running_tid)(),
    172                    hb);
    173    }
    174 
    175    if (!p)
    176       return;
    177 
    178    /* Allocate the per-thread data structure if necessary. */
    179    q = VG_(OSetGen_Lookup)(p->oset, &word_tid);
    180    if (!q)
    181    {
    182       q = VG_(OSetGen_AllocNode)(p->oset, sizeof(*q));
    183       DRD_(hb_thread_initialize)(q, tid);
    184       VG_(OSetGen_Insert)(p->oset, q);
    185       tl_assert(VG_(OSetGen_Lookup)(p->oset, &word_tid) == q);
    186    }
    187 
    188    /*
    189     * Store a pointer to the latest segment of the current thread in the
    190     * per-thread data structure.
    191     */
    192    DRD_(thread_get_latest_segment)(&q->sg, tid);
    193    DRD_(thread_new_segment)(drd_tid);
    194 }
    195 
    196 /** Called because of a happens-after annotation. */
    197 void DRD_(hb_happens_after)(const DrdThreadId tid, const Addr hb)
    198 {
    199    struct hb_info* p;
    200    struct hb_thread_info* q;
    201    VectorClock old_vc;
    202 
    203    p = DRD_(hb_get_or_allocate)(hb);
    204 
    205    if (DRD_(s_trace_hb))
    206    {
    207       VG_(message)(Vg_UserMsg, "[%d] happens_after 0x%lx\n",
    208                    DRD_(thread_get_running_tid)(), hb);
    209    }
    210 
    211    if (!p)
    212       return;
    213 
    214    DRD_(thread_new_segment)(tid);
    215 
    216    /*
    217     * Combine all vector clocks that were stored because of happens-before
    218     * annotations with the vector clock of the current thread.
    219     */
    220    DRD_(vc_copy)(&old_vc, &DRD_(g_threadinfo)[tid].last->vc);
    221    VG_(OSetGen_ResetIter)(p->oset);
    222    for ( ; (q = VG_(OSetGen_Next)(p->oset)) != 0; )
    223    {
    224       if (q->tid != tid)
    225       {
    226          tl_assert(q->sg);
    227          DRD_(vc_combine)(&DRD_(g_threadinfo)[tid].last->vc, &q->sg->vc);
    228       }
    229    }
    230    DRD_(thread_update_conflict_set)(tid, &old_vc);
    231    DRD_(vc_cleanup)(&old_vc);
    232 }
    233 
    234 /** Called because of a happens-done annotation. */
    235 void DRD_(hb_happens_done)(const DrdThreadId tid, const Addr hb)
    236 {
    237    struct hb_info* p;
    238 
    239    if (DRD_(s_trace_hb))
    240    {
    241       VG_(message)(Vg_UserMsg, "[%d] happens_done  0x%lx\n",
    242                    DRD_(thread_get_running_tid)(), hb);
    243    }
    244 
    245    p = DRD_(hb_get)(hb);
    246    if (!p)
    247    {
    248       GenericErrInfo gei = {
    249 	 .tid = DRD_(thread_get_running_tid)(),
    250 	 .addr = hb,
    251       };
    252       VG_(maybe_record_error)(VG_(get_running_tid)(),
    253                               GenericErr,
    254                               VG_(get_IP)(VG_(get_running_tid)()),
    255                               "missing happens-before annotation",
    256                               &gei);
    257       return;
    258    }
    259 
    260    DRD_(clientobj_remove)(p->a1, ClientHbvar);
    261 }
    262