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