DRD updates (Bart Van Assche):

- Updated copyright statement: replaced 2006-2007 by 2006-2008.
- Added copyright statement in the files where it was missing
(drd_track.h and drd_clientreq.c)
- Eliminated dependencies on core header files -- there are no more
#include "pub_core....h" directives in the exp-drd source code.
- Added semaphore support.
- Added barrier support.
- Added pthread_mutex_timedlock() support.
- Stack depth of stack traces printed by exp-drd can now be set via
--num-callers=...
- Added command-line option --trace-barrier=[yes|no].
- Added regression test for pthread_barrier() (matinv, a program that
performs matrix inversion).
- Added regression test sem_as_mutex, which tests whether race
detection works correctly when a semaphore is used to ensure mutual
exclusion of critical sections.
- Some of helgrind's regression tests are now used to test both
helgrind and exp-drd: tc17_sembar and tc18_semabuse.
- Cleaned up bitmap implementation code now that the const keyword has
been added to the declarations of the OSet functions.
- Cleaned up exp-drd/Makefile.am
- Updated exp-drd/TODO.txt




git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7346 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/exp-drd/Makefile.am b/exp-drd/Makefile.am
index 8f18c66..e9627f3 100644
--- a/exp-drd/Makefile.am
+++ b/exp-drd/Makefile.am
@@ -67,6 +67,7 @@
 
 
 DRD_SOURCES_COMMON =    \
+  drd_barrier.c         \
   drd_bitmap.c          \
   drd_clientreq.c       \
   drd_cond.c            \
@@ -75,23 +76,27 @@
   drd_malloc_wrappers.c \
   drd_mutex.c           \
   drd_segment.c         \
+  drd_semaphore.c       \
   drd_suppression.c     \
   drd_thread.c          \
   drd_vc.c
 
-noinst_HEADERS = drd_bitmap.h \
-		 drd_mutex.h \
-		 drd_vc.h \
-		 drd_clientreq.h \
-		 drd_segment.h \
-		 priv_drd_clientreq.h \
-		 drd_cond.h \
-		 drd_suppression.h \
-		 pub_drd_bitmap.h \
-		 drd_error.h \
-		 drd_thread.h \
-		 drd_malloc_wrappers.h \
-		 drd_track.h
+noinst_HEADERS =        \
+  drd_barrier.h         \
+  drd_bitmap.h          \
+  drd_clientreq.h       \
+  drd_cond.h            \
+  drd_error.h           \
+  drd_malloc_wrappers.h \
+  drd_mutex.h           \
+  drd_segment.h         \
+  drd_semaphore.h       \
+  drd_suppression.h     \
+  drd_thread.h          \
+  drd_track.h           \
+  drd_vc.h              \
+  priv_drd_clientreq.h  \
+  pub_drd_bitmap.h
 
 AM_CFLAGS_X86_LINUX   += -I$(top_srcdir)/coregrind
 AM_CFLAGS_AMD64_LINUX += -I$(top_srcdir)/coregrind
@@ -141,13 +146,3 @@
 exp_drd_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
 exp_drd_ppc64_aix5_LDADD        = $(TOOL_LDADD_PPC64_AIX5)
 exp_drd_ppc64_aix5_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_AIX5)
-
-
-#all-local:
-#	for f in $(noinst_PROGRAMS); do \
-#	  p=`echo $$f | sed -e 's/^[^-]*-[^-]*-//' -e 's/\..*$$//'`; \
-#	  n=`echo $$f | sed -e 's/^\([^-]*-[^-]*\)-[^-]*-[^-]*/\1/'`; \
-#	  mkdir -p $(inplacedir)/$$p; \
-#	  rm -f $(inplacedir)/$$p/$$n; \
-#	  ln -f -s ../../$(subdir)/$$f $(inplacedir)/$$p/$$n; \
-#	done
diff --git a/exp-drd/TODO.txt b/exp-drd/TODO.txt
index ffabe8d..123226e 100644
--- a/exp-drd/TODO.txt
+++ b/exp-drd/TODO.txt
@@ -4,29 +4,22 @@
 
 Data-race detection algorithm
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Rename drd_preloaded.c into drd_intercepts.c.
-- Propose on the Valgrind developers mailing list to add scripts
-  "run-in-place" and "debug-in-place".
+- pthread rwlock state tracking and support.
+- Fix Fedora 7 / Fedora 8 pth_cond_race regression test failure.
 - Implement segment merging, such that the number of segments per thread
   remains limited even when there is no synchronization between threads.
 - Find out why a race is reported on std::string::string(std::string const&)
   (stc test case 16).
-- Make sure that drd supports more than 256 mutexes.
+- Eliminate the upper bounds on the number of mutexes, condition variables,
+  semaphores and barriers by converting arrays into OSet's.
+- Add a regression test for pthread_mutex_timedlock().
 - Performance testing and tuning.
-- pthread semaphore support.
-- pthread rwlock state tracking and support.
-- pthread barrier state tracking and support.
-- mutexes: support for pthread_mutex_timedlock() (recently added to the POSIX
-  spec, and present in glibc). See also
-  http://www.opengroup.org/onlinepubs/009695399/functions/pthread_mutex_timedlock.html
 - testing on PPC and AIX (current implementation is only tested on X86 and
   AMD64).
 - Change s_threadinfo[] from an array into an OSet or VgHashTable, in order to
   make ThreadId <> DrdThreadId <> pthread_t conversions faster.
-- [AMD64] Find out why removing 'write(1, "", 0)' in drd_preloaded.c triggers
+- [AMD64] Find out why removing 'write(1, "", 0)' in drd_intercepts.c triggers
   a crash on AMD64. Is this a drd or a VEX bug ?
-- Reintroduce the const keyword in the function declarations of the OSet
-  implementation in the core where appropriate.
 
 Testing
 ~~~~~~~
@@ -39,8 +32,8 @@
 
 Documentation
 ~~~~~~~~~~~~~
-- Document the code.
 - Document how to use the tool.
+- Document the code.
 
 
 Known bugs
diff --git a/exp-drd/drd_barrier.c b/exp-drd/drd_barrier.c
new file mode 100644
index 0000000..1346142
--- /dev/null
+++ b/exp-drd/drd_barrier.c
@@ -0,0 +1,281 @@
+/*
+  This file is part of drd, a data race detector.
+
+  Copyright (C) 2006-2008 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_barrier.h"
+#include "drd_error.h"
+#include "drd_suppression.h"
+#include "priv_drd_clientreq.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_oset.h"
+#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
+
+
+// Type definitions.
+
+struct barrier_thread_info
+{
+  UWord       tid;           // A DrdThreadId
+  Word        iteration;     // barrier number corresponding to ongoing
+                             // pthread_barrier() call modulo two.
+  VectorClock vc[2];         // vector clocks corresponding to the last two
+                             // pthread_barrier() calls.
+};
+
+struct barrier_info
+{
+  Addr  barrier;             // Client address of barrier.
+  SizeT size;                // Size in bytes of client-side object.
+  Word  count;               // Participant count in a barrier wait.
+  Word  iteration;           // barrier number corresponding to ongoing
+                             // pthread_barrier() call modulo two.
+  Word  participants;        // Number of participants that still have to join
+                             // the most recent barrier.
+  OSet* oset;                // Information about specific threads.
+};
+
+
+// Local variables.
+
+static Bool s_trace_barrier = False;
+struct barrier_info s_barrier[4];
+
+
+// Function definitions.
+
+void barrier_set_trace(const Bool trace_barrier)
+{
+  s_trace_barrier = trace_barrier;
+}
+
+static void barrier_thread_initialize(struct barrier_thread_info* const p,
+                                      const DrdThreadId tid,
+                                      const Word iteration)
+{
+  p->tid = tid;
+  p->iteration = iteration;
+  vc_init(&p->vc[0], 0, 0);
+  vc_init(&p->vc[1], 0, 0);
+}
+
+static void barrier_thread_destroy(struct barrier_thread_info* const p)
+{
+  vc_cleanup(&p->vc[0]);
+  vc_cleanup(&p->vc[1]);
+}
+
+static
+void barrier_initialize(struct barrier_info* const p,
+                        const Addr barrier,
+                        const SizeT size,
+                        const Word count)
+{
+  tl_assert(barrier != 0);
+  tl_assert(size > 0);
+  tl_assert(count > 0);
+
+  p->barrier = barrier;
+  p->size    = size;
+  p->count   = count;
+  p->iteration = 0;
+  p->participants = count;
+  tl_assert(sizeof(((struct barrier_thread_info*)0)->tid) == sizeof(Word));
+  tl_assert(sizeof(((struct barrier_thread_info*)0)->tid)
+            >= sizeof(DrdThreadId));
+  p->oset = VG_(OSetGen_Create)(0, 0, VG_(malloc), VG_(free));
+}
+
+void barrier_destroy(struct barrier_info* const p)
+{
+  struct barrier_thread_info* q;
+
+  tl_assert(p);
+
+  drd_finish_suppression(p->barrier, p->barrier + p->size);
+
+  VG_(OSetGen_ResetIter)(p->oset);
+  for ( ; (q = VG_(OSetGen_Next)(p->oset)) != 0; )
+  {
+    barrier_thread_destroy(q);
+  }
+  VG_(OSetGen_Destroy)(p->oset);
+  p->barrier = 0;
+  p->size = 0;
+  p->count = 0;
+  p->iteration = 0;
+  p->participants = 0;
+}
+
+static
+struct barrier_info*
+barrier_get_or_allocate(const Addr barrier, const SizeT size, const Word count)
+{
+  int i;
+
+  for (i = 0; i < sizeof(s_barrier)/sizeof(s_barrier[0]); i++)
+  {
+    if (s_barrier[i].barrier == barrier)
+    {
+      tl_assert(s_barrier[i].size == size);
+      return &s_barrier[i];
+    }
+  }
+  for (i = 0; i < sizeof(s_barrier)/sizeof(s_barrier[0]); i++)
+  {
+    if (s_barrier[i].barrier == 0)
+    {
+      barrier_initialize(&s_barrier[i], barrier, size, count);
+      drd_start_suppression(barrier, barrier + size, "barrier");
+      return &s_barrier[i];
+    }
+  }
+  tl_assert(0);
+  return 0;
+}
+
+struct barrier_info*
+barrier_init(const Addr barrier, const SizeT size, const Word count)
+{
+  tl_assert(barrier_get(barrier) == 0);
+  return barrier_get_or_allocate(barrier, size, count);
+}
+
+struct barrier_info* barrier_get(const Addr barrier)
+{
+  int i;
+  for (i = 0; i < sizeof(s_barrier)/sizeof(s_barrier[0]); i++)
+    if (s_barrier[i].barrier == barrier)
+      return &s_barrier[i];
+  return 0;
+}
+
+void barrier_pre_wait(const DrdThreadId tid, const Addr barrier)
+{
+  struct barrier_info* p;
+  struct barrier_thread_info* q;
+  const UWord word_tid = tid;
+
+  p = barrier_get(barrier);
+  tl_assert(p);
+
+  if (s_trace_barrier)
+  {
+    VG_(message)(Vg_DebugMsg,
+                 "[%d] barrier_pre_wait(%p) iteration %d / left %d/%d",
+                 tid, barrier, p->iteration, p->participants, p->count);
+  }
+
+  if (--p->participants <= 0)
+  {
+    p->iteration    = ! p->iteration;
+    p->participants = p->count;
+  }
+  q = VG_(OSetGen_Lookup)(p->oset, &word_tid);
+  if (q == 0)
+  {
+    q = VG_(OSetGen_AllocNode)(p->oset, sizeof(*q));
+    barrier_thread_initialize(q, tid, p->iteration);
+    tl_assert(q->tid == tid);
+    VG_(OSetGen_Insert)(p->oset, q);
+    tl_assert(VG_(OSetGen_Lookup)(p->oset, &word_tid) == q);
+  }
+  tl_assert(VG_(OSetGen_Lookup)(p->oset, &word_tid) == q);
+  vc_copy(&q->vc[p->iteration], &thread_get_segment(tid)->vc);
+}
+
+void barrier_post_wait(const DrdThreadId tid, const Addr barrier,
+                       const Bool waited)
+{
+  struct barrier_info* const p = barrier_get(barrier);
+
+  if (s_trace_barrier)
+  {
+    VG_(message)(Vg_DebugMsg, "[%d] barrier_post_wait(%p) iteration %d",
+                 tid, barrier, p ? 1 - p->iteration : -1);
+  }
+
+  if (waited)
+  {
+    const UWord word_tid = tid;
+    struct barrier_thread_info* q;
+    struct barrier_thread_info* r;
+
+    tl_assert(p);
+    q = VG_(OSetGen_Lookup)(p->oset, &word_tid);
+    tl_assert(q);
+    VG_(OSetGen_ResetIter)(p->oset);
+    for ( ; (r = VG_(OSetGen_Next)(p->oset)) != 0; )
+    {
+      if (r != q)
+      {
+        if (s_trace_barrier)
+        {
+          VG_(message)(Vg_DebugMsg,
+                       "[%d] barrier_post_wait: combining vc of thread %d",
+                       tid, r->tid);
+        }
+        thread_combine_vc2(tid, &r->vc[1 - q->iteration]);
+      }
+    }
+  }
+}
+
+/**
+ * Call this function when thread threadid stops to exist, such that the
+ * "last owner" field can be cleared if it still refers to that thread.
+ */
+void barrier_thread_delete(const DrdThreadId tid)
+{
+  int i;
+  struct barrier_thread_info* q;
+
+  for (i = 0; i < sizeof(s_barrier)/sizeof(s_barrier[0]); i++)
+  {
+    struct barrier_info* const p = &s_barrier[i];
+    if (p->barrier)
+    {
+      VG_(OSetGen_ResetIter)(p->oset);
+      for ( ; (q = VG_(OSetGen_Next)(p->oset)) != 0; )
+      {
+      }
+    }
+  }
+}
+
+void barrier_stop_using_mem(const Addr a1, const Addr a2)
+{
+  unsigned i;
+  for (i = 0; i < sizeof(s_barrier)/sizeof(s_barrier[0]); i++)
+  {
+    if (a1 <= s_barrier[i].barrier && s_barrier[i].barrier < a2)
+    {
+      tl_assert(s_barrier[i].barrier + s_barrier[i].size <= a2);
+      barrier_destroy(&s_barrier[i]);
+    }
+  }
+}
diff --git a/exp-drd/drd_barrier.h b/exp-drd/drd_barrier.h
new file mode 100644
index 0000000..edd4235
--- /dev/null
+++ b/exp-drd/drd_barrier.h
@@ -0,0 +1,53 @@
+/*
+  This file is part of drd, a data race detector.
+
+  Copyright (C) 2006-2008 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.
+*/
+
+
+// Barrier state information.
+
+
+#ifndef __BARRIER_H
+#define __BARRIER_H
+
+
+#include "drd_thread.h"           // DrdThreadId
+#include "drd_vc.h"
+#include "pub_tool_basics.h"      // Addr, SizeT
+
+
+struct barrier_info;
+
+
+void barrier_set_trace(const Bool trace_barrier);
+struct barrier_info* barrier_init(const Addr barrier, const SizeT size,
+                                  const Word count);
+void barrier_destroy(struct barrier_info* const p);
+struct barrier_info* barrier_get(const Addr barrier);
+void barrier_pre_wait(const DrdThreadId tid, const Addr barrier);
+void barrier_post_wait(const DrdThreadId tid, const Addr barrier,
+                       const Bool waited);
+void barrier_thread_delete(const DrdThreadId threadid);
+void barrier_stop_using_mem(const Addr a1, const Addr a2);
+
+
+#endif /* __BARRIER_H */
diff --git a/exp-drd/drd_bitmap.c b/exp-drd/drd_bitmap.c
index 21d9bb3..d171037 100644
--- a/exp-drd/drd_bitmap.c
+++ b/exp-drd/drd_bitmap.c
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/drd_bitmap.h b/exp-drd/drd_bitmap.h
index 248a5d2..d70252f 100644
--- a/exp-drd/drd_bitmap.h
+++ b/exp-drd/drd_bitmap.h
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
@@ -75,13 +75,6 @@
 #define UWORD_HIGHEST_ADDRESS(a) ((a) | (BITS_PER_UWORD - 1))
 
 
-// Local functions.
-
-// Similar to const_cast<> in C++.
-static __inline__ OSet* const_to_non_const_oset(const OSet* os)
-{ return (OSet*)os; }
-
-
 // Local constants.
 
 static ULong s_bitmap2_creation_count;
@@ -134,7 +127,7 @@
 struct bitmap2* bm_lookup(const struct bitmap* const bm, const Addr a)
 {
   const UWord a1 = a >> ADDR0_BITS;
-  return VG_(OSetGen_Lookup)(const_to_non_const_oset(bm->oset), (void*)&a1);
+  return VG_(OSetGen_Lookup)(bm->oset, &a1);
 }
 
 static __inline__
@@ -155,7 +148,7 @@
 struct bitmap2* bm2_lookup_or_insert(const struct bitmap* const bm,
                                      const UWord a1)
 {
-   struct bitmap2* p2 = VG_(OSetGen_Lookup)(const_to_non_const_oset(bm->oset), (void*)&a1);
+   struct bitmap2* p2 = VG_(OSetGen_Lookup)(bm->oset, &a1);
    if (p2 == 0)
    {
       p2 = bm2_insert(bm, a1);
diff --git a/exp-drd/drd_clientreq.c b/exp-drd/drd_clientreq.c
index d77c741..ac4b045 100644
--- a/exp-drd/drd_clientreq.c
+++ b/exp-drd/drd_clientreq.c
@@ -1,11 +1,36 @@
+/*
+  This file is part of drd, a data race detector.
+
+  Copyright (C) 2006-2008 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_clientreq.h"
 #include "drd_cond.h"
 #include "drd_mutex.h"
+#include "drd_semaphore.h"
 #include "drd_suppression.h"      // drd_start_suppression()
 #include "drd_thread.h"
 #include "drd_track.h"
 #include "priv_drd_clientreq.h"
-#include "pub_core_tooliface.h"   // VG_TRACK()
 #include "pub_tool_basics.h"      // Bool
 #include "pub_tool_libcassert.h"
 #include "pub_tool_libcassert.h"  // tl_assert()
@@ -155,6 +180,42 @@
       drd_pre_cond_broadcast(arg[1]);
       break;
 
+   case VG_USERREQ__SEM_INIT:
+      drd_semaphore_init(arg[1], arg[2], arg[3], arg[4]);
+      break;
+
+   case VG_USERREQ__SEM_DESTROY:
+      drd_semaphore_destroy(arg[1]);
+      break;
+
+   case VG_USERREQ__POST_SEM_WAIT:
+      drd_semaphore_post_wait(thread_get_running_tid(), arg[1], arg[2]);
+      break;
+
+   case VG_USERREQ__PRE_SEM_POST:
+      drd_semaphore_pre_post(thread_get_running_tid(), arg[1], arg[2]);
+      break;
+
+   case VG_USERREQ__POST_SEM_POST:
+      drd_semaphore_post_post(thread_get_running_tid(), arg[1], arg[2]);
+      break;
+
+   case VG_USERREQ__BARRIER_INIT:
+      drd_barrier_init(arg[1], arg[2], arg[3]);
+      break;
+
+   case VG_USERREQ__BARRIER_DESTROY:
+      drd_barrier_destroy(arg[1]);
+      break;
+
+   case VG_USERREQ__PRE_BARRIER_WAIT:
+      drd_barrier_pre_wait(thread_get_running_tid(), arg[1]);
+      break;
+
+   case VG_USERREQ__POST_BARRIER_WAIT:
+      drd_barrier_post_wait(thread_get_running_tid(), arg[1], arg[2]);
+      break;
+
    default:
       VG_(message)(Vg_DebugMsg, "Unrecognized client request 0x%lx 0x%lx",
                    arg[0], arg[1]);
diff --git a/exp-drd/drd_clientreq.h b/exp-drd/drd_clientreq.h
index e07f008..4d7d4f3 100644
--- a/exp-drd/drd_clientreq.h
+++ b/exp-drd/drd_clientreq.h
@@ -52,29 +52,29 @@
   VG_USERREQ__POST_THREAD_JOIN,
   /* args: pthread_t (joinee) */
 
-  /* To notify the core of a pthread_mutex_init call */
+  /* to notify the drd tool of a pthread_mutex_init call. */
   VG_USERREQ__PRE_MUTEX_INIT,
   /* args: Addr, MutexT */
-  /* To notify the core of a pthread_mutex_destroy call */
+  /* to notify the drd tool of a pthread_mutex_destroy call. */
   VG_USERREQ__POST_MUTEX_DESTROY,
   /* args: Addr, SizeT, MutexT */
-  /* To notify the core of pthread_mutex_lock calls */
+  /* to notify the drd tool of pthread_mutex_lock calls */
   VG_USERREQ__PRE_PTHREAD_MUTEX_LOCK,
   /* args: Addr, SizeT, MutexT */
-  /* To notify the core of pthread_mutex_lock calls */
+  /* to notify the drd tool of pthread_mutex_lock calls */
   VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
   /* args: Addr, SizeT, MutexT */
-  /* To notify the core of pthread_mutex_unlock calls */
+  /* to notify the drd tool of pthread_mutex_unlock calls */
   VG_USERREQ__PRE_PTHREAD_MUTEX_UNLOCK,
   /* args: Addr */
   VG_USERREQ__SPIN_INIT_OR_UNLOCK,
   /* args: Addr spinlock, SizeT size */
 
 
-  /* To notify the core of a pthread_cond_init call */
+  /* to notify the drd tool of a pthread_cond_init call. */
   VG_USERREQ__POST_PTHREAD_COND_INIT,
   /* args: Addr */
-  /* To notify the core of a pthread_cond_destroy call */
+  /* to notify the drd tool of a pthread_cond_destroy call. */
   VG_USERREQ__PRE_PTHREAD_COND_DESTROY,
   /* args: Addr cond, SizeT cond_size, Addr mutex, SizeT mutex_size */
   VG_USERREQ__PRE_PTHREAD_COND_WAIT,
@@ -86,6 +86,35 @@
   VG_USERREQ__PRE_PTHREAD_COND_BROADCAST,
   /* args: Addr cond */
 
+  /* To notify the drd tool of a sem_init call. */
+  VG_USERREQ__SEM_INIT,
+  /* args: Addr sem, SizeT sem_size, Word pshared, Word value */
+  /* To notify the drd tool of a sem_destroy call. */
+  VG_USERREQ__SEM_DESTROY,
+  /* args: Addr sem */
+  /* To notify the drd tool of a sem_wait call. */
+  VG_USERREQ__POST_SEM_WAIT,
+  /* args: Addr sem, SizeT sem_size */
+  /* To notify the drd tool before a sem_post call. */
+  VG_USERREQ__PRE_SEM_POST,
+  /* args: Addr sem, SizeT sem_size */
+  /* To notify the drd tool after a sem_post call. */
+  VG_USERREQ__POST_SEM_POST,
+  /* args: Addr sem, SizeT sem_size */
+
+  /* To notify the drd tool of a pthread_barrier_init call. */
+  VG_USERREQ__BARRIER_INIT,
+  /* args: Addr barrier, SizeT barrier_size, Word count */
+  /* To notify the drd tool of a pthread_barrier_destroy call. */
+  VG_USERREQ__BARRIER_DESTROY,
+  /* args: Addr barrier */
+  /* To notify the drd tool of a pthread_barrier_wait call. */
+  VG_USERREQ__PRE_BARRIER_WAIT,
+  /* args: Addr barrier */
+  /* To notify the drd tool of a pthread_barrier_wait call. */
+  VG_USERREQ__POST_BARRIER_WAIT,
+  /* args: Addr barrier, Word has_waited */
+
 };
 
 typedef enum
diff --git a/exp-drd/drd_cond.c b/exp-drd/drd_cond.c
index 83db465..6fdd912 100644
--- a/exp-drd/drd_cond.c
+++ b/exp-drd/drd_cond.c
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
@@ -31,8 +31,8 @@
 #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)()
-#include "pub_core_options.h"     // VG_(clo_backtrace_size)
 
 
 static struct cond_info s_cond[256];
@@ -195,6 +195,9 @@
   cond_pre_signal(cond);
 }
 
+void cond_thread_delete(const DrdThreadId tid)
+{ }
+
 void cond_stop_using_mem(const Addr a1, const Addr a2)
 {
   unsigned i;
diff --git a/exp-drd/drd_cond.h b/exp-drd/drd_cond.h
index 9912c83..8a27449 100644
--- a/exp-drd/drd_cond.h
+++ b/exp-drd/drd_cond.h
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
@@ -48,11 +48,12 @@
 void cond_set_trace(const Bool trace_cond);
 void cond_init(const Addr cond, const SizeT size);
 void cond_destroy(struct cond_info* const p);
-struct cond_info* cond_get(Addr const mutex);
+struct cond_info* cond_get(const Addr mutex);
 int cond_pre_wait(const Addr cond, const SizeT cond_size, const Addr mutex);
 int cond_post_wait(const Addr cond);
-void cond_pre_signal(Addr const cond);
-void cond_pre_broadcast(Addr const cond);
+void cond_pre_signal(const Addr cond);
+void cond_pre_broadcast(const Addr cond);
+void cond_thread_delete(const DrdThreadId tid);
 void cond_stop_using_mem(const Addr a1, const Addr a2);
 
 
diff --git a/exp-drd/drd_error.c b/exp-drd/drd_error.c
index 6ec58e6..23008d1 100644
--- a/exp-drd/drd_error.c
+++ b/exp-drd/drd_error.c
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/drd_error.h b/exp-drd/drd_error.h
index dc9ed1c..c298df8 100644
--- a/exp-drd/drd_error.h
+++ b/exp-drd/drd_error.h
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/drd_intercepts.c b/exp-drd/drd_intercepts.c
index a0c6a1a..675eec4 100644
--- a/exp-drd/drd_intercepts.c
+++ b/exp-drd/drd_intercepts.c
@@ -1,12 +1,12 @@
 
 /*--------------------------------------------------------------------*/
-/*--- Client-space code for drd.                   drd_preloaded.c ---*/
+/*--- Client-space code for drd.                  drd_intercepts.c ---*/
 /*--------------------------------------------------------------------*/
 
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
@@ -47,15 +47,12 @@
 
 #include <assert.h>
 #include <inttypes.h> // uintptr_t
+#include <pthread.h>
+#include <semaphore.h>
 #include <stdio.h>
 #include <unistd.h>
-#include <pthread.h>
 #include "drd_clientreq.h"
-#include "pub_core_basics.h"
-#include "pub_core_clreq.h"
-#include "pub_core_debuginfo.h"  // Needed for pub_core_redir.h
-#include "pub_core_redir.h"      // For VG_NOTIFY_ON_LOAD
-#include "pub_tool_threadstate.h"// VG_N_THREADS
+#include "pub_tool_redir.h"
 
 
 // Defines.
@@ -122,9 +119,6 @@
 {
    int res;
    assert(joinable == 0 || joinable == 1);
-#if 0
-   printf("vg_set_joinable(%ld, %d)\n", tid, joinable);
-#endif
    VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__SET_JOINABLE,
                               tid, joinable, 0, 0, 0);
 }
@@ -217,7 +211,7 @@
 #else
    // Yes, you see it correctly, busy waiting ... The problem is that
    // POSIX threads functions cannot be called here -- the functions defined
-   // in this file (vg_preloaded.c) would be called instead of those in
+   // in this file (drd_intercepts.c) would be called instead of those in
    // libpthread.so. This loop is necessary because vgargs is allocated on the
    // stack, and the created thread reads it.
    if (ret == 0)
@@ -334,6 +328,24 @@
    return ret;
 }
 
+// pthread_mutex_timedlock
+PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
+              pthread_mutex_t *mutex,
+              const struct timespec *abs_timeout)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
+                                mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
+   }
+   return ret;
+}
+
 // pthread_mutex_unlock
 PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
               pthread_mutex_t *mutex)
@@ -523,6 +535,271 @@
    return ret;
 }
 
+// pthread_barrier_init
+PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
+              pthread_barrier_t* barrier,
+              const pthread_barrierattr_t* attr,
+              unsigned count)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__BARRIER_INIT,
+                              barrier, sizeof(*barrier),
+                              count, 0, 0);
+   CALL_FN_W_WWW(ret, fn, barrier, attr, count);
+   return ret;
+}
+
+// pthread_barrier_destroy
+PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
+              pthread_barrier_t* barrier)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   CALL_FN_W_W(ret, fn, barrier);
+   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__BARRIER_DESTROY,
+                              barrier, 0, 0, 0, 0);
+   return ret;
+}
+
+// pthread_barrier_wait
+PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
+              pthread_barrier_t* barrier)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_WAIT,
+                              barrier, 0, 0, 0, 0);
+   CALL_FN_W_W(ret, fn, barrier);
+   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_WAIT,
+                              barrier,
+                              ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
+                              0, 0, 0);
+   return ret;
+}
+
+
+// From glibc 2.0 linuxthreads/sysdeps/pthread/cmpxchg/semaphorebits.h
+typedef struct { long int sem_status; } sem_t_glibc_2_0;
+
+// sem_init
+PTH_FUNC(int, sem_initZAGLIBCZu2Zd0, // sem_init@GLIBC_2.0
+              sem_t_glibc_2_0 *sem,
+              int pshared,
+              unsigned int value)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   CALL_FN_W_WWW(ret, fn, sem, pshared, value);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SEM_INIT,
+                                 sem, sizeof(*sem),
+                                 pshared, value, 0);
+   }
+   return ret;
+}
+
+PTH_FUNC(int, sem_initZa, // sem_init*
+              sem_t *sem,
+              int pshared,
+              unsigned int value)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   CALL_FN_W_WWW(ret, fn, sem, pshared, value);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SEM_INIT,
+                                 sem, sizeof(*sem),
+                                 pshared, value, 0);
+   }
+   return ret;
+}
+
+// sem_destroy
+PTH_FUNC(int, sem_destroyZAGLIBCZu2Zd0, // sem_destroy@GLIBC_2.0
+              sem_t_glibc_2_0 *sem)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   CALL_FN_W_W(ret, fn, sem);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SEM_DESTROY,
+                                 sem, 0, 0, 0, 0);
+   }
+   return ret;
+}
+
+PTH_FUNC(int, sem_destroyZa, // sem_destroy*
+              sem_t *sem)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   CALL_FN_W_W(ret, fn, sem);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SEM_DESTROY,
+                                 sem, 0, 0, 0, 0);
+   }
+   return ret;
+}
+
+// sem_wait
+PTH_FUNC(int, sem_waitZAGLIBCZu2Zd0, // sem_wait@GLIBC_2.0
+              sem_t_glibc_2_0 *sem)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   CALL_FN_W_W(ret, fn, sem);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
+                                 sem, sizeof(*sem), 0, 0, 0);
+   }
+   return ret;
+}
+
+PTH_FUNC(int, sem_waitZa, // sem_wait*
+              sem_t *sem)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   CALL_FN_W_W(ret, fn, sem);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
+                                 sem, sizeof(*sem), 0, 0, 0);
+   }
+   return ret;
+}
+
+// sem_trywait
+PTH_FUNC(int, sem_trywaitZAGLIBCZu2Zd0, // sem_trywait@GLIBC_2.0
+              sem_t_glibc_2_0 *sem)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   CALL_FN_W_W(ret, fn, sem);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
+                                 sem, sizeof(*sem), 0, 0, 0);
+   }
+   return ret;
+}
+
+PTH_FUNC(int, sem_trywaitZa, // sem_trywait*
+              sem_t *sem)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   CALL_FN_W_W(ret, fn, sem);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
+                                 sem, sizeof(*sem), 0, 0, 0);
+   }
+   return ret;
+}
+
+// sem_timedwait
+PTH_FUNC(int, sem_timedwait, // sem_timedwait
+              sem_t *sem, const struct timespec *abs_timeout)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   CALL_FN_W_WW(ret, fn, sem, abs_timeout);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
+                                 sem, sizeof(*sem), 0, 0, 0);
+   }
+   return ret;
+}
+
+// sem_post
+PTH_FUNC(int, sem_postZAGLIBCZu2Zd0, // sem_post@GLIBC_2.0
+              sem_t_glibc_2_0 *sem)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_POST,
+                              sem, sizeof(*sem), 0, 0, 0);
+   CALL_FN_W_W(ret, fn, sem);
+   assert(ret == 0);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_POST,
+                                 sem, sizeof(*sem), 0, 0, 0);
+   }
+   return ret;
+}
+
+PTH_FUNC(int, sem_postZa, // sem_post*
+              sem_t *sem)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_POST,
+                              sem, sizeof(*sem), 0, 0, 0);
+   CALL_FN_W_W(ret, fn, sem);
+   assert(ret == 0);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_POST,
+                                 sem, sizeof(*sem), 0, 0, 0);
+   }
+   return ret;
+}
+
+/*
+pthread_rwlock_destroy
+pthread_rwlock_init
+pthread_rwlock_rdlock
+pthread_rwlock_timedrdlock
+pthread_rwlock_timedwrlock
+pthread_rwlock_tryrdlock
+pthread_rwlock_trywrlock
+pthread_rwlock_unlock
+pthread_rwlock_wrlock
+pthread_rwlockattr_destroy
+pthread_rwlockattr_getkind_np
+pthread_rwlockattr_getpshared
+pthread_rwlockattr_init
+pthread_rwlockattr_setkind_np
+pthread_rwlockattr_setpshared
+ */
+
 /*
  * Local variables:
  * c-basic-offset: 3
diff --git a/exp-drd/drd_main.c b/exp-drd/drd_main.c
index 9cc7f12..d4634ff 100644
--- a/exp-drd/drd_main.c
+++ b/exp-drd/drd_main.c
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
@@ -23,24 +23,26 @@
 */
 
 
-#include "pub_drd_bitmap.h"
+#include "drd_barrier.h"
 #include "drd_clientreq.h"
 #include "drd_cond.h"
 #include "drd_error.h"
 #include "drd_malloc_wrappers.h"
 #include "drd_mutex.h"
 #include "drd_segment.h"
+#include "drd_semaphore.h"
 #include "drd_suppression.h"
 #include "drd_thread.h"
 #include "drd_track.h"
 #include "drd_vc.h"
 #include "priv_drd_clientreq.h"
-#include "pub_tool_vki.h"
+#include "pub_drd_bitmap.h"
 #include "pub_tool_basics.h"
 #include "pub_tool_debuginfo.h"   // VG_(describe_IP)()
 #include "pub_tool_libcassert.h"  // tl_assert()
 #include "pub_tool_libcbase.h"    // VG_(strcmp)
 #include "pub_tool_libcprint.h"   // VG_(printf)
+#include "pub_tool_vki.h"         // Must be included before pub_tool_libcproc
 #include "pub_tool_libcproc.h"
 #include "pub_tool_machine.h"
 #include "pub_tool_options.h"     // command line options
@@ -48,17 +50,6 @@
 #include "pub_tool_tooliface.h"
 
 
-// Type definitions.
-
-#if 0
-typedef struct 
-{
-  const Char* const soname;
-  const Char* const symbol;
-} SuppressedSymbol;
-#endif
-
-
 // Function declarations.
 
 static void drd_start_client_code(const ThreadId tid, const ULong bbs_done);
@@ -69,8 +60,8 @@
 // Local variables.
 
 static Bool drd_print_stats = False;
-static Bool drd_trace_mem = False;
 static Bool drd_trace_fork_join = False;
+static Bool drd_trace_mem = False;
 static Addr drd_trace_address = 0;
 
 
@@ -80,6 +71,7 @@
 
 static Bool drd_process_cmd_line_option(Char* arg)
 {
+   Bool trace_barrier     = False;
    Bool trace_cond        = False;
    Bool trace_mutex       = False;
    Bool trace_segment     = False;
@@ -87,6 +79,7 @@
    Char* trace_address    = 0;
 
    VG_BOOL_CLO     (arg, "--drd-stats",         drd_print_stats)
+   else VG_BOOL_CLO(arg, "--trace-barrier",     trace_barrier)
    else VG_BOOL_CLO(arg, "--trace-cond",        trace_cond)
    else VG_BOOL_CLO(arg, "--trace-fork-join",   drd_trace_fork_join)
    else VG_BOOL_CLO(arg, "--trace-mem",         drd_trace_mem)
@@ -99,6 +92,8 @@
 
    if (trace_address)
       drd_trace_address = VG_(strtoll16)(trace_address, 0);
+   if (trace_barrier)
+      barrier_set_trace(trace_barrier);
    if (trace_cond)
       cond_set_trace(trace_cond);
    if (trace_mutex)
@@ -150,7 +145,8 @@
                    thread_get_name(thread_get_running_tid()),
                    VG_(get_running_tid)(),
                    thread_get_running_tid());
-      VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 12);
+      VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
+                                 VG_(clo_backtrace_size));
       tl_assert(DrdThreadIdToVgThreadId(thread_get_running_tid())
                 == VG_(get_running_tid)());
    }
@@ -192,7 +188,8 @@
                    VG_(get_running_tid)(),
                    thread_get_running_tid(),
                    addr - thread_get_stack_min(thread_get_running_tid()));
-      VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 12);
+      VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
+                                 VG_(clo_backtrace_size));
       tl_assert(DrdThreadIdToVgThreadId(thread_get_running_tid())
                 == VG_(get_running_tid)());
    }
@@ -247,7 +244,8 @@
       VG_(message)(Vg_UserMsg, "start 0x%lx size %ld %s (tracing 0x%lx)",
                    a1, a2 - a1, thread_get_name(thread_get_running_tid()),
                    drd_trace_address);
-      VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 12);
+      VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
+                                 VG_(clo_backtrace_size));
    }
 }
 
@@ -259,11 +257,14 @@
       VG_(message)(Vg_UserMsg, "end   0x%lx size %ld %s (tracing 0x%lx)",
                    a1, a2 - a1, thread_get_name(thread_get_running_tid()),
                    drd_trace_address);
-      VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 12);
+      VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
+                                 VG_(clo_backtrace_size));
    }
    thread_stop_using_mem(a1, a2);
    mutex_stop_using_mem(a1, a2);
    cond_stop_using_mem(a1, a2);
+   semaphore_stop_using_mem(a1, a2);
+   barrier_stop_using_mem(a1, a2);
    drd_suppression_stop_using_mem(a1, a2);
 }
 
@@ -373,12 +374,19 @@
 
    thread_delete(drd_joinee);
    mutex_thread_delete(drd_joinee);
+   cond_thread_delete(drd_joinee);
+   semaphore_thread_delete(drd_joinee);
+   barrier_thread_delete(drd_joinee);
 }
 
 /* Called after a thread has performed its last memory access. */
 static void drd_thread_finished(ThreadId tid)
 {
-   const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(tid);
+   DrdThreadId drd_tid;
+
+   drd_set_running_tid(tid);
+
+   drd_tid = VgThreadIdToDrdThreadId(tid);
    if (drd_trace_fork_join)
    {
       VG_(message)(Vg_DebugMsg,
@@ -403,6 +411,7 @@
    struct mutex_info* p;
 
    p = mutex_get(mutex);
+   tl_assert(p);
    if (p)
    {
       // TO DO: report an error in case the recursion count is not zero
@@ -472,6 +481,70 @@
    }
 }
 
+void drd_semaphore_init(const Addr semaphore, const SizeT size,
+                        const Word pshared, const Word value)
+{
+   semaphore_init(semaphore, size, pshared, value);
+}
+
+void drd_semaphore_destroy(const Addr semaphore)
+{
+   struct semaphore_info* p;
+
+   p = semaphore_get(semaphore);
+   tl_assert(p);
+   if (p)
+   {
+      semaphore_destroy(p);
+   }
+}
+
+void drd_semaphore_post_wait(const DrdThreadId tid, const Addr semaphore,
+                             const SizeT size)
+{
+   semaphore_post_wait(tid, semaphore, size);
+}
+
+void drd_semaphore_pre_post(const DrdThreadId tid, const Addr semaphore,
+                            const SizeT size)
+{
+   semaphore_pre_post(tid, semaphore, size);
+}
+
+void drd_semaphore_post_post(const DrdThreadId tid, const Addr semaphore,
+                             const SizeT size)
+{
+   semaphore_post_post(tid, semaphore, size);
+}
+
+
+void drd_barrier_init(const Addr barrier, const SizeT size, const Word count)
+{
+   barrier_init(barrier, size, count);
+}
+
+void drd_barrier_destroy(const Addr barrier)
+{
+   struct barrier_info* p;
+
+   p = barrier_get(barrier);
+   if (p)
+   {
+      barrier_destroy(p);
+   }
+}
+
+void drd_barrier_pre_wait(const DrdThreadId tid, const Addr barrier)
+{
+   barrier_pre_wait(tid, barrier);
+}
+
+void drd_barrier_post_wait(const DrdThreadId tid, const Addr barrier,
+                           const Bool waited)
+{
+   barrier_post_wait(tid, barrier, waited);
+}
+
 
 //
 // Implementation of the tool interface.
@@ -686,7 +759,7 @@
    VG_(details_name)            ("exp-drd");
    VG_(details_version)         (NULL);
    VG_(details_description)     ("a data race detector");
-   VG_(details_copyright_author)("Copyright (C) 2006-2007, and GNU GPL'd,"
+   VG_(details_copyright_author)("Copyright (C) 2006-2008, and GNU GPL'd,"
                                  " by Bart Van Assche.");
    VG_(details_bug_reports_to)  (VG_BUGS_TO);
 
diff --git a/exp-drd/drd_malloc_wrappers.c b/exp-drd/drd_malloc_wrappers.c
index 205f473..55ae703 100644
--- a/exp-drd/drd_malloc_wrappers.c
+++ b/exp-drd/drd_malloc_wrappers.c
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/drd_malloc_wrappers.h b/exp-drd/drd_malloc_wrappers.h
index 8c9978e..ce3b93b 100644
--- a/exp-drd/drd_malloc_wrappers.h
+++ b/exp-drd/drd_malloc_wrappers.h
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/drd_mutex.c b/exp-drd/drd_mutex.c
index 304f365..39aec23 100644
--- a/exp-drd/drd_mutex.c
+++ b/exp-drd/drd_mutex.c
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/drd_mutex.h b/exp-drd/drd_mutex.h
index 180c7e1..b5b06e4 100644
--- a/exp-drd/drd_mutex.h
+++ b/exp-drd/drd_mutex.h
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/drd_segment.c b/exp-drd/drd_segment.c
index 06b4bbf..9d54dbb 100644
--- a/exp-drd/drd_segment.c
+++ b/exp-drd/drd_segment.c
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/drd_segment.h b/exp-drd/drd_segment.h
index 209ed16..46bca85 100644
--- a/exp-drd/drd_segment.h
+++ b/exp-drd/drd_segment.h
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/drd_semaphore.c b/exp-drd/drd_semaphore.c
new file mode 100644
index 0000000..c577196
--- /dev/null
+++ b/exp-drd/drd_semaphore.c
@@ -0,0 +1,187 @@
+/*
+  This file is part of drd, a data race detector.
+
+  Copyright (C) 2006-2008 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_error.h"
+#include "drd_semaphore.h"
+#include "drd_suppression.h"
+#include "priv_drd_clientreq.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_threadstate.h" // VG_(get_running_tid)()
+
+
+// Type definitions.
+
+struct semaphore_info
+{
+  Addr        semaphore;         // Pointer to client semaphore.
+  SizeT       size;              // Size in bytes of client-side object.
+  UWord       value;             // Semaphore value.
+  DrdThreadId last_sem_post_tid; // Thread ID associated with last sem_post().
+  VectorClock vc;                // Vector clock of last sem_post() call.
+};
+
+
+// Local variables.
+
+static Bool s_trace_semaphore;
+struct semaphore_info s_semaphore[256];
+
+
+// Function definitions.
+
+void semaphore_set_trace(const Bool trace_semaphore)
+{
+  s_trace_semaphore = trace_semaphore;
+}
+
+static
+void semaphore_initialize(struct semaphore_info* const p,
+                          const Addr semaphore,
+                          const SizeT size,
+                          const UWord value)
+{
+  tl_assert(semaphore != 0);
+  tl_assert(size > 0);
+
+  p->semaphore = semaphore;
+  p->size      = size;
+  p->value     = value;
+  p->last_sem_post_tid = DRD_INVALID_THREADID;
+  vc_init(&p->vc, 0, 0);
+}
+
+static
+struct semaphore_info*
+semaphore_get_or_allocate(const Addr semaphore, const SizeT size)
+{
+  int i;
+
+  for (i = 0; i < sizeof(s_semaphore)/sizeof(s_semaphore[0]); i++)
+  {
+    if (s_semaphore[i].semaphore == semaphore)
+    {
+      tl_assert(s_semaphore[i].size == size);
+      return &s_semaphore[i];
+    }
+  }
+  for (i = 0; i < sizeof(s_semaphore)/sizeof(s_semaphore[0]); i++)
+  {
+    if (s_semaphore[i].semaphore == 0)
+    {
+      semaphore_initialize(&s_semaphore[i], semaphore, size, 0);
+      drd_start_suppression(semaphore, semaphore + size, "semaphore");
+      return &s_semaphore[i];
+    }
+  }
+  tl_assert(0);
+  return 0;
+}
+
+struct semaphore_info* semaphore_init(const Addr semaphore, const SizeT size,
+                                      const Word pshared, const UWord value)
+{
+  struct semaphore_info* p;
+
+  tl_assert(semaphore_get(semaphore) == 0);
+  p = semaphore_get_or_allocate(semaphore, size);
+  p->value = value;
+  return p;
+}
+
+void semaphore_destroy(struct semaphore_info* const p)
+{
+  drd_finish_suppression(p->semaphore, p->semaphore + p->size);
+
+  vc_cleanup(&p->vc);
+  p->semaphore = 0;
+}
+
+struct semaphore_info* semaphore_get(const Addr semaphore)
+{
+  int i;
+  for (i = 0; i < sizeof(s_semaphore)/sizeof(s_semaphore[0]); i++)
+    if (s_semaphore[i].semaphore == semaphore)
+      return &s_semaphore[i];
+  return 0;
+}
+
+/** Called after sem_wait() finished successfully. */
+void semaphore_post_wait(const DrdThreadId tid, const Addr semaphore,
+                         const SizeT size)
+{
+  struct semaphore_info* p;
+
+  p = semaphore_get_or_allocate(semaphore, size);
+  tl_assert(p->value >= 0);
+  p->value--;
+  tl_assert(p->value >= 0);
+  if (p->last_sem_post_tid != tid)
+    thread_combine_vc2(tid, &p->vc);
+  thread_new_segment(tid);
+}
+
+/** Called before sem_post(). */
+void semaphore_pre_post(const DrdThreadId tid, const Addr semaphore,
+                        const SizeT size)
+{
+  struct semaphore_info* p;
+
+  p = semaphore_get_or_allocate(semaphore, size);
+  p->value++;
+  if (p->value == 1)
+  {
+    p->last_sem_post_tid = tid;
+  }
+}
+
+/** Called after sem_post() finished successfully. */
+void semaphore_post_post(const DrdThreadId tid, const Addr semaphore,
+                         const SizeT size)
+{
+  struct semaphore_info* p;
+
+  p = semaphore_get_or_allocate(semaphore, size);
+  thread_new_segment(tid);
+  vc_copy(&p->vc, thread_get_vc(tid));
+}
+
+void semaphore_thread_delete(const DrdThreadId threadid)
+{ }
+
+void semaphore_stop_using_mem(const Addr a1, const Addr a2)
+{
+  unsigned i;
+  for (i = 0; i < sizeof(s_semaphore)/sizeof(s_semaphore[0]); i++)
+  {
+    if (a1 <= s_semaphore[i].semaphore && s_semaphore[i].semaphore < a2)
+    {
+      tl_assert(s_semaphore[i].semaphore + s_semaphore[i].size <= a2);
+      semaphore_destroy(&s_semaphore[i]);
+    }
+  }
+}
diff --git a/exp-drd/drd_semaphore.h b/exp-drd/drd_semaphore.h
new file mode 100644
index 0000000..1562d34
--- /dev/null
+++ b/exp-drd/drd_semaphore.h
@@ -0,0 +1,56 @@
+/*
+  This file is part of drd, a data race detector.
+
+  Copyright (C) 2006-2008 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.
+*/
+
+
+// Semaphore state information: owner thread and recursion count.
+
+
+#ifndef __SEMAPHORE_H
+#define __SEMAPHORE_H
+
+
+#include "drd_thread.h"           // DrdThreadId
+#include "drd_vc.h"
+#include "pub_tool_basics.h"      // Addr, SizeT
+
+
+struct semaphore_info;
+
+
+void semaphore_set_trace(const Bool trace_semaphore);
+struct semaphore_info* semaphore_init(const Addr semaphore, const SizeT size,
+                                      const Word pshared, const UWord value);
+void semaphore_destroy(struct semaphore_info* const p);
+struct semaphore_info* semaphore_get(const Addr semaphore);
+void semaphore_post_wait(const DrdThreadId tid, const Addr semaphore,
+                         const SizeT size);
+void semaphore_pre_post(const DrdThreadId tid, const Addr semaphore,
+                        const SizeT size);
+void semaphore_post_post(const DrdThreadId tid, const Addr semaphore,
+                         const SizeT size);
+void semaphore_thread_delete(const DrdThreadId tid);
+void semaphore_stop_using_mem(const Addr a1, const Addr a2);
+
+
+#endif /* __SEMAPHORE_H */
diff --git a/exp-drd/drd_suppression.c b/exp-drd/drd_suppression.c
index 5fe25f7..1659784 100644
--- a/exp-drd/drd_suppression.c
+++ b/exp-drd/drd_suppression.c
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
@@ -24,12 +24,11 @@
 
 
 #include "drd_suppression.h"
-#include "pub_core_libcassert.h"
-#include "pub_core_libcprint.h"
-#include "pub_core_options.h"     // VG_(clo_backtrace_size)
 #include "pub_drd_bitmap.h"
+#include "pub_tool_libcassert.h"  // tl_assert()
 #include "pub_tool_stacktrace.h"  // VG_(get_and_pp_StackTrace)()
 #include "pub_tool_threadstate.h" // VG_(get_running_tid)()
+#include "pub_tool_libcprint.h"   // Vg_DebugMsg
 
 
 // Local variables.
@@ -72,16 +71,14 @@
   {
     VG_(message)(Vg_DebugMsg, "finish suppression of 0x%lx sz %ld",
                  a1, a2 - a1);
-    VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
-                               VG_(clo_backtrace_size));   
+    VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 12);   
   }
 
   tl_assert(a1 < a2);
   if (! drd_is_suppressed(a1, a2))
   {
      VG_(message)(Vg_DebugMsg, "?? not suppressed ??");
-     VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
-                                VG_(clo_backtrace_size));   
+     VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 12);
      tl_assert(False);
   }
   bm_clear(s_suppressed, a1, a2);
@@ -119,7 +116,6 @@
         VG_(message)(Vg_DebugMsg,
                      "stop_using_mem(0x%lx, %ld) finish suppression of 0x%lx",
                      a1, a2 - a1, b);
-        //VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), VG_(clo_backtrace_size));   
       }
     }
   }
diff --git a/exp-drd/drd_thread.c b/exp-drd/drd_thread.c
index 4277e1b..4da1f02 100644
--- a/exp-drd/drd_thread.c
+++ b/exp-drd/drd_thread.c
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
@@ -27,7 +27,6 @@
 #include "drd_segment.h"
 #include "drd_suppression.h"
 #include "drd_thread.h"
-#include "pub_core_options.h"     // VG_(clo_backtrace_size)
 #include "pub_tool_basics.h"      // Addr, SizeT
 #include "pub_tool_errormgr.h"    // VG_(unique_error)()
 #include "pub_tool_libcassert.h"  // tl_assert()
@@ -35,6 +34,7 @@
 #include "pub_tool_libcprint.h"   // VG_(printf)()
 #include "pub_tool_machine.h"
 #include "pub_tool_mallocfree.h"  // VG_(malloc)(), VG_(free)()
+#include "pub_tool_options.h"     // VG_(clo_backtrace_size)
 #include "pub_tool_threadstate.h" // VG_(get_pthread_id)()
 
 
diff --git a/exp-drd/drd_thread.h b/exp-drd/drd_thread.h
index cf3cbf6..30342f4 100644
--- a/exp-drd/drd_thread.h
+++ b/exp-drd/drd_thread.h
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/drd_track.h b/exp-drd/drd_track.h
index 4a8e564..4ffcd6e 100644
--- a/exp-drd/drd_track.h
+++ b/exp-drd/drd_track.h
@@ -1,4 +1,30 @@
+/*
+  This file is part of drd, a data race detector.
+
+  Copyright (C) 2006-2008 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.
+*/
+
+
 void drd_post_thread_join(DrdThreadId joiner, DrdThreadId joinee);
+
 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(DrdThreadId tid, Addr mutex, const SizeT size,
@@ -7,5 +33,22 @@
                          const MutexT mutex_type);
 void drd_pre_mutex_unlock(const DrdThreadId tid, const Addr mutex,
                           const MutexT mutex_type);
+
 void drd_post_cond_init(Addr cond, SizeT s);
 void drd_pre_cond_destroy(Addr cond);
+
+void drd_semaphore_init(const Addr semaphore, const SizeT size,
+                        const Word pshared, const Word value);
+void drd_semaphore_destroy(const Addr semaphore);
+void drd_semaphore_post_wait(const DrdThreadId tid, const Addr semaphore,
+                             const SizeT size);
+void drd_semaphore_pre_post(const DrdThreadId tid, const Addr semaphore,
+                            const SizeT size);
+void drd_semaphore_post_post(const DrdThreadId tid, const Addr semaphore,
+                             const SizeT size);
+
+void drd_barrier_init(const Addr barrier, const SizeT size, const Word count);
+void drd_barrier_destroy(const Addr barrier);
+void drd_barrier_pre_wait(const DrdThreadId tid, const Addr barrier);
+void drd_barrier_post_wait(const DrdThreadId tid, const Addr barrier,
+                           const Bool waited);
diff --git a/exp-drd/drd_vc.c b/exp-drd/drd_vc.c
index 92f0474..558595a 100644
--- a/exp-drd/drd_vc.c
+++ b/exp-drd/drd_vc.c
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/drd_vc.h b/exp-drd/drd_vc.h
index dd2b6db..2cbf3bd 100644
--- a/exp-drd/drd_vc.h
+++ b/exp-drd/drd_vc.h
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
@@ -50,14 +50,14 @@
 typedef struct
 {
   ThreadId threadid;
-  UInt count;
+  UInt     count;
 } VCElem;
 
 typedef struct
 {
-  unsigned       capacity;
-  unsigned       size;
-  VCElem* vc;
+  unsigned capacity;
+  unsigned size;
+  VCElem*  vc;
 } VectorClock;
 
 
diff --git a/exp-drd/priv_drd_clientreq.h b/exp-drd/priv_drd_clientreq.h
index 0e63b0e..2b566b6 100644
--- a/exp-drd/priv_drd_clientreq.h
+++ b/exp-drd/priv_drd_clientreq.h
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/pub_drd_bitmap.h b/exp-drd/pub_drd_bitmap.h
index 6f6b867..f0afffc 100644
--- a/exp-drd/pub_drd_bitmap.h
+++ b/exp-drd/pub_drd_bitmap.h
@@ -1,7 +1,7 @@
 /*
   This file is part of drd, a data race detector.
 
-  Copyright (C) 2006-2007 Bart Van Assche
+  Copyright (C) 2006-2008 Bart Van Assche
   bart.vanassche@gmail.com
 
   This program is free software; you can redistribute it and/or
diff --git a/exp-drd/tests/Makefile.am b/exp-drd/tests/Makefile.am
index a62b3aa..4e68ed3 100644
--- a/exp-drd/tests/Makefile.am
+++ b/exp-drd/tests/Makefile.am
@@ -15,6 +15,8 @@
 	fp_race.stderr.exp2                                     \
 	fp_race2.vgtest                                         \
 	fp_race2.stdout.exp fp_race2.stderr.exp                 \
+	matinv.vgtest                                           \
+	matinv.stdout.exp matinv.stderr.exp                     \
 	pth_broadcast.vgtest                                    \
 	pth_broadcast.stdout.exp pth_broadcast.stderr.exp       \
 	pth_cond_race.vgtest                                    \
@@ -27,6 +29,15 @@
 	pth_detached.stdout.exp pth_detached.stderr.exp         \
 	pth_detached2.vgtest                                    \
 	pth_detached2.stdout.exp pth_detached2.stderr.exp       \
+	sem_as_mutex.vgtest                                     \
+	sem_as_mutex.stdout.exp sem_as_mutex.stderr.exp         \
+	sem_as_mutex.stderr.exp2                                \
+	sem_as_mutex2.vgtest                                    \
+	sem_as_mutex2.stdout.exp sem_as_mutex2.stderr.exp       \
+	tc17_sembar.vgtest                                      \
+	tc17_sembar.stdout.exp tc17_sembar.stderr.exp           \
+	tc18_semabuse.vgtest                                    \
+	tc18_semabuse.stdout.exp tc18_semabuse.stderr.exp       \
 	sigalrm.vgtest                                          \
 	sigalrm.stdout.exp sigalrm.stderr.exp
 
@@ -36,26 +47,42 @@
 
 check_PROGRAMS =   \
   fp_race          \
+  matinv           \
   pth_broadcast    \
   pth_cond_race    \
   pth_create_chain \
   pth_detached     \
-  sigalrm
+  sem_as_mutex     \
+  sigalrm          \
+  tc17_sembar      \
+  tc18_semabuse
 
-fp_race_SOURCES       = fp_race.c
-fp_race_LDADD         = -lpthread
+fp_race_SOURCES          = fp_race.c
+fp_race_LDADD            = -lpthread
 
-pth_broadcast_SOURCES = pth_broadcast.c
-pth_broadcast_LDADD   = -lpthread
+matinv_SOURCES           = matinv.c
+matinv_LDADD             = -lpthread -lm
 
-pth_cond_race_SOURCES = pth_cond_race.c
-pth_cond_race_LDADD   = -lpthread
+pth_broadcast_SOURCES    = pth_broadcast.c
+pth_broadcast_LDADD      = -lpthread
+
+pth_cond_race_SOURCES    = pth_cond_race.c
+pth_cond_race_LDADD      = -lpthread
 
 pth_create_chain_SOURCES = pth_create_chain.c
 pth_create_chain_LDADD   = -lpthread
 
-pth_detached_SOURCES  = pth_detached.c
-pth_detached_LDADD    = -lpthread
+pth_detached_SOURCES     = pth_detached.c
+pth_detached_LDADD       = -lpthread
 
-sigalrm_SOURCES       = sigalrm.c
-sigalrm_LDADD         = -lpthread
+sem_as_mutex_SOURCES     = sem_as_mutex.c
+sem_as_mutex_LDADD       = -lpthread
+
+sigalrm_SOURCES          = sigalrm.c
+sigalrm_LDADD            = -lpthread
+
+tc17_sembar_SOURCES      = ../../helgrind/tests/tc17_sembar.c
+tc17_sembar_LDADD        = -lpthread
+
+tc18_semabuse_SOURCES    = ../../helgrind/tests/tc18_semabuse.c
+tc18_semabuse_LDADD      = -lpthread
diff --git a/exp-drd/tests/matinv.c b/exp-drd/tests/matinv.c
new file mode 100644
index 0000000..dad8dd3
--- /dev/null
+++ b/exp-drd/tests/matinv.c
@@ -0,0 +1,339 @@
+/* Compute the matrix inverse via Gauss-Jordan elimination.
+ * This program uses only barriers to separate computation steps but no
+ * mutexes. It is an example of a race-free program on which no data races
+ * are reported by the happens-before algorithm (drd), but a lot of data races
+ * (all false positives) are reported by the Eraser-algorithm (helgrind).
+ */
+
+
+/***********************/
+/* Include directives. */
+/***********************/
+
+#include <assert.h>
+#include <math.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+/*********************/
+/* Type definitions. */
+/*********************/
+
+typedef double elem_t;
+
+struct gj_threadinfo
+{
+  pthread_barrier_t* b;
+  pthread_t tid;
+  elem_t* a;
+  int rows;
+  int cols;
+  int r0;
+  int r1;
+};
+
+
+/********************/
+/* Local variables. */
+/********************/
+
+static int s_nthread;
+
+
+/*************************/
+/* Function definitions. */
+/*************************/
+
+/** Allocate memory for a matrix with the specified number of rows and
+ *  columns.
+ */
+static elem_t* new_matrix(const int rows, const int cols)
+{
+  assert(rows > 0);
+  assert(cols > 0);
+  return malloc(rows * cols * sizeof(elem_t));
+}
+
+/** Free the memory that was allocated for a matrix. */
+static void delete_matrix(elem_t* const a)
+{
+  free(a);
+}
+
+/** Fill in some numbers in a matrix.
+ *  @note It is important not to call srand() in this program, such that
+ *        the results of a run are reproducible.
+ */
+static void init_matrix(elem_t* const a, const int rows, const int cols)
+{
+  int i, j;
+  for (i = 0; i < rows; i++)
+  {
+    for (j = 0; j < rows; j++)
+    {
+      a[i * cols + j] = rand() * 1.0 / RAND_MAX;
+    }
+  }
+}
+
+/** Print all elements of a matrix. */
+void print_matrix(const char* const label,
+                  const elem_t* const a, const int rows, const int cols)
+{
+  int i, j;
+  printf("%s:\n", label);
+  for (i = 0; i < rows; i++)
+  {
+    for (j = 0; j < cols; j++)
+    {
+      printf("%g ", a[i * cols + j]);
+    }
+    printf("\n");
+  }
+}
+
+/** Copy a subset of the elements of a matrix into another matrix. */
+static void copy_matrix(const elem_t* const from,
+                        const int from_rows,
+                        const int from_cols,
+                        const int from_row_first,
+                        const int from_row_last,
+                        const int from_col_first,
+                        const int from_col_last,
+                        elem_t* const to,
+                        const int to_rows,
+                        const int to_cols,
+                        const int to_row_first,
+                        const int to_row_last,
+                        const int to_col_first,
+                        const int to_col_last)
+{
+  int i, j;
+
+  assert(from_row_last - from_row_first == to_row_last - to_row_first);
+  assert(from_col_last - from_col_first == to_col_last - to_col_first);
+
+  for (i = from_row_first; i < from_row_last; i++)
+  {
+    assert(i < from_rows);
+    assert(i - from_row_first + to_row_first < to_rows);
+    for (j = from_col_first; j < from_col_last; j++)
+    {
+      assert(j < from_cols);
+      assert(j - from_col_first + to_col_first < to_cols);
+      to[(i - from_row_first + to_col_first) * to_cols
+         + (j - from_col_first + to_col_first)]
+        = from[i * from_cols + j];
+    }
+  }
+}
+
+/** Compute the matrix product of a1 and a2. */
+static elem_t* multiply_matrices(const elem_t* const a1,
+                                 const int rows1,
+                                 const int cols1,
+                                 const elem_t* const a2,
+                                 const int rows2,
+                                 const int cols2)
+{
+  int i, j, k;
+  elem_t* prod;
+
+  assert(cols1 == rows2);
+
+  prod = new_matrix(rows1, cols2);
+  for (i = 0; i < rows1; i++)
+  {
+    for (j = 0; j < cols2; j++)
+    {
+      prod[i * cols2 + j] = 0;
+      for (k = 0; k < cols1; k++)
+      {
+        prod[i * cols2 + j] += a1[i * cols1 + k] * a2[k * cols2 + j];
+      }
+    }
+  }
+  return prod;
+}
+
+/** Apply the Gauss-Jordan elimination algorithm on the matrix p->a starting
+ *  at row r0 and up to but not including row r1. It is assumed that as many
+ *  threads execute this function concurrently as the count barrier p->b was 
+ *  initialized with. If the matrix p->a is nonsingular, and if matrix p->a
+ *  has at least as many columns as rows, the result of this algorithm is that
+ *  submatrix p->a[0..p->rows-1,0..p->rows-1] is the identity matrix.
+ * @see http://en.wikipedia.org/wiki/Gauss-Jordan_elimination
+ */
+static void gj_threadfunc(struct gj_threadinfo* p)
+{
+  int i, j, k;
+  elem_t* const a = p->a;
+  const int rows = p->rows;
+  const int cols = p->cols;
+
+  for (i = 0; i < p->rows; i++)
+  {
+    if (pthread_barrier_wait(p->b) == PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      // Pivoting.
+      j = i;
+      for (k = i + 1; k < rows; k++)
+      {
+        if (a[k * cols + i] > a[j * cols + i])
+        {
+          j = k;
+        }
+      }
+      if (j != i)
+      {
+        for (k = 0; k < cols; k++)
+        {
+          const elem_t t = a[i * cols + k];
+          a[i * cols + k] = a[j * cols + k];
+          a[j * cols + k] = t;
+        }
+      }
+      // Normalize row i.
+      if (a[i * cols + i] != 0)
+      {
+        for (k = cols - 1; k >= 0; k--)
+        {
+          a[i * cols + k] /= a[i * cols + i];
+        }
+      }
+    }
+    pthread_barrier_wait(p->b);
+    // Reduce all rows j != i.
+    for (j = p->r0; j < p->r1; j++)
+    {
+      if (i != j)
+      {
+        const elem_t factor = a[j * cols + i];
+        for (k = 0; k < cols; k++)
+        {
+          a[j * cols + k] -= a[i * cols + k] * factor;
+        }
+      }
+    }
+  }
+}
+
+/** Multithreaded Gauss-Jordan algorithm. */
+static void gj(elem_t* const a, const int rows, const int cols)
+{
+  int i;
+  struct gj_threadinfo* t;
+  pthread_barrier_t b;
+
+  assert(rows <= cols);
+
+  t = malloc(sizeof(struct gj_threadinfo) * s_nthread);
+
+  pthread_barrier_init(&b, 0, s_nthread);
+
+  for (i = 0; i < s_nthread; i++)
+  {
+    t[i].b = &b;
+    t[i].a = a;
+    t[i].rows = rows;
+    t[i].cols = cols;
+    t[i].r0 = i * rows / s_nthread;
+    t[i].r1 = (i+1) * rows / s_nthread;
+    pthread_create(&t[i].tid, 0, (void*(*)(void*))gj_threadfunc, &t[i]);
+  }
+
+  for (i = 0; i < s_nthread; i++)
+  {
+    pthread_join(t[i].tid, 0);
+  }
+
+  pthread_barrier_destroy(&b);
+
+  free(t);
+}
+
+/** Matrix inversion via the Gauss-Jordan algorithm. */
+static elem_t* invert_matrix(const elem_t* const a, const int n)
+{
+  int i, j;
+  elem_t* const inv = new_matrix(n, n);
+  elem_t* const tmp = new_matrix(n, 2*n);
+  copy_matrix(a, n, n, 0, n, 0, n, tmp, n, 2 * n, 0, n, 0, n);
+  for (i = 0; i < n; i++)
+    for (j = 0; j < n; j++)
+      tmp[i * 2 * n + n + j] = (i == j);
+  gj(tmp, n, 2*n);
+  copy_matrix(tmp, n, 2*n, 0, n, n, 2*n, inv, n, n, 0, n, 0, n);
+  delete_matrix(tmp);
+  return inv;
+}
+
+/** Compute the average square error between the identity matrix and the
+ * product of matrix a with its inverse matrix.
+ */
+static double identity_error(const elem_t* const a, const int n)
+{
+  int i, j;
+  elem_t e = 0;
+  for (i = 0; i < n; i++)
+  {
+    for (j = 0; j < n; j++)
+    {
+      const elem_t d = a[i * n + j] - (i == j);
+      e += d * d;
+    }
+  }
+  return sqrt(e / (n * n));
+}
+
+/** Compute epsilon for the numeric type elem_t. Epsilon is defined as the
+ *  smallest number for which the sum of one and that number is different of
+ *  one. It is assumed that the underlying representation of elem_t uses
+ *  base two.
+ */
+static elem_t epsilon()
+{
+  elem_t eps;
+  for (eps = 1; 1 + eps != 1; eps /= 2)
+    ;
+  return 2 * eps;
+}
+
+int main(int argc, char** argv)
+{
+  int matrix_size;
+  int silent;
+  elem_t *a, *inv, *prod;
+  elem_t eps;
+  double error;
+  double ratio;
+
+  matrix_size = (argc > 1) ? atoi(argv[1]) : 3;
+  s_nthread = (argc > 2) ? atoi(argv[2]) : 3;
+  silent = (argc > 3) ? atoi(argv[3]) : 0;
+
+  eps = epsilon();
+  a = new_matrix(matrix_size, matrix_size);
+  init_matrix(a, matrix_size, matrix_size);
+  inv = invert_matrix(a, matrix_size);
+  prod = multiply_matrices(a, matrix_size, matrix_size,
+                           inv, matrix_size, matrix_size);
+  error = identity_error(prod, matrix_size);
+  ratio = error / (eps * matrix_size);
+  if (! silent)
+  {
+    printf("error = %g; epsilon = %g; error / (epsilon * n) = %g\n",
+           error, eps, ratio);
+  }
+  if (ratio < 100)
+    printf("Error within bounds.\n");
+  else
+    printf("Error out of bounds.\n");
+  delete_matrix(prod);
+  delete_matrix(inv);
+  delete_matrix(a);
+
+  return 0;
+}
diff --git a/exp-drd/tests/matinv.stderr.exp b/exp-drd/tests/matinv.stderr.exp
new file mode 100644
index 0000000..d18786f
--- /dev/null
+++ b/exp-drd/tests/matinv.stderr.exp
@@ -0,0 +1,3 @@
+
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/exp-drd/tests/matinv.stdout.exp b/exp-drd/tests/matinv.stdout.exp
new file mode 100644
index 0000000..3035da4
--- /dev/null
+++ b/exp-drd/tests/matinv.stdout.exp
@@ -0,0 +1 @@
+Error within bounds.
diff --git a/exp-drd/tests/matinv.vgtest b/exp-drd/tests/matinv.vgtest
new file mode 100644
index 0000000..b5fc59c
--- /dev/null
+++ b/exp-drd/tests/matinv.vgtest
@@ -0,0 +1,2 @@
+prog: matinv
+args: 30 15 1
diff --git a/exp-drd/tests/sem_as_mutex.c b/exp-drd/tests/sem_as_mutex.c
new file mode 100644
index 0000000..24b01ff
--- /dev/null
+++ b/exp-drd/tests/sem_as_mutex.c
@@ -0,0 +1,140 @@
+/*
+  This file is part of drd, a data race detector.
+
+  Copyright (C) 2006-2007 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.
+*/
+
+// Use a semaphore to implement mutual exclusion.
+
+#include <assert.h>
+#include <stdio.h>      // printf()
+#include <pthread.h>
+#include <semaphore.h>
+#include <unistd.h>    // usleep()
+#include "../drd_clientreq.h"
+
+
+// Local functions declarations.
+
+static void* thread_func(void*);
+
+// Local variables.
+
+// s_sem protects s_d3.
+static sem_t s_sem;
+
+static double s_d1; // accessed before thread creation and in the created
+                    // thread (not a race).
+static double s_d2; // accessed in the created thread and after the join
+                    // (not a race).
+static double s_d3; // accessed simultaneously from both threads (race).
+static int    s_debug     = 0;
+static int    s_do_printf = 0;
+static int    s_do_mutual_exclusion = 0;
+
+
+// Function definitions.
+
+static void set_thread_name(const char* const name)
+{
+  int res;
+  VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__SET_THREAD_NAME,
+                             name, 0, 0, 0, 0);
+}
+
+int main(int argc, char** argv)
+{
+  int optchar;
+  pthread_t threadid;
+
+  set_thread_name("main");
+
+  while ((optchar = getopt(argc, argv, "dmp")) != EOF)
+  {
+    switch (optchar)
+    {
+    case 'd':
+      s_debug = 1;
+      break;
+    case 'm':
+      s_do_mutual_exclusion = 1;
+      break;
+    case 'p':
+      s_do_printf = 1;
+      break;
+    default:
+      assert(0);
+    }
+  }
+
+  sem_init(&s_sem, 0, 1);
+
+  // Switch to line-buffered mode, such that timing information can be 
+  // obtained for each printf() call with strace.
+  setlinebuf(stdout);
+
+  if (s_debug)
+  {
+    printf("&s_d1 = %p; &s_d2 = %p; &s_d3 = %p\n", &s_d1, &s_d2, &s_d3);
+  }
+
+  s_d1 = 1;
+  s_d3 = 3;
+
+  pthread_create(&threadid, 0, thread_func, 0);
+  // Wait until the printf() in the created thread finished.
+
+  {
+    if (s_do_mutual_exclusion) sem_wait(&s_sem);
+    s_d3++;
+    if (s_do_mutual_exclusion) sem_post(&s_sem);
+  }
+
+  // Wait until the thread finished.
+  //printf("Before call to pthread_join()\n");
+  //fflush(stdout);
+  pthread_join(threadid, 0);
+  //printf("After call to pthread_join()\n");
+  //fflush(stdout);
+  if (s_do_printf) printf("s_d2 = %g (should be 2)\n", s_d2);
+  if (s_do_printf) printf("s_d3 = %g (should be 5)\n", s_d3);
+
+  sem_destroy(&s_sem);
+
+  return 0;
+}
+
+static void* thread_func(void* thread_arg)
+{
+  set_thread_name("thread_func");
+
+  if (s_do_printf)
+  {
+    printf("s_d1 = %g (should be 1)\n", s_d1);
+  }
+  s_d2 = 2;
+  {
+    if (s_do_mutual_exclusion) sem_wait(&s_sem);
+    s_d3++;
+    if (s_do_mutual_exclusion) sem_post(&s_sem);
+  }
+  return 0;
+}
diff --git a/exp-drd/tests/sem_as_mutex.stderr.exp b/exp-drd/tests/sem_as_mutex.stderr.exp
new file mode 100644
index 0000000..c2a2f32
--- /dev/null
+++ b/exp-drd/tests/sem_as_mutex.stderr.exp
@@ -0,0 +1,18 @@
+
+Conflicting load by main at 0x........ size 8
+   at 0x........: main (sem_as_mutex.c:?)
+Allocation context: s_d3 (offset 0, size 8) in sem_as_mutex, NONE:BSS
+Other segment start (thread_func)
+   (thread finished, call stack no longer available)
+Other segment end (thread_func)
+   (thread finished, call stack no longer available)
+
+Conflicting store by main at 0x........ size 8
+   at 0x........: main (sem_as_mutex.c:?)
+Allocation context: s_d3 (offset 0, size 8) in sem_as_mutex, NONE:BSS
+Other segment start (thread_func)
+   (thread finished, call stack no longer available)
+Other segment end (thread_func)
+   (thread finished, call stack no longer available)
+
+ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
diff --git a/exp-drd/tests/sem_as_mutex.stderr.exp2 b/exp-drd/tests/sem_as_mutex.stderr.exp2
new file mode 100644
index 0000000..8c39609
--- /dev/null
+++ b/exp-drd/tests/sem_as_mutex.stderr.exp2
@@ -0,0 +1,18 @@
+
+Conflicting load by main at 0x........ size 8
+   at 0x........: main (sem_as_mutex.c:?)
+Allocation context: unknown
+Other segment start (thread_func)
+   (thread finished, call stack no longer available)
+Other segment end (thread_func)
+   (thread finished, call stack no longer available)
+
+Conflicting store by main at 0x........ size 8
+   at 0x........: main (sem_as_mutex.c:?)
+Allocation context: unknown
+Other segment start (thread_func)
+   (thread finished, call stack no longer available)
+Other segment end (thread_func)
+   (thread finished, call stack no longer available)
+
+ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
diff --git a/exp-drd/tests/sem_as_mutex.vgtest b/exp-drd/tests/sem_as_mutex.vgtest
new file mode 100644
index 0000000..1db7bd3
--- /dev/null
+++ b/exp-drd/tests/sem_as_mutex.vgtest
@@ -0,0 +1 @@
+prog: sem_as_mutex
diff --git a/exp-drd/tests/sem_as_mutex2.stderr.exp b/exp-drd/tests/sem_as_mutex2.stderr.exp
new file mode 100644
index 0000000..d18786f
--- /dev/null
+++ b/exp-drd/tests/sem_as_mutex2.stderr.exp
@@ -0,0 +1,3 @@
+
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/exp-drd/tests/sem_as_mutex2.vgtest b/exp-drd/tests/sem_as_mutex2.vgtest
new file mode 100644
index 0000000..6afcb28
--- /dev/null
+++ b/exp-drd/tests/sem_as_mutex2.vgtest
@@ -0,0 +1,2 @@
+prog: sem_as_mutex
+args: -m
diff --git a/exp-drd/tests/tc17_sembar.stderr.exp b/exp-drd/tests/tc17_sembar.stderr.exp
new file mode 100644
index 0000000..b3f318e
--- /dev/null
+++ b/exp-drd/tests/tc17_sembar.stderr.exp
@@ -0,0 +1,5 @@
+
+starting
+done, result is 88, should be 88
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/exp-drd/tests/tc17_sembar.vgtest b/exp-drd/tests/tc17_sembar.vgtest
new file mode 100644
index 0000000..643ed8a
--- /dev/null
+++ b/exp-drd/tests/tc17_sembar.vgtest
@@ -0,0 +1 @@
+prog: tc17_sembar
diff --git a/exp-drd/tests/tc18_semabuse.stderr.exp b/exp-drd/tests/tc18_semabuse.stderr.exp
new file mode 100644
index 0000000..d18786f
--- /dev/null
+++ b/exp-drd/tests/tc18_semabuse.stderr.exp
@@ -0,0 +1,3 @@
+
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/exp-drd/tests/tc18_semabuse.vgtest b/exp-drd/tests/tc18_semabuse.vgtest
new file mode 100644
index 0000000..fe4d22b
--- /dev/null
+++ b/exp-drd/tests/tc18_semabuse.vgtest
@@ -0,0 +1 @@
+prog: tc18_semabuse