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_error.h"
     27 #include "drd_segment.h"
     28 #include "drd_thread.h"
     29 #include "pub_tool_basics.h"      // Addr, SizeT
     30 #include "pub_tool_libcassert.h"  // tl_assert()
     31 #include "pub_tool_libcbase.h"    // VG_(strlen)()
     32 #include "pub_tool_libcprint.h"   // VG_(printf)()
     33 #include "pub_tool_machine.h"     // VG_(get_SP)()
     34 #include "pub_tool_mallocfree.h"  // VG_(malloc)(), VG_(free)()
     35 #include "pub_tool_threadstate.h" // VG_INVALID_THREADID
     36 
     37 
     38 /* Local variables. */
     39 
     40 static ULong s_segment_merge_count;
     41 static ULong s_segments_created_count;
     42 static ULong s_segments_alive_count;
     43 static ULong s_max_segments_alive_count;
     44 static Bool s_trace_segment;
     45 
     46 
     47 /* Function definitions. */
     48 
     49 /**
     50  * Initialize the memory 'sg' points at.
     51  *
     52  * @note The creator and created thread ID's may be equal.
     53  * @note This function copies the vector clock of thread 'creator', a technique
     54  *   also known as clock snooping. This will only work reliably if the thread
     55  *   that called pthread_create() waits until the created thread has copied
     56  *   the vector clock.
     57  */
     58 static void sg_init(Segment* const sg,
     59                     const DrdThreadId creator,
     60                     const DrdThreadId created)
     61 {
     62    Segment* creator_sg;
     63    ThreadId vg_created = DRD_(DrdThreadIdToVgThreadId)(created);
     64 
     65    tl_assert(sg);
     66    tl_assert(creator == DRD_INVALID_THREADID
     67              || DRD_(IsValidDrdThreadId)(creator));
     68 
     69    creator_sg = (creator != DRD_INVALID_THREADID
     70                  ? DRD_(thread_get_segment)(creator) : 0);
     71 
     72    sg->next = 0;
     73    sg->prev = 0;
     74    sg->tid = created;
     75    sg->refcnt = 1;
     76 
     77    if (vg_created != VG_INVALID_THREADID && VG_(get_SP)(vg_created) != 0)
     78       sg->stacktrace = VG_(record_ExeContext)(vg_created, 0);
     79    else
     80       sg->stacktrace = 0;
     81 
     82    if (creator_sg)
     83       DRD_(vc_copy)(&sg->vc, &creator_sg->vc);
     84    else
     85       DRD_(vc_init)(&sg->vc, 0, 0);
     86    DRD_(vc_increment)(&sg->vc, created);
     87    DRD_(bm_init)(&sg->bm);
     88 
     89    if (s_trace_segment)
     90    {
     91       char* vc;
     92 
     93       vc = DRD_(vc_aprint)(&sg->vc);
     94       VG_(message)(Vg_DebugMsg, "New segment for thread %d with vc %s\n",
     95                    created, vc);
     96       VG_(free)(vc);
     97    }
     98 }
     99 
    100 /** Deallocate the memory that was allocated by sg_init(). */
    101 static void DRD_(sg_cleanup)(Segment* const sg)
    102 {
    103    tl_assert(sg);
    104    tl_assert(sg->refcnt == 0);
    105 
    106    DRD_(vc_cleanup)(&sg->vc);
    107    DRD_(bm_cleanup)(&sg->bm);
    108 }
    109 
    110 /** Allocate and initialize a new segment. */
    111 Segment* DRD_(sg_new)(const DrdThreadId creator, const DrdThreadId created)
    112 {
    113    Segment* sg;
    114 
    115    s_segments_created_count++;
    116    s_segments_alive_count++;
    117    if (s_max_segments_alive_count < s_segments_alive_count)
    118       s_max_segments_alive_count = s_segments_alive_count;
    119 
    120    sg = VG_(malloc)("drd.segment.sn.1", sizeof(*sg));
    121    tl_assert(sg);
    122    sg_init(sg, creator, created);
    123    return sg;
    124 }
    125 
    126 static void DRD_(sg_delete)(Segment* const sg)
    127 {
    128    if (DRD_(sg_get_trace)())
    129    {
    130       char* vc;
    131 
    132       vc = DRD_(vc_aprint)(&sg->vc);
    133       VG_(message)(Vg_DebugMsg, "Discarding the segment with vector clock %s\n",
    134                    vc);
    135       VG_(free)(vc);
    136    }
    137 
    138    s_segments_alive_count--;
    139 
    140    tl_assert(sg);
    141    DRD_(sg_cleanup)(sg);
    142    VG_(free)(sg);
    143 }
    144 
    145 /** Increment the reference count of the specified segment. */
    146 Segment* DRD_(sg_get)(Segment* const sg)
    147 {
    148    tl_assert(sg);
    149 
    150    sg->refcnt++;
    151    return sg;
    152 }
    153 
    154 /**
    155  * Decrement the reference count of the specified segment and deallocate the
    156  * segment if the reference count became zero.
    157  */
    158 void DRD_(sg_put)(Segment* const sg)
    159 {
    160    if (sg == 0)
    161       return;
    162 
    163    if (s_trace_segment)
    164    {
    165       char* vc;
    166 
    167       vc = DRD_(vc_aprint)(&sg->vc);
    168       VG_(message)(Vg_DebugMsg,
    169                    "Decrementing segment reference count %d -> %d with vc %s\n",
    170                    sg->refcnt, sg->refcnt - 1, vc);
    171       VG_(free)(vc);
    172    }
    173 
    174    tl_assert(sg->refcnt >= 1);
    175 
    176    if (--sg->refcnt == 0)
    177    {
    178       DRD_(sg_delete)(sg);
    179    }
    180 }
    181 
    182 /** Merge sg1 and sg2 into sg1. */
    183 void DRD_(sg_merge)(Segment* const sg1, Segment* const sg2)
    184 {
    185    tl_assert(sg1);
    186    tl_assert(sg1->refcnt == 1);
    187    tl_assert(sg2);
    188    tl_assert(sg2->refcnt == 1);
    189 
    190    if (s_trace_segment)
    191    {
    192       char *vc1, *vc2;
    193 
    194       vc1 = DRD_(vc_aprint)(&sg1->vc);
    195       vc2 = DRD_(vc_aprint)(&sg2->vc);
    196 
    197       VG_(message)(Vg_DebugMsg,
    198 		   "Merging segments with vector clocks %s and %s\n", vc1, vc2);
    199       VG_(free)(vc1);
    200       VG_(free)(vc2);
    201    }
    202 
    203    s_segment_merge_count++;
    204 
    205    // Keep sg1->stacktrace.
    206    // Keep sg1->vc.
    207    // Merge sg2->bm into sg1->bm.
    208    DRD_(bm_merge2)(&sg1->bm, &sg2->bm);
    209 }
    210 
    211 /** Print the vector clock and the bitmap of the specified segment. */
    212 void DRD_(sg_print)(Segment* const sg)
    213 {
    214    tl_assert(sg);
    215    VG_(printf)("vc: ");
    216    DRD_(vc_print)(&sg->vc);
    217    VG_(printf)("\n");
    218    DRD_(bm_print)(&sg->bm);
    219 }
    220 
    221 /** Query whether segment tracing has been enabled. */
    222 Bool DRD_(sg_get_trace)(void)
    223 {
    224    return s_trace_segment;
    225 }
    226 
    227 /** Enable or disable segment tracing. */
    228 void DRD_(sg_set_trace)(Bool const trace_segment)
    229 {
    230    tl_assert(trace_segment == False || trace_segment == True);
    231    s_trace_segment = trace_segment;
    232 }
    233 
    234 ULong DRD_(sg_get_segments_created_count)(void)
    235 {
    236    return s_segments_created_count;
    237 }
    238 
    239 ULong DRD_(sg_get_segments_alive_count)(void)
    240 {
    241    return s_segments_alive_count;
    242 }
    243 
    244 ULong DRD_(sg_get_max_segments_alive_count)(void)
    245 {
    246    return s_max_segments_alive_count;
    247 }
    248 
    249 ULong DRD_(sg_get_segment_merge_count)(void)
    250 {
    251    return s_segment_merge_count;
    252 }
    253