From: Julian Seward Date: Mon, 14 Jan 2008 11:54:56 +0000 (+0000) Subject: DRD updates (Bart Van Assche): X-Git-Tag: svn/VALGRIND_3_4_0~1102 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=22b3fe2a3e36500b309a6da583ff6225f6efc89a;p=thirdparty%2Fvalgrind.git 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 --- diff --git a/exp-drd/Makefile.am b/exp-drd/Makefile.am index 8f18c66c2b..e9627f3608 100644 --- a/exp-drd/Makefile.am +++ b/exp-drd/Makefile.am @@ -67,6 +67,7 @@ vgpreload_exp_drd_ppc64_aix5_so_LDFLAGS = $(PRELOAD_LDFLAGS_PPC64_AIX5) DRD_SOURCES_COMMON = \ + drd_barrier.c \ drd_bitmap.c \ drd_clientreq.c \ drd_cond.c \ @@ -75,23 +76,27 @@ DRD_SOURCES_COMMON = \ 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_CFLAGS = $(AM_CFLAGS_PPC64_AIX5) 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 ffabe8d49d..123226e468 100644 --- a/exp-drd/TODO.txt +++ b/exp-drd/TODO.txt @@ -4,29 +4,22 @@ Last updated February 22, 2006 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 @@ Testing 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 0000000000..134614273c --- /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 0000000000..edd42359a9 --- /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 21d9bb377b..d1710372fc 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 248a5d29c9..d70252f537 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 @@ static __inline__ 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 @@ static __inline__ 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 d77c741dee..ac4b04592c 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 @@ static Bool drd_handle_client_request(ThreadId tid, UWord* arg, UWord* ret) 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 e07f008488..4d7d4f3457 100644 --- a/exp-drd/drd_clientreq.h +++ b/exp-drd/drd_clientreq.h @@ -52,29 +52,29 @@ enum { 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 @@ enum { 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 83db465b63..6fdd912755 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 @@ void cond_pre_broadcast(Addr const cond) 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 9912c83c31..8a27449876 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 @@ struct cond_info 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 6ec58e6f7f..23008d1faf 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 dc9ed1c276..c298df8219 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 a0c6a1a84e..675eec44d4 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 #include // uintptr_t +#include +#include #include #include -#include #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 @@ static void vg_set_joinable(const pthread_t tid, const int joinable) { 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 @@ PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@* #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 @@ PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock 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 @@ PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock 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 9cc7f1244e..d4634ffc73 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 @@ static void drd_set_running_tid(const ThreadId tid); // 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 Addr drd_trace_address = 0; 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 @@ static Bool drd_process_cmd_line_option(Char* arg) 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 @@ static Bool drd_process_cmd_line_option(Char* arg) 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 @@ VG_REGPARM(2) void drd_trace_load(Addr addr, SizeT size) 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_REGPARM(2) void drd_trace_store(Addr addr, SizeT size) 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 @@ static void drd_start_using_mem(const Addr a1, const Addr a2) 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 @@ static void drd_stop_using_mem(const Addr a1, const Addr a2) 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 @@ void drd_post_thread_join(DrdThreadId drd_joiner, DrdThreadId drd_joinee) 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 @@ void drd_post_mutex_destroy(Addr mutex, MutexT mutex_type) 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_pre_cond_destroy(Addr cond) } } +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 @@ void drd_pre_clo_init(void) 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 205f473bcd..55ae703f17 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 8c9978ebf0..ce3b93b07c 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 304f36531a..39aec2374d 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 180c7e1744..b5b06e4834 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 06b4bbf7a2..9d54dbb144 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 209ed160e4..46bca857d2 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 0000000000..c5771964c3 --- /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 0000000000..1562d342f3 --- /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 5fe25f7e99..1659784012 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 @@ void drd_finish_suppression(const Addr a1, const Addr a2) { 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 @@ void drd_suppression_stop_using_mem(const Addr a1, const Addr a2) 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 4277e1b2ee..4da1f024f3 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 cf3cbf6bf3..30342f43ee 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 4a8e564f69..4ffcd6e16d 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 @@ void drd_post_mutex_lock(DrdThreadId tid, Addr mutex, const SizeT size, 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 92f0474c8f..558595a64d 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 dd2b6db665..2cbf3bd17f 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 0e63b0ea9e..2b566b699a 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 6f6b867fa6..f0afffcfa7 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 a62b3aa508..4e68ed311c 100644 --- a/exp-drd/tests/Makefile.am +++ b/exp-drd/tests/Makefile.am @@ -15,6 +15,8 @@ EXTRA_DIST = $(noinst_SCRIPTS) \ 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 @@ EXTRA_DIST = $(noinst_SCRIPTS) \ 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 @@ AM_CXXFLAGS = $(AM_CFLAGS) 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 + +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 -sigalrm_SOURCES = sigalrm.c -sigalrm_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 0000000000..dad8dd3ea0 --- /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 +#include +#include +#include +#include + + +/*********************/ +/* 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 0000000000..d18786f806 --- /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 0000000000..3035da459d --- /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 0000000000..b5fc59c172 --- /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 0000000000..24b01ff4f1 --- /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 +#include // printf() +#include +#include +#include // 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 0000000000..c2a2f3265e --- /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 0000000000..8c396090a9 --- /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 0000000000..1db7bd3a41 --- /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 0000000000..d18786f806 --- /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 0000000000..6afcb28200 --- /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 0000000000..b3f318ea93 --- /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 0000000000..643ed8ab3b --- /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 0000000000..d18786f806 --- /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 0000000000..fe4d22ba17 --- /dev/null +++ b/exp-drd/tests/tc18_semabuse.vgtest @@ -0,0 +1 @@ +prog: tc18_semabuse