]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Added new command-line option --trace-rwlock. Added regression test exp-drd/tests...
authorBart Van Assche <bvanassche@acm.org>
Mon, 3 Mar 2008 20:31:58 +0000 (20:31 +0000)
committerBart Van Assche <bvanassche@acm.org>
Mon, 3 Mar 2008 20:31:58 +0000 (20:31 +0000)
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7549

17 files changed:
exp-drd/TODO.txt
exp-drd/drd_clientreq.c
exp-drd/drd_clientreq.h
exp-drd/drd_intercepts.c
exp-drd/drd_main.c
exp-drd/drd_mutex.c
exp-drd/drd_rwlock.c
exp-drd/drd_thread.c
exp-drd/drd_track.h
exp-drd/drd_vc.c
exp-drd/tests/Makefile.am
exp-drd/tests/rwlock_race.c [new file with mode: 0644]
exp-drd/tests/rwlock_race.stderr.exp [new file with mode: 0644]
exp-drd/tests/rwlock_race.vgtest [new file with mode: 0644]
exp-drd/tests/tc06_two_races.stderr.exp
exp-drd/tests/tc21_pthonce.stderr.exp
glibc-2.X-drd.supp

index 1b6c7cb43abc8be079e89af64b91d072bd914af3..2cd2b96733ec6149d86377f34665f3c256d2f18d 100644 (file)
@@ -12,6 +12,11 @@ Data-race detection algorithm
   without triggering Valgrind's redirection mechanism.
 - Discuss on the Valgrind mailing list the modificaiton of tests/vg_regtest
   such that it ignores files ending in ~ or #.
+- Continue the discussion on the Valgrind mailing list about docbook and
+  'make dist'.
+- Continue the discussion on the Valgrind mailing list about -Wformat.
+- Explain on the Valgrind mailing list the difference between a bus lock
+  and acquire / release labels.
 - Find out why a race is reported on std::string::string(std::string const&)
   (stc test case 16).
 - Add support for objects that are shared over threads and that use reference
@@ -27,8 +32,9 @@ Data-race detection algorithm
 - Performance testing and tuning.
 - testing on PPC and AIX (current implementation is only tested on X86 and
   AMD64).
-- [AMD64] Find out why removing 'write(1, "", 0)' in drd_intercepts.c triggers
-  a crash on AMD64. Is this an exp-drd or a VEX bug ?
+- Find out why there are sometimes races reported on exp-drd/test/matinv.
+- [Fedora 8] Find out why pth_broadcast sometimes hangs on Fedora 8. Is this an
+  exp-drd, pth_broadcast, kernel or glibc bug ?
 - On x86 and amd64 platforms, add support for implicit locking arising from
   the use of the LOCK instruction prefix.
 - Convert the array in drd_thread.c with thread information into an OSet.
@@ -65,5 +71,3 @@ Known bugs
   (works fine on i386). This is a bug in Valgrind's debug info reader
   -- VG_(find_seginfo)() returns NULL for BSS symbols on x86_64. Not yet in
   the KDE bug tracking system.
-- No error message is printed for tc20_verifywrap when a locked mutex is
-  deallocated (mutex was allocated on the stack).
index 20d1aa3db50edc7a5cb1bc49accf91a8e52bea38..e63cf6a63aa3dac8a5c028f258c31ce31703a6ec 100644 (file)
@@ -111,6 +111,10 @@ static Bool drd_handle_client_request(ThreadId tid, UWord* arg, UWord* ret)
       thread_new_segment(PtThreadIdToDrdThreadId(arg[1]));
       break;
 
+   case VG_USERREQ__DRD_TRACE_ADDR:
+      drd_trace_addr(arg[1]);
+      break;
+
    case VG_USERREQ__SET_PTHREADID:
       thread_set_pthreadid(thread_get_running_tid(), arg[1]);
       break;
index 12bc5e35f077ab80dfb7d4d345a2cac6b81e840b..1a569f6927cba4c54e5b3dc5a31a30db1bf25bc0 100644 (file)
@@ -28,6 +28,9 @@ enum {
   /* To ask the drd tool to start a new segment in the specified thread. */
   VG_USERREQ__DRD_START_NEW_SEGMENT,
   /* args: POSIX thread ID. */
+  /* To ask the drd tool to trace all accesses to the specified address. */
+  VG_USERREQ__DRD_TRACE_ADDR,
+  /* args: Addr. */
 
   /* Tell the core the pthread_t of the running thread */
   VG_USERREQ__SET_PTHREADID,
index 706ec1efc25ded315456cc009213af60fc877524..96a1f945c1f7403d87c9e5cae7675cc3864a8d70 100644 (file)
@@ -339,12 +339,6 @@ PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
    VALGRIND_GET_ORIG_FN(fn);
    VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_PTHREAD_MUTEX_LOCK,
                               mutex, sizeof(*mutex), mutex_type(mutex), 0, 0);
-#if 1
-   // The only purpose of the system call below is to make drd work on AMD64
-   // systems. Without this system call, clients crash (SIGSEGV) in
-   // std::locale::locale().
-   write(1, "", 0);
-#endif
    CALL_FN_W_W(ret, fn, mutex);
    VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
                               mutex, ret == 0, 0, 0, 0);
index fce6142162e51c5d1c42ae9afec7e6e8826b0dbc..0262962edbcd243d81a636469caf9e87fb1b673d 100644 (file)
@@ -30,6 +30,7 @@
 #include "drd_error.h"
 #include "drd_malloc_wrappers.h"
 #include "drd_mutex.h"
+#include "drd_rwlock.h"
 #include "drd_segment.h"
 #include "drd_semaphore.h"
 #include "drd_suppression.h"
@@ -82,6 +83,7 @@ static Bool drd_process_cmd_line_option(Char* arg)
    Bool trace_csw         = False;
    Bool trace_danger_set  = False;
    Bool trace_mutex       = False;
+   Bool trace_rwlock      = False;
    Bool trace_segment     = False;
    Bool trace_semaphore   = False;
    Bool trace_suppression = False;
@@ -96,6 +98,7 @@ static Bool drd_process_cmd_line_option(Char* arg)
    else VG_BOOL_CLO(arg, "--trace-fork-join",   drd_trace_fork_join)
    else VG_BOOL_CLO(arg, "--trace-mem",         drd_trace_mem)
    else VG_BOOL_CLO(arg, "--trace-mutex",       trace_mutex)
+   else VG_BOOL_CLO(arg, "--trace-rwlock",      trace_rwlock)
    else VG_BOOL_CLO(arg, "--trace-segment",     trace_segment)
    else VG_BOOL_CLO(arg, "--trace-semaphore",   trace_semaphore)
    else VG_BOOL_CLO(arg, "--trace-suppression", trace_suppression)
@@ -119,6 +122,8 @@ static Bool drd_process_cmd_line_option(Char* arg)
       thread_trace_danger_set(trace_danger_set);
    if (trace_mutex)
       mutex_set_trace(trace_mutex);
+   if (trace_rwlock)
+      rwlock_set_trace(trace_rwlock);
    if (trace_segment)
       sg_set_trace(trace_segment);
    if (trace_semaphore)
@@ -160,12 +165,15 @@ VG_REGPARM(2) void drd_trace_load(Addr addr, SizeT size)
 #if 1
    if (drd_trace_mem || (addr == drd_trace_address))
    {
-      VG_(message)(Vg_UserMsg, "load  0x%lx size %ld %s (vg %d / drd %d)",
+      char vc[80];
+      vc_snprint(vc, sizeof(vc), thread_get_vc(thread_get_running_tid()));
+      VG_(message)(Vg_UserMsg, "load  0x%lx size %ld %s (vg %d / drd %d / vc %s)",
                    addr,
                    size,
                    thread_get_name(thread_get_running_tid()),
                    VG_(get_running_tid)(),
-                   thread_get_running_tid());
+                   thread_get_running_tid(),
+                   vc);
       VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
                                  VG_(clo_backtrace_size));
       tl_assert(DrdThreadIdToVgThreadId(thread_get_running_tid())
@@ -200,13 +208,16 @@ VG_REGPARM(2) void drd_trace_store(Addr addr, SizeT size)
 #if 1
    if (drd_trace_mem || (addr == drd_trace_address))
    {
-      VG_(message)(Vg_UserMsg, "store 0x%lx size %ld %s (vg %d / drd %d / off %d)",
+      char vc[80];
+      vc_snprint(vc, sizeof(vc), thread_get_vc(thread_get_running_tid()));
+      VG_(message)(Vg_UserMsg, "store 0x%lx size %ld %s (vg %d / drd %d / off %d / vc %s)",
                    addr,
                    size,
                    thread_get_name(thread_get_running_tid()),
                    VG_(get_running_tid)(),
                    thread_get_running_tid(),
-                   addr - thread_get_stack_min(thread_get_running_tid()));
+                   addr - thread_get_stack_min(thread_get_running_tid()),
+                   vc);
       VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
                                  VG_(clo_backtrace_size));
       tl_assert(DrdThreadIdToVgThreadId(thread_get_running_tid())
@@ -420,6 +431,11 @@ void drd_post_thread_join(DrdThreadId drd_joiner, DrdThreadId drd_joinee)
    barrier_thread_delete(drd_joinee);
 }
 
+void drd_trace_addr(const Addr addr)
+{
+   drd_trace_address = addr;
+}
+
 /* Called after a thread has performed its last memory access. */
 static void drd_thread_finished(ThreadId tid)
 {
index 1178a3a110fb06d3970743ae854914c712ce6363..55598ae7d0a70bdeb0a29b1a3a3b4ef5f6c389f8 100644 (file)
@@ -29,6 +29,7 @@
 #include "priv_drd_clientreq.h"
 #include "pub_tool_errormgr.h"    // VG_(maybe_record_error)()
 #include "pub_tool_libcassert.h"  // tl_assert()
+#include "pub_tool_libcbase.h"    // VG_(strlen)
 #include "pub_tool_libcprint.h"   // VG_(message)()
 #include "pub_tool_machine.h"     // VG_(get_IP)()
 #include "pub_tool_threadstate.h" // VG_(get_running_tid)()
@@ -117,13 +118,13 @@ mutex_get_or_allocate(const Addr mutex,
 
   if (clientobj_present(mutex, mutex + size))
   {
-     GenericErrInfo GEI;
-     VG_(maybe_record_error)(VG_(get_running_tid)(),
-                             GenericErr,
-                             VG_(get_IP)(VG_(get_running_tid)()),
-                             "Not a mutex",
-                             &GEI);
-     return 0;
+    GenericErrInfo GEI;
+    VG_(maybe_record_error)(VG_(get_running_tid)(),
+                            GenericErr,
+                            VG_(get_IP)(VG_(get_running_tid)()),
+                            "Not a mutex",
+                            &GEI);
+    return 0;
   }
 
   p = &clientobj_add(mutex, mutex + size, ClientMutex)->mutex;
@@ -281,10 +282,16 @@ void mutex_post_lock(const Addr mutex, const Bool took_lock)
   }
 
   if (! p || ! took_lock)
-     return;
+    return;
 
   if (p->recursion_count == 0)
   {
+    const DrdThreadId last_owner = p->owner;
+
+    if (last_owner != drd_tid && last_owner != DRD_INVALID_THREADID)
+      thread_combine_vc2(drd_tid, mutex_get_last_vc(mutex));
+    thread_new_segment(drd_tid);
+
     p->owner = drd_tid;
     s_mutex_lock_count++;
   }
@@ -298,15 +305,6 @@ void mutex_post_lock(const Addr mutex, const Bool took_lock)
     p->owner = drd_tid;
   }
   p->recursion_count++;
-
-  if (p->recursion_count == 1)
-  {
-     const DrdThreadId last_owner = p->owner;
-
-    if (last_owner != drd_tid && last_owner != DRD_INVALID_THREADID)
-      thread_combine_vc2(drd_tid, mutex_get_last_vc(mutex));
-    thread_new_segment(drd_tid);
-  }
 }
 
 /**
@@ -339,13 +337,13 @@ void mutex_unlock(const Addr mutex, const MutexT mutex_type)
 
   if (p == 0 || mutex_type == mutex_type_invalid_mutex)
   {
-     GenericErrInfo GEI;
-     VG_(maybe_record_error)(vg_tid,
-                             GenericErr,
-                             VG_(get_IP)(vg_tid),
-                             "Not a mutex",
-                             &GEI);
-     return;
+    GenericErrInfo GEI;
+    VG_(maybe_record_error)(vg_tid,
+                            GenericErr,
+                            VG_(get_IP)(vg_tid),
+                            "Not a mutex",
+                            &GEI);
+    return;
   }
 
   if (p->owner == DRD_INVALID_THREADID)
@@ -356,14 +354,14 @@ void mutex_unlock(const Addr mutex, const MutexT mutex_type)
                             VG_(get_IP)(vg_tid),
                             "Mutex not locked",
                             &MEI);
-     return;
+    return;
   }
 
   tl_assert(p);
   if (p->mutex_type != mutex_type)
   {
     VG_(message)(Vg_UserMsg, "??? mutex %p: type changed from %d into %d",
-                p->a1, p->mutex_type, mutex_type);
+                 p->a1, p->mutex_type, mutex_type);
   }
   tl_assert(p->mutex_type == mutex_type);
   tl_assert(p->owner != DRD_INVALID_THREADID);
@@ -483,6 +481,6 @@ ULong get_mutex_lock_count(void)
 
 /*
  * Local variables:
- * c-basic-offset: 3
+ * c-basic-offset: 2
  * End:
  */
index ac0560ba781303d8d147825447eac4375b2180b1..ade98dbd9fb411798e73aed451c8e2830f7c8008 100644 (file)
 
 struct rwlock_thread_info
 {
-  UWord tid;        // DrdThreadId.
-  UInt  reader_nesting_count;
-  UInt  writer_nesting_count;
+  UWord       tid;        // DrdThreadId.
+  UInt        reader_nesting_count;
+  UInt        writer_nesting_count;
   VectorClock vc;   // Vector clock associated with last unlock by this thread.
+  Bool        last_lock_was_writer_lock;
 };
 
 
@@ -129,6 +130,7 @@ struct rwlock_thread_info* lookup_or_insert_node(OSet* oset, const UWord tid)
     q->reader_nesting_count = 0;
     q->writer_nesting_count = 0;
     vc_init(&q->vc, 0, 0);
+    q->last_lock_was_writer_lock = False;
     VG_(OSetGen_Insert)(oset, q);
   }
   tl_assert(q);
@@ -136,14 +138,15 @@ struct rwlock_thread_info* lookup_or_insert_node(OSet* oset, const UWord tid)
 }
 
 static void rwlock_combine_other_vc(struct rwlock_info* const p,
-                                    const DrdThreadId tid)
+                                    const DrdThreadId tid,
+                                    const Bool readers_too)
 {
   struct rwlock_thread_info* q;
 
   VG_(OSetGen_ResetIter)(p->thread_info);
   for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
   {
-    if (q->tid != tid)
+    if (q->tid != tid && (readers_too || q->last_lock_was_writer_lock))
     {
       thread_combine_vc2(tid, &q->vc);
     }
@@ -175,7 +178,7 @@ static void rwlock_cleanup(struct rwlock_info* p)
   if (s_trace_rwlock)
   {
     VG_(message)(Vg_UserMsg,
-                 "[%d/%d] rwlock_destroy   0x%lx",
+                 "[%d/%d] rwlock_destroy     0x%lx",
                  VG_(get_running_tid)(),
                  thread_get_running_tid(),
                  p->a1);
@@ -244,7 +247,7 @@ rwlock_pre_init(const Addr rwlock, const SizeT size)
   if (s_trace_rwlock)
   {
     VG_(message)(Vg_UserMsg,
-                 "[%d/%d] rwlock_init      %s 0x%lx",
+                 "[%d/%d] rwlock_init        0x%lx",
                  VG_(get_running_tid)(),
                  thread_get_running_tid(),
                  rwlock);
@@ -351,7 +354,7 @@ void rwlock_post_rdlock(const Addr rwlock, const Bool took_lock)
   q = lookup_or_insert_node(p->thread_info, drd_tid);
   if (++q->reader_nesting_count == 1)
   {
-    rwlock_combine_other_vc(p, drd_tid);
+    rwlock_combine_other_vc(p, drd_tid, False);
     thread_new_segment(drd_tid);
   }
 }
@@ -422,8 +425,9 @@ void rwlock_post_wrlock(const Addr rwlock, const Bool took_lock)
   q = lookup_or_insert_node(p->thread_info, thread_get_running_tid());
   tl_assert(q->writer_nesting_count == 0);
   q->writer_nesting_count++;
+  q->last_lock_was_writer_lock = True;
   tl_assert(q->writer_nesting_count == 1);
-  rwlock_combine_other_vc(p, drd_tid);
+  rwlock_combine_other_vc(p, drd_tid, True);
   thread_new_segment(drd_tid);
 }
 
@@ -447,7 +451,7 @@ void rwlock_pre_unlock(const Addr rwlock)
   if (s_trace_rwlock && p != 0)
   {
     VG_(message)(Vg_UserMsg,
-                 "[%d/%d] rwlock_unlock    0x%lx",
+                 "[%d/%d] rwlock_unlock      0x%lx",
                  vg_tid,
                  drd_tid,
                  rwlock);
@@ -479,6 +483,7 @@ void rwlock_pre_unlock(const Addr rwlock)
     /* current vector clock of the thread such that it is available when  */
     /* this rwlock is locked again.                                        */
     vc_assign(&q->vc, vc);
+    q->last_lock_was_writer_lock = False;
 
     thread_new_segment(drd_tid);
   }
index 6a151d48fdb95c6ed9103d47f8cc5eb1337d63d9..8807117baec5cfedf2fd8a81817446a35481dade 100644 (file)
@@ -582,7 +582,7 @@ static void thread_compute_maximum_vc(VectorClock* vc)
 }
 
 /**
- * Discard all segments that have a defined ordered against the latest vector
+ * Discard all segments that have a defined order against the latest vector
  * clock of every thread -- these segments can no longer be involved in a
  * data race.
  */
@@ -875,7 +875,7 @@ static void thread_update_danger_set(const DrdThreadId tid)
       VG_(message)(Vg_DebugMsg, "%s", msg);
    }
 
-   for (p = s_threadinfo[tid].first; p; p = p->next)
+   p = s_threadinfo[tid].last;
    {
       unsigned j;
 
@@ -896,7 +896,8 @@ static void thread_update_danger_set(const DrdThreadId tid)
       {
          if (IsValidDrdThreadId(j))
          {
-            const Segment* const q = s_threadinfo[j].last;
+            const Segment* q;
+            for (q = s_threadinfo[j].last; q; q = q->prev)
             if (j != tid && q != 0
                 && ! vc_lte(&q->vc, &p->vc) && ! vc_lte(&p->vc, &q->vc))
             {
index 7bb6373d526bd4df61ec2a7dfee5868f08f042c3..0b0045c2ddab2c4089c753b14321c73d97be4b4f 100644 (file)
@@ -25,6 +25,8 @@
 
 void drd_post_thread_join(DrdThreadId joiner, DrdThreadId joinee);
 
+void drd_trace_addr(const Addr addr);
+
 void drd_pre_mutex_init(Addr mutex, SizeT size, const MutexT mutex_type);
 void drd_post_mutex_destroy(Addr mutex, const MutexT mutex_type);
 void drd_pre_mutex_lock(const Addr mutex, const SizeT size,
index 26c6e5ca375cc69c7b3f0b597eb57528b391000d..6e887d07e5494f43e32198c77045e65565e2ad18 100644 (file)
@@ -134,9 +134,7 @@ Bool vc_ordered(const VectorClock* const vc1,
   return vc_lte(vc1, vc2) || vc_lte(vc2, vc1);
 }
 
-/**
- * Compute elementwise minimum.
- */
+/** Compute elementwise minimum. */
 void vc_min(VectorClock* const result,
             const VectorClock* const rhs)
 {
@@ -148,7 +146,7 @@ void vc_min(VectorClock* const result,
   tl_assert(result);
   tl_assert(rhs);
 
-  // First count the number of shared thread id's.
+  /* First count the number of shared thread ID's. */
   j = 0;
   shared = 0;
   for (i = 0; i < result->size; i++)
@@ -169,14 +167,18 @@ void vc_min(VectorClock* const result,
 
   vc_check(result);
 
-  // Next, combine both vector clocks into one.
+  /* Next, combine both vector clocks into one. */
   i = 0;
   for (j = 0; j < rhs->size; j++)
   {
     vc_check(result);
 
     while (i < result->size && result->vc[i].threadid < rhs->vc[j].threadid)
+    {
+      /* Thread ID is missing in second vector clock. Clear the count. */
+      result->vc[i].count = 0;
       i++;
+    }
     if (i >= result->size)
     {
       result->size++;
@@ -185,17 +187,12 @@ void vc_min(VectorClock* const result,
     }
     else if (result->vc[i].threadid > rhs->vc[j].threadid)
     {
-      unsigned k;
-      for (k = result->size; k > i; k--)
-      {
-        result->vc[k] = result->vc[k - 1];
-      }
-      result->size++;
-      result->vc[i] = rhs->vc[j];
-      vc_check(result);
+      /* Thread ID is missing in first vector clock. Leave out. */
     }
     else
     {
+      /* The thread ID is present in both vector clocks. Compute the minimum */
+      /* of vc[i].count and vc[j].count. */
       tl_assert(result->vc[i].threadid == rhs->vc[j].threadid);
       if (rhs->vc[j].count < result->vc[i].count)
       {
@@ -205,7 +202,6 @@ void vc_min(VectorClock* const result,
     }
   }
   vc_check(result);
-  tl_assert(result->size == new_size);
 }
 
 /**
index 6196f99ce435510f046e1851d3c77551a033c2ec..de0a6a008bc83ef25b4f5ec2971dfeb21fcd4f6c 100644 (file)
@@ -48,6 +48,7 @@ EXTRA_DIST = $(noinst_SCRIPTS)                                  \
        pth_detached2.vgtest                                    \
        pth_detached2.stdout.exp pth_detached2.stderr.exp       \
        recursive_mutex.vgtest recursive_mutex.stderr.exp       \
+       rwlock_race.vgtest rwlock_race.stderr.exp               \
        sem_as_mutex.vgtest  sem_as_mutex.stderr.exp            \
        sem_as_mutex2.vgtest sem_as_mutex2.stderr.exp           \
        sigalrm.vgtest                                          \
@@ -121,8 +122,9 @@ check_PROGRAMS =      \
   pth_cond_race       \
   pth_create_chain    \
   pth_detached        \
-  sem_as_mutex        \
   recursive_mutex     \
+  rwlock_race         \
+  sem_as_mutex        \
   sigalrm             \
   tc01_simple_race    \
   tc02_simple_tls     \
@@ -194,6 +196,9 @@ pth_detached_LDADD          = -lpthread
 recursive_mutex_SOURCES     = recursive_mutex.c
 recursive_mutex_LDADD       = -lpthread
 
+rwlock_race_SOURCES         = rwlock_race.c
+rwlock_race_LDADD           = -lpthread
+
 sem_as_mutex_SOURCES        = sem_as_mutex.c
 sem_as_mutex_LDADD          = -lpthread
 
diff --git a/exp-drd/tests/rwlock_race.c b/exp-drd/tests/rwlock_race.c
new file mode 100644 (file)
index 0000000..d7c6af2
--- /dev/null
@@ -0,0 +1,48 @@
+/** Cause a race inside code protected by a reader lock.
+ */
+
+
+/* Needed for older glibc's (2.3 and older, at least) who don't
+   otherwise "know" about pthread_rwlock_anything or about
+   PTHREAD_MUTEX_RECURSIVE (amongst things). */
+
+#define _GNU_SOURCE 1
+
+#include <stdio.h>
+#include <pthread.h>
+#include "../drd_clientreq.h"
+
+
+static pthread_rwlock_t s_rwlock;
+static int s_racy;
+
+static void* thread(void* arg)
+{
+  pthread_rwlock_rdlock(&s_rwlock);
+  s_racy++;
+  pthread_rwlock_unlock(&s_rwlock);
+  return 0;
+}
+
+int main(int argc, char** argv)
+{
+  pthread_t thread1;
+  pthread_t thread2;
+
+#if 0
+  int res;
+  VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_TRACE_ADDR,
+                             &s_racy, 0, 0, 0, 0);
+#endif
+
+  pthread_rwlock_init(&s_rwlock, 0);
+  pthread_create(&thread1, 0, thread, 0);
+  pthread_create(&thread2, 0, thread, 0);
+  pthread_join(thread1, 0);
+  pthread_join(thread2, 0);
+  pthread_rwlock_destroy(&s_rwlock);
+
+  fprintf(stderr, "Result: %d\n", s_racy);
+
+  return 0;
+}
diff --git a/exp-drd/tests/rwlock_race.stderr.exp b/exp-drd/tests/rwlock_race.stderr.exp
new file mode 100644 (file)
index 0000000..8bf1411
--- /dev/null
@@ -0,0 +1,26 @@
+
+Thread 2:
+Conflicting load by thread 2 at 0x........ size 4
+   at 0x........: thread (rwlock_race.c:?)
+   by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
+   by 0x........: start_thread (in libpthread-?.?.so)
+   by 0x........: clone (in /...libc...)
+Allocation context: unknown
+Other segment start (thread 2)
+   (thread finished, call stack no longer available)
+Other segment end (thread 2)
+   (thread finished, call stack no longer available)
+
+Conflicting store by thread 2 at 0x........ size 4
+   at 0x........: thread (rwlock_race.c:?)
+   by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
+   by 0x........: start_thread (in libpthread-?.?.so)
+   by 0x........: clone (in /...libc...)
+Allocation context: unknown
+Other segment start (thread 2)
+   (thread finished, call stack no longer available)
+Other segment end (thread 2)
+   (thread finished, call stack no longer available)
+Result: 2
+
+ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
diff --git a/exp-drd/tests/rwlock_race.vgtest b/exp-drd/tests/rwlock_race.vgtest
new file mode 100644 (file)
index 0000000..00a15e7
--- /dev/null
@@ -0,0 +1 @@
+prog: rwlock_race
index a2fd0a24ec74c31b5d906513294488ab0f902fdb..4cbed89c1ac45a413fba99d08d896678dfbfcb93 100644 (file)
@@ -1 +1 @@
-ERROR SUMMARY: 2 errors from 2 contexts
+ERROR SUMMARY: 4 errors from 4 contexts
index d18786f80668a209115b4a13cf5e8afa8d9cd471..f9e0de4dfe6afc73e94b6d72865bb5faf40abde1 100644 (file)
@@ -1,3 +1,45 @@
 
+Thread 2:
+Conflicting load by thread 2 at 0x........ size 4
+   at 0x........: vfprintf (in /...libc...)
+   by 0x........: printf (in /...libc...)
+   by 0x........: child (tc21_pthonce.c:73)
+   by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
+   by 0x........: start_thread (in libpthread-?.?.so)
+   by 0x........: clone (in /...libc...)
+Allocation context: unknown
+Other segment start (thread 1)
+   at 0x........: clone (in /...libc...)
+   by 0x........: do_clone (in libpthread-?.?.so)
+   by 0x........: pthread_create@@GLIBC_2.2.5 (in libpthread-?.?.so)
+   by 0x........: pthread_create* (drd_intercepts.c:?)
+   by 0x........: main (tc21_pthonce.c:86)
+Other segment end (thread 1)
+   at 0x........: clone (in /...libc...)
+   by 0x........: do_clone (in libpthread-?.?.so)
+   by 0x........: pthread_create@@GLIBC_2.2.5 (in libpthread-?.?.so)
+   by 0x........: pthread_create* (drd_intercepts.c:?)
+   by 0x........: main (tc21_pthonce.c:86)
 
-ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+Conflicting load by thread 2 at 0x........ size 4
+   at 0x........: vfprintf (in /...libc...)
+   by 0x........: printf (in /...libc...)
+   by 0x........: child (tc21_pthonce.c:73)
+   by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
+   by 0x........: start_thread (in libpthread-?.?.so)
+   by 0x........: clone (in /...libc...)
+Allocation context: unknown
+Other segment start (thread 1)
+   at 0x........: clone (in /...libc...)
+   by 0x........: do_clone (in libpthread-?.?.so)
+   by 0x........: pthread_create@@GLIBC_2.2.5 (in libpthread-?.?.so)
+   by 0x........: pthread_create* (drd_intercepts.c:?)
+   by 0x........: main (tc21_pthonce.c:86)
+Other segment end (thread 1)
+   at 0x........: clone (in /...libc...)
+   by 0x........: do_clone (in libpthread-?.?.so)
+   by 0x........: pthread_create@@GLIBC_2.2.5 (in libpthread-?.?.so)
+   by 0x........: pthread_create* (drd_intercepts.c:?)
+   by 0x........: main (tc21_pthonce.c:86)
+
+ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
index 0f3dcb315a4d158a6bf8c5567f29a6b71ef6ee92..f1b68cc85eed744c9438c446bd8189dd0055bce4 100644 (file)
    fun:pthread_create@@GLIBC_*
    fun:pthread_create*
 }
+{
+   pthread
+   exp-drd:ConflictingAccess
+   fun:clone
+   fun:do_clone
+   fun:pthread_create@@GLIBC_*
+   fun:pthread_create*
+}
 {
    pthread-glibc2.7-pthread_create
    exp-drd:ConflictingAccess
    fun:pthread_mutex_lock
    fun:pthread_mutex_lock
 }
+{
+   pthread
+   exp-drd:ConflictingAccess
+   fun:__pthread_mutex_cond_lock
+   fun:pthread_cond_wait@@GLIBC_*
+   fun:pthread_cond_wait*
+}
 {
    pthread
    exp-drd:ConflictingAccess