]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Changes:
authorBart Van Assche <bvanassche@acm.org>
Sun, 7 Mar 2010 10:54:21 +0000 (10:54 +0000)
committerBart Van Assche <bvanassche@acm.org>
Sun, 7 Mar 2010 10:54:21 +0000 (10:54 +0000)
- Generalized the behavior of happens-before / happens-after annotations such
  that not only 1:1 but also n:m patterns are supported.
- Dropped support for invoking happens-before / happens-after annotations on
  POSIX condition variables (pthread_cond_t).
- Report the details about the offending synchronization object in generic
  errors.
- Converted a few tl_assert() statements into error messages.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11073

15 files changed:
drd/Makefile.am
drd/drd_barrier.c
drd/drd_clientobj.c
drd/drd_clientobj.h
drd/drd_clientreq.c
drd/drd_clientreq.h
drd/drd_cond.c
drd/drd_cond.h
drd/drd_error.c
drd/drd_error.h
drd/drd_hb.c [new file with mode: 0644]
drd/drd_hb.h [new file with mode: 0644]
drd/drd_mutex.c
drd/drd_rwlock.c
drd/drd_semaphore.c

index 60c5ce4b9afe58dd736c7149073f103959270a48..c54d665ecaa645bd64d784b28ca03840070a4840 100644 (file)
@@ -17,6 +17,7 @@ noinst_HEADERS =        \
   drd_clientreq.h       \
   drd_cond.h            \
   drd_error.h           \
+  drd_hb.h              \
   drd_load_store.h      \
   drd_malloc_wrappers.h \
   drd_mutex.h           \
@@ -56,6 +57,7 @@ DRD_SOURCES_COMMON =    \
   drd_clientreq.c       \
   drd_cond.c            \
   drd_error.c           \
+  drd_hb.c              \
   drd_load_store.c      \
   drd_main.c            \
   drd_malloc_wrappers.c \
index 90fa33064f3f2ce9cbf615bc886487199e4bd54e..de8d67b380c28bbacb0739809840a583777c0541 100644 (file)
 struct barrier_thread_info
 {
    UWord       tid;           // A DrdThreadId declared as UWord because
-   // this member variable is the key of an OSet.
+                              // this member variable is the key of an OSet.
    Word        iteration;     // iteration of last pthread_barrier_wait()
-   // call thread tid participated in.
+                              // call thread tid participated in.
    Segment*    sg[2];         // Segments of the last two
-   // pthread_barrier() calls by thread tid.
+                              // pthread_barrier() calls by thread tid.
    ExeContext* wait_call_ctxt;// call stack for *_barrier_wait() call.
    Segment*    post_wait_sg;  // Segment created after *_barrier_wait() finished
 };
@@ -308,7 +308,10 @@ void DRD_(barrier_destroy)(const Addr barrier, const BarrierT barrier_type)
 
    if (p == 0)
    {
-      GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+      GenericErrInfo GEI = {
+        .tid = DRD_(thread_get_running_tid)(),
+        .addr = barrier,
+      };
       VG_(maybe_record_error)(VG_(get_running_tid)(),
                               GenericErr,
                               VG_(get_IP)(VG_(get_running_tid)()),
index 4f305cb1ffa1ddeb1fe0764f4f0e049ae0004330..e734aad5f188aeb4db0d5af754023e12a89f0057 100644 (file)
@@ -249,6 +249,7 @@ const char* DRD_(clientobj_type_name)(const ObjType t)
    {
    case ClientMutex:     return "mutex";
    case ClientCondvar:   return "cond";
+   case ClientHbvar:     return "order annotation";
    case ClientSemaphore: return "semaphore";
    case ClientBarrier:   return "barrier";
    case ClientRwlock:    return "rwlock";
index 13941c5ea2aa35cf561a47f0dea503972453726c..66882d65bf0ab3e843bf971ded4e22e6c726f466 100644 (file)
@@ -45,9 +45,10 @@ union drd_clientobj;
 typedef enum {
    ClientMutex     = 1,
    ClientCondvar   = 2,
-   ClientSemaphore = 3,
-   ClientBarrier   = 4,
-   ClientRwlock    = 5,
+   ClientHbvar     = 3,
+   ClientSemaphore = 4,
+   ClientBarrier   = 5,
+   ClientRwlock    = 6,
 } ObjType;
 
 struct any
@@ -83,7 +84,18 @@ struct cond_info
    ExeContext* first_observed_at;
    int         waiter_count;
    Addr        mutex; // Client mutex specified in pthread_cond_wait() call, and
-   // null if no client threads are currently waiting on this cond.var.
+            // null if no client threads are currently waiting on this cond.var.
+};
+
+struct hb_info
+{
+   Addr        a1;
+   ObjType     type;
+   void        (*cleanup)(union drd_clientobj*);
+   void        (*delete_thread)(union drd_clientobj*, DrdThreadId);
+   ExeContext* first_observed_at;
+   OSet*       oset;  // Per-thread order annotation information.
+   Bool        done;  // Whether happens-done has already been invoked.
 };
 
 struct semaphore_info
@@ -135,6 +147,7 @@ typedef union drd_clientobj
    struct any            any;
    struct mutex_info     mutex;
    struct cond_info      cond;
+   struct hb_info        hb;
    struct semaphore_info semaphore;
    struct barrier_info   barrier;
    struct rwlock_info    rwlock;
index 0363a3fec0e820289eb2d4948fead419734813ad..d7a4de520d67f89438695605131a5922e1a40a65 100644 (file)
@@ -27,6 +27,7 @@
 #include "drd_clientreq.h"
 #include "drd_cond.h"
 #include "drd_error.h"
+#include "drd_hb.h"
 #include "drd_load_store.h"
 #include "drd_malloc_wrappers.h"
 #include "drd_mutex.h"
@@ -82,7 +83,10 @@ static Bool handle_client_request(ThreadId vg_tid, UWord* arg, UWord* ret)
    case VG_USERREQ__FREELIKE_BLOCK:
       if (arg[1] && ! DRD_(freelike_block)(vg_tid, arg[1]/*addr*/))
       {
-         GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+         GenericErrInfo GEI = {
+           .tid = DRD_(thread_get_running_tid)(),
+           .addr = 0,
+        };
          VG_(maybe_record_error)(vg_tid,
                                  GenericErr,
                                  VG_(get_IP)(vg_tid),
@@ -112,28 +116,15 @@ static Bool handle_client_request(ThreadId vg_tid, UWord* arg, UWord* ret)
       break;
 
    case VG_USERREQ__DRD_ANNOTATE_HAPPENS_BEFORE:
-      {
-         struct cond_info* const cond_p = DRD_(cond_get)(arg[1]);
-         if (! cond_p)
-         {
-            DRD_(mutex_init)(arg[1], mutex_type_order_annotation);
-            DRD_(mutex_pre_lock)(arg[1], mutex_type_order_annotation, False);
-            DRD_(mutex_post_lock)(arg[1], mutex_type_order_annotation, False);
-            DRD_(mutex_unlock)(arg[1], mutex_type_order_annotation);
-         }
-      }
+      DRD_(hb_happens_before)(drd_tid, arg[1]);
       break;
 
    case VG_USERREQ__DRD_ANNOTATE_HAPPENS_AFTER:
-      {
-         struct cond_info* const cond_p = DRD_(cond_get)(arg[1]);
-         if (! cond_p)
-         {
-            DRD_(mutex_pre_lock)(arg[1], mutex_type_order_annotation, False);
-            DRD_(mutex_post_lock)(arg[1], mutex_type_order_annotation, False);
-            DRD_(mutex_unlock)(arg[1], mutex_type_order_annotation);
-         }
-      }
+      DRD_(hb_happens_after)(drd_tid, arg[1]);
+      break;
+
+   case VG_USERREQ__DRD_ANNOTATE_HAPPENS_DONE:
+      DRD_(hb_happens_done)(drd_tid, arg[1]);
       break;
 
    case VG_USERREQ__DRD_ANNOTATE_RWLOCK_CREATE:
index 0b5536804797896e3ac6bed785f8c8ae8b9eb966..0d7cfa2d4148da1a56c88ae71f9c20bce5cff495 100644 (file)
@@ -229,7 +229,6 @@ typedef enum {
    mutex_type_errorcheck_mutex = 2,
    mutex_type_default_mutex    = 3,
    mutex_type_spinlock         = 4,
-   mutex_type_order_annotation = 5,
 } MutexT;
 
 /**
index 61f73ebb8d335f8483a301022fed48cb27c3a709..ec98d3c9c8f9701bbc4b83ffd75759481212e8ce 100644 (file)
 #include "drd_cond.h"
 #include "drd_error.h"
 #include "drd_mutex.h"
-#include "drd_suppression.h"
 #include "pub_tool_errormgr.h"    /* VG_(maybe_record_error)() */
 #include "pub_tool_libcassert.h"  /* tl_assert()               */
 #include "pub_tool_libcprint.h"   /* VG_(printf)()             */
 #include "pub_tool_machine.h"     /* VG_(get_IP)()             */
-#include "pub_tool_options.h"     /* VG_(clo_backtrace_size)   */
 #include "pub_tool_threadstate.h" /* VG_(get_running_tid)()    */
 
 
@@ -63,8 +61,8 @@ static
 void DRD_(cond_initialize)(struct cond_info* const p, const Addr cond)
 {
    tl_assert(cond != 0);
-   tl_assert(p->a1         == cond);
-   tl_assert(p->type       == ClientCondvar);
+   tl_assert(p->a1   == cond);
+   tl_assert(p->type == ClientCondvar);
 
    p->cleanup       = (void(*)(DrdClientobj*))(DRD_(cond_cleanup));
    p->delete_thread = 0;
@@ -83,10 +81,13 @@ static void DRD_(cond_cleanup)(struct cond_info* p)
    {
       struct mutex_info* q;
       q = &(DRD_(clientobj_get)(p->mutex, ClientMutex)->mutex);
-      tl_assert(q);
       {
-         CondDestrErrInfo cde = { DRD_(thread_get_running_tid)(),
-                                  p->a1, q->a1, q->owner };
+         CondDestrErrInfo cde = {
+           DRD_(thread_get_running_tid)(),
+           p->a1,
+           q ? q->a1 : 0,
+           q ? q->owner : DRD_INVALID_THREADID
+        };
          VG_(maybe_record_error)(VG_(get_running_tid)(),
                                  CondDestrErr,
                                  VG_(get_IP)(VG_(get_running_tid)()),
@@ -97,17 +98,40 @@ static void DRD_(cond_cleanup)(struct cond_info* p)
    }
 }
 
+/**
+ * Report that the synchronization object at address 'addr' is of the
+ * wrong type.
+ */
+static void wrong_type(const Addr addr)
+{
+   GenericErrInfo gei = {
+      .tid  = DRD_(thread_get_running_tid)(),
+      .addr = addr,
+   };
+   VG_(maybe_record_error)(VG_(get_running_tid)(),
+                           GenericErr,
+                           VG_(get_IP)(VG_(get_running_tid)()),
+                           "wrong type of synchronization object",
+                           &gei);
+}
+
 static struct cond_info* cond_get_or_allocate(const Addr cond)
 {
    struct cond_info *p;
 
    tl_assert(offsetof(DrdClientobj, cond) == 0);
    p = &(DRD_(clientobj_get)(cond, ClientCondvar)->cond);
-   if (p == 0)
+   if (p)
+      return p;
+
+   if (DRD_(clientobj_present)(cond, cond + 1))
    {
-      p = &(DRD_(clientobj_add)(cond, ClientCondvar)->cond);
-      DRD_(cond_initialize)(p, cond);
+      wrong_type(cond);
+      return 0;
    }
+
+   p = &(DRD_(clientobj_add)(cond, ClientCondvar)->cond);
+   DRD_(cond_initialize)(p, cond);
    return p;
 }
 
@@ -184,10 +208,11 @@ void DRD_(cond_post_destroy)(const Addr cond)
    DRD_(clientobj_remove)(p->a1, ClientCondvar);
 }
 
-/** Called before pthread_cond_wait(). Note: before this function is called,
- *  mutex_unlock() has already been called from drd_clientreq.c.
+/**
+ * Called before pthread_cond_wait(). Note: before this function is called,
+ * mutex_unlock() has already been called from drd_clientreq.c.
  */
-int DRD_(cond_pre_wait)(const Addr cond, const Addr mutex)
+void DRD_(cond_pre_wait)(const Addr cond, const Addr mutex)
 {
    struct cond_info* p;
    struct mutex_info* q;
@@ -201,7 +226,16 @@ int DRD_(cond_pre_wait)(const Addr cond, const Addr mutex)
    }
 
    p = cond_get_or_allocate(cond);
-   tl_assert(p);
+   if (!p)
+   {
+      CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
+      VG_(maybe_record_error)(VG_(get_running_tid)(),
+                              CondErr,
+                              VG_(get_IP)(VG_(get_running_tid)()),
+                              "not a condition variable",
+                              &cei);
+      return;
+   }
 
    if (p->waiter_count == 0)
    {
@@ -238,11 +272,13 @@ int DRD_(cond_pre_wait)(const Addr cond, const Addr mutex)
       DRD_(not_a_mutex)(p->mutex);
    }
 
-   return ++p->waiter_count;
+   ++p->waiter_count;
 }
 
-/** Called after pthread_cond_wait(). */
-int DRD_(cond_post_wait)(const Addr cond)
+/**
+ * Called after pthread_cond_wait().
+ */
+void DRD_(cond_post_wait)(const Addr cond)
 {
    struct cond_info* p;
 
@@ -255,55 +291,89 @@ int DRD_(cond_post_wait)(const Addr cond)
    }
 
    p = DRD_(cond_get)(cond);
-   if (p)
+   if (!p)
    {
-      if (p->waiter_count > 0)
+      struct mutex_info* q;
+      q = &(DRD_(clientobj_get)(p->mutex, ClientMutex)->mutex);
       {
-         --p->waiter_count;
-         if (p->waiter_count == 0)
-         {
-            p->mutex = 0;
-         }
+        CondDestrErrInfo cde = {
+           DRD_(thread_get_running_tid)(),
+           p->a1,
+           q ? q->a1 : 0,
+           q ? q->owner : DRD_INVALID_THREADID
+        };
+        VG_(maybe_record_error)(VG_(get_running_tid)(),
+                                CondDestrErr,
+                                VG_(get_IP)(VG_(get_running_tid)()),
+                                "condition variable has been destroyed while"
+                                " being waited upon",
+                                &cde);
+      }
+      return;
+   }
+
+   if (p->waiter_count > 0)
+   {
+      --p->waiter_count;
+      if (p->waiter_count == 0)
+      {
+        p->mutex = 0;
       }
-      return p->waiter_count;
    }
-   return 0;
 }
 
-static void DRD_(cond_signal)(Addr const cond)
+static void cond_signal(const DrdThreadId tid, struct cond_info* const cond_p)
 {
    const ThreadId vg_tid = VG_(get_running_tid)();
    const DrdThreadId drd_tid = DRD_(VgThreadIdToDrdThreadId)(vg_tid);
-   struct cond_info* const cond_p = DRD_(cond_get)(cond);
 
-   if (cond_p && cond_p->waiter_count > 0)
+   tl_assert(cond_p);
+
+   if (cond_p->waiter_count > 0)
    {
       if (DRD_(s_report_signal_unlocked)
-          && ! DRD_(mutex_is_locked_by)(cond_p->mutex, drd_tid))
+         && ! DRD_(mutex_is_locked_by)(cond_p->mutex, drd_tid))
       {
-         /* A signal is sent while the associated mutex has not been locked. */
-         /* This can indicate but is not necessarily a race condition.       */
-         CondRaceErrInfo cei = { .tid = DRD_(thread_get_running_tid)(),
-                                 .cond  = cond,
-                                 .mutex = cond_p->mutex,
-                               };
-         VG_(maybe_record_error)(vg_tid,
-                                 CondRaceErr,
-                                 VG_(get_IP)(vg_tid),
-                                 "CondErr",
-                                 &cei);
+        /*
+         * A signal is sent while the associated mutex has not been locked.
+         * This can indicate but is not necessarily a race condition.
+         */
+        CondRaceErrInfo cei = { .tid = DRD_(thread_get_running_tid)(),
+                                .cond  = cond_p->a1,
+                                .mutex = cond_p->mutex,
+        };
+        VG_(maybe_record_error)(vg_tid,
+                                CondRaceErr,
+                                VG_(get_IP)(vg_tid),
+                                "CondErr",
+                                &cei);
       }
    }
    else
    {
-      /* No other thread is waiting for the signal, hence the signal will be */
-      /* lost. This is normal in a POSIX threads application.                */
+      /*
+       * No other thread is waiting for the signal, hence the signal will
+       * be lost. This is normal in a POSIX threads application.
+       */
    }
 }
 
+static void not_initialized(Addr const cond)
+{
+   CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
+   VG_(maybe_record_error)(VG_(get_running_tid)(),
+                           CondErr,
+                           VG_(get_IP)(VG_(get_running_tid)()),
+                           "condition variable has not been initialized",
+                           &cei);
+}
+
 /** Called before pthread_cond_signal(). */
 void DRD_(cond_pre_signal)(Addr const cond)
 {
+   struct cond_info* p;
+
+   p = DRD_(cond_get)(cond);
    if (DRD_(s_trace_cond))
    {
       VG_(message)(Vg_UserMsg,
@@ -312,12 +382,20 @@ void DRD_(cond_pre_signal)(Addr const cond)
                    cond);
    }
 
-   DRD_(cond_signal)(cond);
+   if (!p)
+   {
+      not_initialized(cond);
+      return;
+   }
+
+   cond_signal(DRD_(thread_get_running_tid)(), p);
 }
 
 /** Called before pthread_cond_broadcast(). */
 void DRD_(cond_pre_broadcast)(Addr const cond)
 {
+   struct cond_info* p;
+
    if (DRD_(s_trace_cond))
    {
       VG_(message)(Vg_UserMsg,
@@ -326,5 +404,12 @@ void DRD_(cond_pre_broadcast)(Addr const cond)
                    cond);
    }
 
-   DRD_(cond_signal)(cond);
+   p = DRD_(cond_get)(cond);
+   if (!p)
+   {
+      not_initialized(cond);
+      return;
+   }
+
+   cond_signal(DRD_(thread_get_running_tid)(), p);
 }
index be98b96cf5dfce1b6251f7b79a658d1c6cb3db72..079f81eed5e12122bea0838f7e09cfa6a0b6d9d8 100644 (file)
@@ -43,8 +43,8 @@ void DRD_(cond_set_trace)(const Bool trace_cond);
 struct cond_info* DRD_(cond_get)(const Addr cond);
 void DRD_(cond_pre_init)(const Addr cond);
 void DRD_(cond_post_destroy)(const Addr cond);
-int DRD_(cond_pre_wait)(const Addr cond, const Addr mutex);
-int DRD_(cond_post_wait)(const Addr cond);
+void DRD_(cond_pre_wait)(const Addr cond, const Addr mutex);
+void DRD_(cond_post_wait)(const Addr cond);
 void DRD_(cond_pre_signal)(const Addr cond);
 void DRD_(cond_pre_broadcast)(const Addr cond);
 
index 2c10703b39c7bad46d4cc3fb95c980e038e8c091..607c32b0dc7388af3137b91d0745f8ed17a22721 100644 (file)
@@ -371,9 +371,11 @@ static void drd_tool_error_pp(Error* const e)
       break;
    }
    case GenericErr: {
-      //GenericErrInfo* gei =(GenericErrInfo*)(VG_(get_error_extra)(e));
+      GenericErrInfo* gei = (GenericErrInfo*)(VG_(get_error_extra)(e));
       VG_(message)(Vg_UserMsg, "%s\n", VG_(get_error_string)(e));
       VG_(pp_ExeContext)(VG_(get_error_where)(e));
+      if (gei->addr)
+        first_observed(gei->addr);
       break;
    }
    case InvalidThreadId: {
index c8e582a716da75a573f45fab87de7208cb27d7de..88094a4eeb58dbd4b946f3e7f742dca2d806911d 100644 (file)
@@ -163,6 +163,7 @@ typedef struct {
 
 typedef struct {
    DrdThreadId tid;
+   Addr        addr;
 } GenericErrInfo;
 
 typedef struct {
diff --git a/drd/drd_hb.c b/drd/drd_hb.c
new file mode 100644 (file)
index 0000000..1f65e82
--- /dev/null
@@ -0,0 +1,287 @@
+/* -*- mode: C; c-basic-offset: 3; -*- */
+/*
+  This file is part of drd, a thread error detector.
+
+  Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>.
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+  02111-1307, USA.
+
+  The GNU General Public License is contained in the file COPYING.
+*/
+
+
+#include "drd_clientobj.h"
+#include "drd_hb.h"
+#include "drd_error.h"
+#include "pub_tool_errormgr.h"    /* VG_(maybe_record_error)() */
+#include "pub_tool_libcassert.h"  /* tl_assert()               */
+#include "pub_tool_libcprint.h"   /* VG_(printf)()             */
+#include "pub_tool_machine.h"     /* VG_(get_IP)()             */
+#include "pub_tool_mallocfree.h"  /* VG_(malloc)(), VG_(free)()*/
+#include "pub_tool_threadstate.h" /* VG_(get_running_tid)()    */
+
+
+/* Type definitions. */
+
+/** Per-thread hb information. */
+struct hb_thread_info
+{
+   UWord       tid; // A DrdThreadId declared as UWord because
+                    // this member variable is the key of an OSet.
+   Segment*    sg;  // Segment created before most recent
+                    // ANNOTATE_HAPPENS_BEFORE().
+};
+
+
+/* Local functions. */
+
+static void DRD_(hb_cleanup)(struct hb_info* p);
+
+
+/* Local variables. */
+
+static Bool DRD_(s_trace_hb);
+
+
+/* Function definitions. */
+
+void DRD_(hb_set_trace)(const Bool trace_hb)
+{
+   DRD_(s_trace_hb) = trace_hb;
+}
+
+/**
+ * Initialize the structure *p with the specified thread ID.
+ */
+static
+void DRD_(hb_thread_initialize)(struct hb_thread_info* const p,
+                                  const DrdThreadId tid)
+{
+   p->tid  = tid;
+   p->sg   = 0;
+}
+
+/**
+ * Deallocate the memory that is owned by members of struct hb_thread_info.
+ */
+static void DRD_(hb_thread_destroy)(struct hb_thread_info* const p)
+{
+   tl_assert(p);
+   DRD_(sg_put)(p->sg);
+}
+
+static
+void DRD_(hb_initialize)(struct hb_info* const p, const Addr hb)
+{
+   tl_assert(hb != 0);
+   tl_assert(p->a1   == hb);
+   tl_assert(p->type == ClientHbvar);
+
+   p->cleanup       = (void(*)(DrdClientobj*))(DRD_(hb_cleanup));
+   p->delete_thread = 0;
+   p->oset          = VG_(OSetGen_Create)(0, 0, VG_(malloc), "drd.hb",
+                                          VG_(free));
+   p->done          = False;
+}
+
+/**
+ * Free the memory that was allocated by hb_initialize(). Called by
+ * DRD_(clientobj_remove)().
+ */
+static void DRD_(hb_cleanup)(struct hb_info* p)
+{
+   struct hb_thread_info* r;
+
+   tl_assert(p);
+   VG_(OSetGen_ResetIter)(p->oset);
+   for ( ; (r = VG_(OSetGen_Next)(p->oset)) != 0; )
+      DRD_(hb_thread_destroy)(r);
+   VG_(OSetGen_Destroy)(p->oset);
+}
+
+/**
+ * Report that the synchronization object at address 'addr' is of the
+ * wrong type.
+ */
+static void wrong_type(const Addr addr)
+{
+   GenericErrInfo gei = {
+      .tid  = DRD_(thread_get_running_tid)(),
+      .addr = addr,
+   };
+   VG_(maybe_record_error)(VG_(get_running_tid)(),
+                           GenericErr,
+                           VG_(get_IP)(VG_(get_running_tid)()),
+                           "wrong type of synchronization object",
+                           &gei);
+}
+
+struct hb_info* DRD_(hb_get_or_allocate)(const Addr hb)
+{
+   struct hb_info *p;
+
+   tl_assert(offsetof(DrdClientobj, hb) == 0);
+   p = &(DRD_(clientobj_get)(hb, ClientHbvar)->hb);
+   if (p)
+      return p;
+
+   if (DRD_(clientobj_present)(hb, hb + 1))
+   {
+      wrong_type(hb);
+      return 0;
+   }
+
+   p = &(DRD_(clientobj_add)(hb, ClientHbvar)->hb);
+   DRD_(hb_initialize)(p, hb);
+   return p;
+}
+
+struct hb_info* DRD_(hb_get)(const Addr hb)
+{
+   tl_assert(offsetof(DrdClientobj, hb) == 0);
+   return &(DRD_(clientobj_get)(hb, ClientHbvar)->hb);
+}
+
+/** Called because of a happens-before annotation. */
+void DRD_(hb_happens_before)(const DrdThreadId tid, Addr const hb)
+{
+   const ThreadId vg_tid = VG_(get_running_tid)();
+   const DrdThreadId drd_tid = DRD_(VgThreadIdToDrdThreadId)(vg_tid);
+   const UWord word_tid = tid;
+   struct hb_info* p;
+   struct hb_thread_info* q;
+
+   p = DRD_(hb_get_or_allocate)(hb);
+   if (DRD_(s_trace_hb))
+   {
+      VG_(message)(Vg_UserMsg,
+                   "[%d] happens_before 0x%lx\n",
+                   DRD_(thread_get_running_tid)(),
+                   hb);
+   }
+
+   if (!p)
+      return;
+
+   if (p->done)
+   {
+      GenericErrInfo gei = {
+        .tid = DRD_(thread_get_running_tid)(),
+        .addr = hb,
+      };
+      VG_(maybe_record_error)(VG_(get_running_tid)(),
+                              GenericErr,
+                              VG_(get_IP)(VG_(get_running_tid)()),
+                              "happens-before after happens-after",
+                              &gei);
+      return;
+   }
+
+   /* Allocate the per-thread data structure if necessary. */
+   q = VG_(OSetGen_Lookup)(p->oset, &word_tid);
+   if (!q)
+   {
+      q = VG_(OSetGen_AllocNode)(p->oset, sizeof(*q));
+      DRD_(hb_thread_initialize)(q, tid);
+      VG_(OSetGen_Insert)(p->oset, q);
+      tl_assert(VG_(OSetGen_Lookup)(p->oset, &word_tid) == q);
+   }
+
+   /*
+    * Store a pointer to the latest segment of the current thread in the
+    * per-thread data structure.
+    */
+   DRD_(thread_get_latest_segment)(&q->sg, tid);
+   DRD_(thread_new_segment)(drd_tid);
+}
+
+/** Called because of a happens-after annotation. */
+void DRD_(hb_happens_after)(const DrdThreadId tid, const Addr hb)
+{
+   struct hb_info* p;
+   struct hb_thread_info* q;
+   VectorClock old_vc;
+
+   p = DRD_(hb_get)(hb);
+
+   if (DRD_(s_trace_hb))
+   {
+      VG_(message)(Vg_UserMsg, "[%d] happens_after 0x%lx\n",
+                   DRD_(thread_get_running_tid)(), hb);
+   }
+
+   if (!p)
+   {
+      GenericErrInfo gei = {
+        .tid = DRD_(thread_get_running_tid)(),
+        .addr = hb,
+      };
+      VG_(maybe_record_error)(VG_(get_running_tid)(),
+                              GenericErr,
+                              VG_(get_IP)(VG_(get_running_tid)()),
+                              "missing happens-before annotation",
+                              &gei);
+      return;
+   }
+
+   p->done = True;
+
+   /*
+    * Combine all vector clocks that were stored because of happens-before
+    * annotations with the vector clock of the current thread.
+    */
+   DRD_(vc_copy)(&old_vc, &DRD_(g_threadinfo)[tid].last->vc);
+   VG_(OSetGen_ResetIter)(p->oset);
+   for ( ; (q = VG_(OSetGen_Next)(p->oset)) != 0; )
+   {
+      if (q->tid != tid)
+      {
+         tl_assert(q->sg);
+         DRD_(vc_combine)(&DRD_(g_threadinfo)[tid].last->vc, &q->sg->vc);
+      }
+   }
+   DRD_(thread_update_conflict_set)(tid, &old_vc);
+   DRD_(vc_cleanup)(&old_vc);
+}
+
+/** Called because of a happens-done annotation. */
+void DRD_(hb_happens_done)(const DrdThreadId tid, const Addr hb)
+{
+   struct hb_info* p;
+
+   if (DRD_(s_trace_hb))
+   {
+      VG_(message)(Vg_UserMsg, "[%d] happens_done  0x%lx\n",
+                   DRD_(thread_get_running_tid)(), hb);
+   }
+
+   p = DRD_(hb_get)(hb);
+   if (!p)
+   {
+      GenericErrInfo gei = {
+        .tid = DRD_(thread_get_running_tid)(),
+        .addr = hb,
+      };
+      VG_(maybe_record_error)(VG_(get_running_tid)(),
+                              GenericErr,
+                              VG_(get_IP)(VG_(get_running_tid)()),
+                              "missing happens-before annotation",
+                              &gei);
+      return;
+   }
+
+   DRD_(clientobj_remove)(p->a1, ClientHbvar);
+}
diff --git a/drd/drd_hb.h b/drd/drd_hb.h
new file mode 100644 (file)
index 0000000..89db2b2
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*- mode: C; c-basic-offset: 3; -*- */
+/*
+  This file is part of drd, a thread error detector.
+
+  Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>.
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+  02111-1307, USA.
+
+  The GNU General Public License is contained in the file COPYING.
+*/
+
+
+#ifndef __DRD_HB_H
+#define __DRD_HB_H
+
+
+#include "drd_thread.h"      /* DrdThreadid */
+#include "pub_tool_basics.h" /* Addr        */
+
+
+/* Forward declarations. */
+
+struct hb_info;
+
+
+/* Function declarations. */
+
+void DRD_(hb_set_trace)(const Bool trace_hb);
+struct hb_info* DRD_(hb_get)(const Addr hb);
+struct hb_info* DRD_(hb_get_or_allocate)(const Addr hb);
+void DRD_(hb_init)(const Addr hb);
+void DRD_(hb_destroy)(const Addr hb);
+void DRD_(hb_happens_after)(const DrdThreadId tid, const Addr hb);
+void DRD_(hb_happens_before)(const DrdThreadId tid, const Addr hb);
+void DRD_(hb_happens_done)(const DrdThreadId tid, const Addr hb);
+
+
+#endif /* __DRD_HB_H */
index cf5a4a86ec1b3a54b208c62e9e2f51e59bb8cca1..f29d68e98dba3393856fea5d804332a92875f986 100644 (file)
@@ -114,7 +114,7 @@ static void mutex_cleanup(struct mutex_info* p)
    p->last_locked_segment = 0;
 }
 
-/** Let Valgrind report that there is no mutex object at address 'mutex'. */
+/** Report that address 'mutex' is not the address of a mutex object. */
 void DRD_(not_a_mutex)(const Addr mutex)
 {
    MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
@@ -126,6 +126,21 @@ void DRD_(not_a_mutex)(const Addr mutex)
                            &MEI);
 }
 
+/**
+ * Report that address 'mutex' is not the address of a mutex object of the
+ * expected type.
+ */
+static void wrong_mutex_type(const Addr mutex)
+{
+   MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
+                        mutex, -1, DRD_INVALID_THREADID };
+   VG_(maybe_record_error)(VG_(get_running_tid)(),
+                           MutexErr,
+                           VG_(get_IP)(VG_(get_running_tid)()),
+                           "Mutex type mismatch",
+                           &MEI);
+}
+
 static
 struct mutex_info*
 DRD_(mutex_get_or_allocate)(const Addr mutex, const MutexT mutex_type)
@@ -136,7 +151,13 @@ DRD_(mutex_get_or_allocate)(const Addr mutex, const MutexT mutex_type)
    p = &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex);
    if (p)
    {
-      return p;
+      if (mutex_type == mutex_type_unknown || p->mutex_type == mutex_type)
+        return p;
+      else
+      {
+        wrong_mutex_type(mutex);
+        return 0;
+      }
    }
 
    if (DRD_(clientobj_present)(mutex, mutex + 1))
@@ -211,10 +232,11 @@ void DRD_(mutex_post_destroy)(const Addr mutex)
    DRD_(clientobj_remove)(mutex, ClientMutex);
 }
 
-/** Called before pthread_mutex_lock() is invoked. If a data structure for
- *  the client-side object was not yet created, do this now. Also check whether
- *  an attempt is made to lock recursively a synchronization object that must
- *  not be locked recursively.
+/**
+ * Called before pthread_mutex_lock() is invoked. If a data structure for the
+ * client-side object was not yet created, do this now. Also check whether an
+ * attempt is made to lock recursively a synchronization object that must not
+ * be locked recursively.
  */
 void DRD_(mutex_pre_lock)(const Addr mutex, MutexT mutex_type,
                           const Bool trylock)
@@ -222,7 +244,7 @@ void DRD_(mutex_pre_lock)(const Addr mutex, MutexT mutex_type,
    struct mutex_info* p;
 
    p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
-   if (mutex_type == mutex_type_unknown)
+   if (p && mutex_type == mutex_type_unknown)
       mutex_type = p->mutex_type;
 
    if (s_trace_mutex)
@@ -464,11 +486,8 @@ const char* DRD_(mutex_type_name)(const MutexT mt)
       return "mutex";
    case mutex_type_spinlock:
       return "spinlock";
-   case mutex_type_order_annotation:
-      return "order annotation mutex";
-   default:
-      tl_assert(0);
    }
+   tl_assert(0);
    return "?";
 }
 
index a6edfdd6a5f3e61b9ed2075356ba95b71e642f7f..01614f61d0d9fe47291f6d137f31852c9914addb 100644 (file)
@@ -294,7 +294,10 @@ DRD_(rwlock_get_or_allocate)(const Addr rwlock, const RwLockT rwlock_type)
 
    if (DRD_(clientobj_present)(rwlock, rwlock + 1))
    {
-      GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+      GenericErrInfo GEI = {
+        .tid  = DRD_(thread_get_running_tid)(),
+        .addr = rwlock,
+      };
       VG_(maybe_record_error)(VG_(get_running_tid)(),
                               GenericErr,
                               VG_(get_IP)(VG_(get_running_tid)()),
@@ -358,7 +361,10 @@ void DRD_(rwlock_post_destroy)(const Addr rwlock, const RwLockT rwlock_type)
    p = DRD_(rwlock_get)(rwlock);
    if (p == 0)
    {
-      GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+      GenericErrInfo GEI = {
+        .tid = DRD_(thread_get_running_tid)(),
+        .addr = rwlock,
+      };
       VG_(maybe_record_error)(VG_(get_running_tid)(),
                               GenericErr,
                               VG_(get_IP)(VG_(get_running_tid)()),
@@ -542,7 +548,10 @@ void DRD_(rwlock_pre_unlock)(const Addr rwlock, const RwLockT rwlock_type)
    p = DRD_(rwlock_get)(rwlock);
    if (p == 0)
    {
-      GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+      GenericErrInfo GEI = {
+        .tid = DRD_(thread_get_running_tid)(),
+        .addr = rwlock,
+      };
       VG_(maybe_record_error)(VG_(get_running_tid)(),
                               GenericErr,
                               VG_(get_IP)(VG_(get_running_tid)()),
index 65b4ad695bd83250581d49451f878b435fde0ed9..4d73a876e1221c0ce44b8888704b35d9a7b8d0c6 100644 (file)
@@ -237,7 +237,10 @@ void DRD_(semaphore_destroy)(const Addr semaphore)
 
    if (p == 0)
    {
-      GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+      GenericErrInfo GEI = {
+        .tid  = DRD_(thread_get_running_tid)(),
+        .addr = semaphore,
+      };
       VG_(maybe_record_error)(VG_(get_running_tid)(),
                               GenericErr,
                               VG_(get_IP)(VG_(get_running_tid)()),
@@ -314,7 +317,10 @@ void DRD_(semaphore_close)(const Addr semaphore)
 
    if (p == 0)
    {
-      GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+      GenericErrInfo GEI = {
+        .tid  = DRD_(thread_get_running_tid)(),
+        .addr = semaphore,
+      };
       VG_(maybe_record_error)(VG_(get_running_tid)(),
                               GenericErr,
                               VG_(get_IP)(VG_(get_running_tid)()),