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