From aaef6d016e02da77a498b1ad1ba2744800e603f0 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sat, 21 Feb 2009 15:27:04 +0000 Subject: [PATCH] Changes: - pthread_barrier_wait() intercept now passes the information to the DRD tool whether or not this function returned PTHREAD_BARRIER_SERIAL_THREAD. This information is now displayed when the command-line option --trace-barrier=yes has been specified. - Changed the cleanup functions for client objects that are called just before a thread stops into callback functions. - Added DRD_(clientobj_delete_thread)(). - Removed DRD_(clientobj_resetiter)(void) and DRD_(clientobj_next)(). - Added test for race conditions between pthread_barrier_wait() and pthread_barrier_destroy() calls. An error message is now printed if this condition has been detected. - Bug fix: pthread_barrier_delete() calls on barriers being waited upon are now reported. - Removed DRD_() wrapper from around the name of some static variables and functions. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@9211 --- drd/drd_barrier.c | 307 +++++++++++++++++++++++------------ drd/drd_barrier.h | 4 +- drd/drd_clientobj.c | 125 +++++++------- drd/drd_clientobj.h | 19 ++- drd/drd_clientreq.c | 2 +- drd/drd_clientreq.h | 2 +- drd/drd_cond.c | 11 +- drd/drd_cond.h | 1 - drd/drd_error.c | 84 +++++----- drd/drd_error.h | 4 +- drd/drd_mutex.c | 79 +++++---- drd/drd_mutex.h | 1 - drd/drd_pthread_intercepts.c | 10 +- drd/drd_rwlock.c | 40 +++-- drd/drd_rwlock.h | 1 - drd/drd_semaphore.c | 30 ++-- drd/drd_semaphore.h | 1 - drd/drd_thread.c | 6 +- 18 files changed, 420 insertions(+), 307 deletions(-) diff --git a/drd/drd_barrier.c b/drd/drd_barrier.c index 1807f5d14b..e20447f221 100644 --- a/drd/drd_barrier.c +++ b/drd/drd_barrier.c @@ -40,57 +40,75 @@ /** Information associated with one thread participating in a barrier. */ struct barrier_thread_info { - UWord tid; // A DrdThreadId + UWord tid; // A DrdThreadId declared as UWord because + // this member variable is the key of an OSet. Word iteration; // iteration of last pthread_barrier_wait() // call thread tid participated in. Segment* sg[2]; // Segments of the last two // 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 }; /* Local functions. */ -static void DRD_(barrier_cleanup)(struct barrier_info* p); -static const char* DRD_(barrier_get_typename)(struct barrier_info* const p); -static const char* DRD_(barrier_type_name)(const BarrierT bt); +static void barrier_cleanup(struct barrier_info* p); +static void barrier_delete_thread(struct barrier_info* const p, + const DrdThreadId tid); +static const char* barrier_get_typename(struct barrier_info* const p); +static const char* barrier_type_name(const BarrierT bt); +static +void barrier_report_wait_delete_race(const struct barrier_info* const p, + const struct barrier_thread_info* const q); /* Local variables. */ -static Bool DRD_(s_trace_barrier) = False; -static ULong DRD_(s_barrier_segment_creation_count); +static Bool s_trace_barrier = False; +static ULong s_barrier_segment_creation_count; /* Function definitions. */ void DRD_(barrier_set_trace)(const Bool trace_barrier) { - DRD_(s_trace_barrier) = trace_barrier; + s_trace_barrier = trace_barrier; } -/** Initialize the structure *p with the specified thread ID and iteration - * information. */ +/** + * Initialize the structure *p with the specified thread ID and iteration + * information. + */ static void DRD_(barrier_thread_initialize)(struct barrier_thread_info* const p, const DrdThreadId tid, const Word iteration) { - p->tid = tid; - p->iteration = iteration; - p->sg[0] = 0; - p->sg[1] = 0; + p->tid = tid; + p->iteration = iteration; + p->sg[0] = 0; + p->sg[1] = 0; + p->wait_call_ctxt = 0; + p->post_wait_sg = 0; } -/** Deallocate the memory that was allocated in barrier_thread_initialize(). */ +/** + * Deallocate the memory that is owned by members of + * struct barrier_thread_info. + */ static void DRD_(barrier_thread_destroy)(struct barrier_thread_info* const p) { tl_assert(p); DRD_(sg_put)(p->sg[0]); DRD_(sg_put)(p->sg[1]); + DRD_(sg_put)(p->post_wait_sg); } -/** Initialize the structure *p with the specified client-side barrier address, - * barrier object size and number of participants in each barrier. */ +/** + * Initialize the structure *p with the specified client-side barrier address, + * barrier object size and number of participants in each barrier. + */ static void DRD_(barrier_initialize)(struct barrier_info* const p, const Addr barrier, @@ -101,13 +119,16 @@ void DRD_(barrier_initialize)(struct barrier_info* const p, tl_assert(barrier_type == pthread_barrier || barrier_type == gomp_barrier); tl_assert(p->a1 == barrier); - p->cleanup = (void(*)(DrdClientobj*))DRD_(barrier_cleanup); + p->cleanup = (void(*)(DrdClientobj*))barrier_cleanup; + p->delete_thread + = (void(*)(DrdClientobj*, DrdThreadId))barrier_delete_thread; p->barrier_type = barrier_type; p->count = count; p->pre_iteration = 0; p->post_iteration = 0; p->pre_waiters_left = count; p->post_waiters_left = count; + tl_assert(sizeof(((struct barrier_thread_info*)0)->tid) == sizeof(Word)); tl_assert(sizeof(((struct barrier_thread_info*)0)->tid) >= sizeof(DrdThreadId)); @@ -116,18 +137,21 @@ void DRD_(barrier_initialize)(struct barrier_info* const p, } /** - * Deallocate the memory allocated by barrier_initialize() and in p->oset. + * Deallocate the memory owned by the struct barrier_info object and also + * all the nodes in the OSet p->oset. + * * Called by clientobj_destroy(). */ -void DRD_(barrier_cleanup)(struct barrier_info* p) +static void barrier_cleanup(struct barrier_info* p) { struct barrier_thread_info* q; + Segment* latest_sg = 0; tl_assert(p); if (p->pre_waiters_left != p->count) { - BarrierErrInfo bei = { p->a1 }; + BarrierErrInfo bei = { p->a1, 0, 0 }; VG_(maybe_record_error)(VG_(get_running_tid)(), BarrierErr, VG_(get_IP)(VG_(get_running_tid)()), @@ -136,16 +160,29 @@ void DRD_(barrier_cleanup)(struct barrier_info* p) &bei); } + DRD_(thread_get_latest_segment)(&latest_sg, DRD_(thread_get_running_tid)()); + tl_assert(latest_sg); + VG_(OSetGen_ResetIter)(p->oset); for ( ; (q = VG_(OSetGen_Next)(p->oset)) != 0; ) { + if (q->post_wait_sg + && ! DRD_(vc_lte)(&q->post_wait_sg->vc, &latest_sg->vc)) + { + barrier_report_wait_delete_race(p, q); + } + DRD_(barrier_thread_destroy)(q); } VG_(OSetGen_Destroy)(p->oset); + + DRD_(sg_put)(latest_sg); } -/** Look up the client-side barrier address barrier in s_barrier[]. If not - * found, add it. */ +/** + * Look up the client-side barrier address barrier in s_barrier[]. If not + * found, add it. + */ static struct barrier_info* DRD_(barrier_get_or_allocate)(const Addr barrier, @@ -165,17 +202,21 @@ DRD_(barrier_get_or_allocate)(const Addr barrier, return p; } -/** Look up the address of the information associated with the client-side - * barrier object. */ +/** + * Look up the address of the information associated with the client-side + * barrier object. + */ static struct barrier_info* DRD_(barrier_get)(const Addr barrier) { tl_assert(offsetof(DrdClientobj, barrier) == 0); return &(DRD_(clientobj_get)(barrier, ClientBarrier)->barrier); } -/** Initialize a barrier with client address barrier, client size size, and - * where count threads participate in each barrier. - * Called before pthread_barrier_init(). +/** + * Initialize a barrier with client address barrier, client size size, and + * where count threads participate in each barrier. + * + * Called before pthread_barrier_init(). */ void DRD_(barrier_init)(const Addr barrier, const BarrierT barrier_type, const Word count, @@ -187,7 +228,7 @@ void DRD_(barrier_init)(const Addr barrier, if (count == 0) { - BarrierErrInfo bei = { barrier }; + BarrierErrInfo bei = { barrier, 0, 0 }; VG_(maybe_record_error)(VG_(get_running_tid)(), BarrierErr, VG_(get_IP)(VG_(get_running_tid)()), @@ -200,7 +241,7 @@ void DRD_(barrier_init)(const Addr barrier, p = DRD_(barrier_get)(barrier); if (p) { - BarrierErrInfo bei = { barrier }; + BarrierErrInfo bei = { barrier, 0, 0 }; VG_(maybe_record_error)(VG_(get_running_tid)(), BarrierErr, VG_(get_IP)(VG_(get_running_tid)()), @@ -210,7 +251,7 @@ void DRD_(barrier_init)(const Addr barrier, } p = DRD_(barrier_get_or_allocate)(barrier, barrier_type, count); - if (DRD_(s_trace_barrier)) + if (s_trace_barrier) { if (reinitialization) { @@ -218,7 +259,7 @@ void DRD_(barrier_init)(const Addr barrier, "[%d/%d] barrier_reinit %s 0x%lx count %ld -> %ld", VG_(get_running_tid)(), DRD_(thread_get_running_tid)(), - DRD_(barrier_get_typename)(p), + barrier_get_typename(p), barrier, p->count, count); @@ -229,7 +270,7 @@ void DRD_(barrier_init)(const Addr barrier, "[%d/%d] barrier_init %s 0x%lx", VG_(get_running_tid)(), DRD_(thread_get_running_tid)(), - DRD_(barrier_get_typename)(p), + barrier_get_typename(p), barrier); } } @@ -238,7 +279,7 @@ void DRD_(barrier_init)(const Addr barrier, { if (p->pre_waiters_left != p->count || p->post_waiters_left != p->count) { - BarrierErrInfo bei = { p->a1 }; + BarrierErrInfo bei = { p->a1, 0, 0 }; VG_(maybe_record_error)(VG_(get_running_tid)(), BarrierErr, VG_(get_IP)(VG_(get_running_tid)()), @@ -250,20 +291,20 @@ void DRD_(barrier_init)(const Addr barrier, } } -/** Called after pthread_barrier_destroy(). */ +/** Called after pthread_barrier_destroy() / gomp_barrier_destroy(). */ void DRD_(barrier_destroy)(const Addr barrier, const BarrierT barrier_type) { struct barrier_info* p; p = DRD_(barrier_get)(barrier); - if (DRD_(s_trace_barrier)) + if (s_trace_barrier) { VG_(message)(Vg_UserMsg, "[%d/%d] barrier_destroy %s 0x%lx", VG_(get_running_tid)(), DRD_(thread_get_running_tid)(), - DRD_(barrier_get_typename)(p), + barrier_get_typename(p), barrier); } @@ -280,7 +321,7 @@ void DRD_(barrier_destroy)(const Addr barrier, const BarrierT barrier_type) if (p->pre_waiters_left != p->count || p->post_waiters_left != p->count) { - BarrierErrInfo bei = { p->a1 }; + BarrierErrInfo bei = { p->a1, 0, 0 }; VG_(maybe_record_error)(VG_(get_running_tid)(), BarrierErr, VG_(get_IP)(VG_(get_running_tid)()), @@ -291,7 +332,7 @@ void DRD_(barrier_destroy)(const Addr barrier, const BarrierT barrier_type) DRD_(clientobj_remove)(p->a1, ClientBarrier); } -/** Called before pthread_barrier_wait(). */ +/** Called before pthread_barrier_wait() / gomp_barrier_wait(). */ void DRD_(barrier_pre_wait)(const DrdThreadId tid, const Addr barrier, const BarrierT barrier_type) { @@ -302,6 +343,11 @@ void DRD_(barrier_pre_wait)(const DrdThreadId tid, const Addr barrier, p = DRD_(barrier_get)(barrier); if (p == 0 && barrier_type == gomp_barrier) { + /* + * gomp_barrier_wait() call has been intercepted but gomp_barrier_init() + * not. The only cause I know of that can trigger this is that libgomp.so + * has been compiled with --enable-linux-futex. + */ VG_(message)(Vg_UserMsg, ""); VG_(message)(Vg_UserMsg, "Please verify whether gcc has been configured" @@ -312,17 +358,18 @@ void DRD_(barrier_pre_wait)(const DrdThreadId tid, const Addr barrier, } tl_assert(p); - if (DRD_(s_trace_barrier)) + if (s_trace_barrier) { VG_(message)(Vg_UserMsg, "[%d/%d] barrier_pre_wait %s 0x%lx iteration %ld", VG_(get_running_tid)(), DRD_(thread_get_running_tid)(), - DRD_(barrier_get_typename)(p), + barrier_get_typename(p), barrier, p->pre_iteration); } + /* Allocate the per-thread data structure if necessary. */ q = VG_(OSetGen_Lookup)(p->oset, &word_tid); if (q == 0) { @@ -331,8 +378,21 @@ void DRD_(barrier_pre_wait)(const DrdThreadId tid, const Addr barrier, VG_(OSetGen_Insert)(p->oset, q); tl_assert(VG_(OSetGen_Lookup)(p->oset, &word_tid) == q); } + + /* Record *_barrier_wait() call context. */ + q->wait_call_ctxt = VG_(record_ExeContext)(VG_(get_running_tid)(), 0); + + /* + * Store a pointer to the latest segment of the current thread in the + * per-thread data structure. + */ DRD_(thread_get_latest_segment)(&q->sg[p->pre_iteration], tid); + /* + * If the same number of threads as the barrier count indicates have + * called the pre *_barrier_wait() wrapper, toggle p->pre_iteration and + * reset the p->pre_waiters_left counter. + */ if (--p->pre_waiters_left <= 0) { p->pre_iteration = 1 - p->pre_iteration; @@ -340,106 +400,143 @@ void DRD_(barrier_pre_wait)(const DrdThreadId tid, const Addr barrier, } } -/** Called after pthread_barrier_wait(). */ +/** Called after pthread_barrier_wait() / gomp_barrier_wait(). */ void DRD_(barrier_post_wait)(const DrdThreadId tid, const Addr barrier, - const BarrierT barrier_type, const Bool waited) + const BarrierT barrier_type, const Bool waited, + const Bool serializing) { struct barrier_info* p; + const UWord word_tid = tid; + struct barrier_thread_info* q; + struct barrier_thread_info* r; p = DRD_(barrier_get)(barrier); - if (DRD_(s_trace_barrier)) + if (s_trace_barrier) { VG_(message)(Vg_UserMsg, - "[%d/%d] barrier_post_wait %s 0x%lx iteration %ld", + "[%d/%d] barrier_post_wait %s 0x%lx iteration %ld%s", VG_(get_running_tid)(), tid, - p ? DRD_(barrier_get_typename)(p) : "(?)", + p ? barrier_get_typename(p) : "(?)", barrier, - p ? p->post_iteration : -1); + p ? p->post_iteration : -1, + serializing ? " (serializing)" : ""); } - /* If p == 0, this means that the barrier has been destroyed after */ - /* *_barrier_wait() returned and before this function was called. Just */ - /* return in that case. */ + /* + * If p == 0, this means that the barrier has been destroyed after + * *_barrier_wait() returned and before this function was called. Just + * return in that case -- race conditions between *_barrier_wait() + * and *_barrier_destroy() are detected by the *_barrier_destroy() wrapper. + */ if (p == 0) return; - if (waited) - { - const UWord word_tid = tid; - struct barrier_thread_info* q; - struct barrier_thread_info* r; + /* If the *_barrier_wait() call returned an error code, exit. */ + if (! waited) + return; - q = VG_(OSetGen_Lookup)(p->oset, &word_tid); - if (q == 0) - { - BarrierErrInfo bei = { p->a1 }; - VG_(maybe_record_error)(VG_(get_running_tid)(), - BarrierErr, - VG_(get_IP)(VG_(get_running_tid)()), - "Error in barrier implementation" - " -- barrier_wait() started before" - " barrier_destroy() and finished after" - " barrier_destroy()", - &bei); + q = VG_(OSetGen_Lookup)(p->oset, &word_tid); + if (q == 0) + { + BarrierErrInfo bei = { p->a1, 0, 0 }; + VG_(maybe_record_error)(VG_(get_running_tid)(), + BarrierErr, + VG_(get_IP)(VG_(get_running_tid)()), + "Error in barrier implementation" + " -- barrier_wait() started before" + " barrier_destroy() and finished after" + " barrier_destroy()", + &bei); - q = VG_(OSetGen_AllocNode)(p->oset, sizeof(*q)); - DRD_(barrier_thread_initialize)(q, tid, p->pre_iteration); - VG_(OSetGen_Insert)(p->oset, q); - tl_assert(VG_(OSetGen_Lookup)(p->oset, &word_tid) == q); - } - VG_(OSetGen_ResetIter)(p->oset); - for ( ; (r = VG_(OSetGen_Next)(p->oset)) != 0; ) + q = VG_(OSetGen_AllocNode)(p->oset, sizeof(*q)); + DRD_(barrier_thread_initialize)(q, tid, p->pre_iteration); + VG_(OSetGen_Insert)(p->oset, q); + tl_assert(VG_(OSetGen_Lookup)(p->oset, &word_tid) == q); + } + /* + * Combine all vector clocks that were stored in the pre_barrier_wait + * wrapper with the vector clock of the current thread. + */ + VG_(OSetGen_ResetIter)(p->oset); + for ( ; (r = VG_(OSetGen_Next)(p->oset)) != 0; ) + { + if (r != q) { - if (r != q) - { - tl_assert(r->sg[p->post_iteration]); - DRD_(thread_combine_vc2)(tid, &r->sg[p->post_iteration]->vc); - } + tl_assert(r->sg[p->post_iteration]); + DRD_(thread_combine_vc2)(tid, &r->sg[p->post_iteration]->vc); } + } - DRD_(thread_new_segment)(tid); - DRD_(s_barrier_segment_creation_count)++; + /* Create a new segment and store a pointer to that segment. */ + DRD_(thread_new_segment)(tid); + DRD_(thread_get_latest_segment)(&q->post_wait_sg, tid); + s_barrier_segment_creation_count++; + + /* + * If the same number of threads as the barrier count indicates have + * called the post *_barrier_wait() wrapper, toggle p->post_iteration and + * reset the p->post_waiters_left counter. + */ + if (--p->post_waiters_left <= 0) + { + p->post_iteration = 1 - p->post_iteration; + p->post_waiters_left = p->count; + } +} - if (--p->post_waiters_left <= 0) - { - p->post_iteration = 1 - p->post_iteration; - p->post_waiters_left = p->count; - } +/** Called when thread tid stops to exist. */ +static void barrier_delete_thread(struct barrier_info* const p, + const DrdThreadId tid) +{ + struct barrier_thread_info* q; + const UWord word_tid = tid; + + q = VG_(OSetGen_Remove)(p->oset, &word_tid); + + /* + * q is only non-zero if the barrier object has been used by thread tid + * after the barrier_init() call and before the thread finished. + */ + if (q) + { + DRD_(barrier_thread_destroy)(q); + VG_(OSetGen_FreeNode)(p->oset, q); } } -/** Call this function when thread tid stops to exist. */ -void DRD_(barrier_thread_delete)(const DrdThreadId tid) +/** + * Report that *_barrier_destroy() has been called but that this call was + * not synchronized with the last *_barrier_wait() call on the same barrier. + */ +static +void barrier_report_wait_delete_race(const struct barrier_info* const p, + const struct barrier_thread_info* const q) { - struct barrier_info* p; + tl_assert(p); + tl_assert(q); - DRD_(clientobj_resetiter)(); - for ( ; (p = &(DRD_(clientobj_next)(ClientBarrier)->barrier)) != 0; ) { - struct barrier_thread_info* q; - const UWord word_tid = tid; - q = VG_(OSetGen_Remove)(p->oset, &word_tid); - /* q is only non-zero if the barrier object has been used by thread tid - * after the barrier_init() call and before the thread finished. - */ - if (q) - { - DRD_(barrier_thread_destroy)(q); - VG_(OSetGen_FreeNode)(p->oset, q); - } + BarrierErrInfo bei + = { p->a1, q->tid, q->wait_call_ctxt }; + VG_(maybe_record_error)(VG_(get_running_tid)(), + BarrierErr, + VG_(get_IP)(VG_(get_running_tid)()), + "Destruction of barrier not synchronized with" + " barrier wait call", + &bei); } } -static const char* DRD_(barrier_get_typename)(struct barrier_info* const p) +static const char* barrier_get_typename(struct barrier_info* const p) { tl_assert(p); - return DRD_(barrier_type_name)(p->barrier_type); + return barrier_type_name(p->barrier_type); } -static const char* DRD_(barrier_type_name)(const BarrierT bt) +static const char* barrier_type_name(const BarrierT bt) { switch (bt) { @@ -453,5 +550,5 @@ static const char* DRD_(barrier_type_name)(const BarrierT bt) ULong DRD_(get_barrier_segment_creation_count)(void) { - return DRD_(s_barrier_segment_creation_count); + return s_barrier_segment_creation_count; } diff --git a/drd/drd_barrier.h b/drd/drd_barrier.h index 2ef1f89957..1acb4a6e30 100644 --- a/drd/drd_barrier.h +++ b/drd/drd_barrier.h @@ -45,8 +45,8 @@ void DRD_(barrier_destroy)(const Addr barrier, const BarrierT barrier_type); void DRD_(barrier_pre_wait)(const DrdThreadId tid, const Addr barrier, const BarrierT barrier_type); void DRD_(barrier_post_wait)(const DrdThreadId tid, const Addr barrier, - const BarrierT barrier_type, const Bool waited); -void DRD_(barrier_thread_delete)(const DrdThreadId threadid); + const BarrierT barrier_type, const Bool waited, + const Bool serializing); void DRD_(barrier_stop_using_mem)(const Addr a1, const Addr a2); ULong DRD_(get_barrier_segment_creation_count)(void); diff --git a/drd/drd_clientobj.c b/drd/drd_clientobj.c index 70c162a2a4..d1f5f9641c 100644 --- a/drd/drd_clientobj.c +++ b/drd/drd_clientobj.c @@ -37,26 +37,29 @@ /* Local variables. */ -static OSet* DRD_(s_clientobj_set); -static Bool DRD_(s_trace_clientobj); +static OSet* s_clientobj_set; +static Bool s_trace_clientobj; + + +/* Local functions. */ + +static Bool clientobj_remove_obj(DrdClientobj* const p); /* Function definitions. */ void DRD_(clientobj_set_trace)(const Bool trace) { - DRD_(s_trace_clientobj) = trace; + s_trace_clientobj = trace; } /** Initialize the client object set. */ void DRD_(clientobj_init)(void) { - tl_assert(DRD_(s_clientobj_set) == 0); - DRD_(s_clientobj_set) = VG_(OSetGen_Create)(0, 0, - VG_(malloc), - "drd.clientobj.ci.1", - VG_(free)); - tl_assert(DRD_(s_clientobj_set)); + tl_assert(s_clientobj_set == 0); + s_clientobj_set = VG_(OSetGen_Create)(0, 0, VG_(malloc), + "drd.clientobj.ci.1", VG_(free)); + tl_assert(s_clientobj_set); } /** @@ -66,19 +69,20 @@ void DRD_(clientobj_init)(void) */ void DRD_(clientobj_cleanup)(void) { - tl_assert(DRD_(s_clientobj_set)); - tl_assert(VG_(OSetGen_Size)(DRD_(s_clientobj_set)) == 0); - VG_(OSetGen_Destroy)(DRD_(s_clientobj_set)); - DRD_(s_clientobj_set) = 0; + tl_assert(s_clientobj_set); + tl_assert(VG_(OSetGen_Size)(s_clientobj_set) == 0); + VG_(OSetGen_Destroy)(s_clientobj_set); + s_clientobj_set = 0; } -/** Return the data associated with the client object at client address addr. - * Return 0 if there is no client object in the set with the specified start - * address. +/** + * Return the data associated with the client object at client address addr. + * Return 0 if there is no client object in the set with the specified start + * address. */ DrdClientobj* DRD_(clientobj_get_any)(const Addr addr) { - return VG_(OSetGen_Lookup)(DRD_(s_clientobj_set), &addr); + return VG_(OSetGen_Lookup)(s_clientobj_set, &addr); } /** Return the data associated with the client object at client address addr @@ -88,7 +92,7 @@ DrdClientobj* DRD_(clientobj_get_any)(const Addr addr) DrdClientobj* DRD_(clientobj_get)(const Addr addr, const ObjType t) { DrdClientobj* p; - p = VG_(OSetGen_Lookup)(DRD_(s_clientobj_set), &addr); + p = VG_(OSetGen_Lookup)(s_clientobj_set, &addr); if (p && p->any.type == t) return p; return 0; @@ -102,8 +106,8 @@ Bool DRD_(clientobj_present)(const Addr a1, const Addr a2) DrdClientobj *p; tl_assert(a1 < a2); - VG_(OSetGen_ResetIter)(DRD_(s_clientobj_set)); - for ( ; (p = VG_(OSetGen_Next)(DRD_(s_clientobj_set))) != 0; ) + VG_(OSetGen_ResetIter)(s_clientobj_set); + for ( ; (p = VG_(OSetGen_Next)(s_clientobj_set)) != 0; ) { if (a1 <= p->any.a1 && p->any.a1 < a2) { @@ -122,20 +126,20 @@ DrdClientobj* DRD_(clientobj_add)(const Addr a1, const ObjType t) DrdClientobj* p; tl_assert(! DRD_(clientobj_present)(a1, a1 + 1)); - tl_assert(VG_(OSetGen_Lookup)(DRD_(s_clientobj_set), &a1) == 0); + tl_assert(VG_(OSetGen_Lookup)(s_clientobj_set, &a1) == 0); - if (DRD_(s_trace_clientobj)) + if (s_trace_clientobj) { VG_(message)(Vg_UserMsg, "Adding client object 0x%lx of type %d", a1, t); } - p = VG_(OSetGen_AllocNode)(DRD_(s_clientobj_set), sizeof(*p)); + p = VG_(OSetGen_AllocNode)(s_clientobj_set, sizeof(*p)); VG_(memset)(p, 0, sizeof(*p)); p->any.a1 = a1; p->any.type = t; p->any.first_observed_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0); - VG_(OSetGen_Insert)(DRD_(s_clientobj_set), p); - tl_assert(VG_(OSetGen_Lookup)(DRD_(s_clientobj_set), &a1) == p); + VG_(OSetGen_Insert)(s_clientobj_set, p); + tl_assert(VG_(OSetGen_Lookup)(s_clientobj_set, &a1) == p); DRD_(start_suppression)(a1, a1 + 1, "clientobj"); return p; } @@ -144,28 +148,35 @@ Bool DRD_(clientobj_remove)(const Addr addr, const ObjType t) { DrdClientobj* p; - if (DRD_(s_trace_clientobj)) + p = VG_(OSetGen_Lookup)(s_clientobj_set, &addr); + tl_assert(p); + tl_assert(p->any.type == t); + return clientobj_remove_obj(p); +} + +static Bool clientobj_remove_obj(DrdClientobj* const p) +{ + DrdClientobj* q; + + if (s_trace_clientobj) { VG_(message)(Vg_UserMsg, "Removing client object 0x%lx of type %d", - addr, t); + p->any.a1, p->any.type); #if 0 VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), VG_(clo_backtrace_size)); #endif } - p = VG_(OSetGen_Lookup)(DRD_(s_clientobj_set), &addr); - tl_assert(p->any.type == t); - p = VG_(OSetGen_Remove)(DRD_(s_clientobj_set), &addr); - if (p) - { - tl_assert(VG_(OSetGen_Lookup)(DRD_(s_clientobj_set), &addr) == 0); - tl_assert(p->any.cleanup); - (*p->any.cleanup)(p); - VG_(OSetGen_FreeNode)(DRD_(s_clientobj_set), p); - return True; - } - return False; + tl_assert(p); + q = VG_(OSetGen_Remove)(s_clientobj_set, &p->any.a1); + tl_assert(p == q); + + tl_assert(VG_(OSetGen_Lookup)(s_clientobj_set, &p->any.a1) == 0); + tl_assert(p->any.cleanup); + (*p->any.cleanup)(p); + VG_(OSetGen_FreeNode)(s_clientobj_set, p); + return True; } void DRD_(clientobj_stop_using_mem)(const Addr a1, const Addr a2) @@ -173,13 +184,13 @@ void DRD_(clientobj_stop_using_mem)(const Addr a1, const Addr a2) Addr removed_at; DrdClientobj* p; - tl_assert(DRD_(s_clientobj_set)); + tl_assert(s_clientobj_set); if (! DRD_(is_any_suppressed)(a1, a2)) return; - VG_(OSetGen_ResetIter)(DRD_(s_clientobj_set)); - p = VG_(OSetGen_Next)(DRD_(s_clientobj_set)); + VG_(OSetGen_ResetIter)(s_clientobj_set); + p = VG_(OSetGen_Next)(s_clientobj_set); for ( ; p != 0; ) { if (a1 <= p->any.a1 && p->any.a1 < a2) @@ -188,30 +199,34 @@ void DRD_(clientobj_stop_using_mem)(const Addr a1, const Addr a2) DRD_(clientobj_remove)(p->any.a1, p->any.type); /* The above call removes an element from the oset and hence */ /* invalidates the iterator. Set the iterator back. */ - VG_(OSetGen_ResetIter)(DRD_(s_clientobj_set)); - while ((p = VG_(OSetGen_Next)(DRD_(s_clientobj_set))) != 0 + VG_(OSetGen_ResetIter)(s_clientobj_set); + while ((p = VG_(OSetGen_Next)(s_clientobj_set)) != 0 && p->any.a1 <= removed_at) { } } else { - p = VG_(OSetGen_Next)(DRD_(s_clientobj_set)); + p = VG_(OSetGen_Next)(s_clientobj_set); } } } -void DRD_(clientobj_resetiter)(void) +/** + * Delete the per-thread information stored in client objects for the + * specified thread. + */ +void DRD_(clientobj_delete_thread)(const DrdThreadId tid) { - VG_(OSetGen_ResetIter)(DRD_(s_clientobj_set)); -} + DrdClientobj *p; -DrdClientobj* DRD_(clientobj_next)(const ObjType t) -{ - DrdClientobj* p; - while ((p = VG_(OSetGen_Next)(DRD_(s_clientobj_set))) != 0 - && p->any.type != t) - ; - return p; + VG_(OSetGen_ResetIter)(s_clientobj_set); + for ( ; (p = VG_(OSetGen_Next)(s_clientobj_set)) != 0; ) + { + if (p->any.delete_thread) + { + (*p->any.delete_thread)(p, tid); + } + } } const char* DRD_(clientobj_type_name)(const ObjType t) diff --git a/drd/drd_clientobj.h b/drd/drd_clientobj.h index efe4e6d5c4..c30a17cfbd 100644 --- a/drd/drd_clientobj.h +++ b/drd/drd_clientobj.h @@ -53,7 +53,8 @@ struct any { Addr a1; ObjType type; - void (*cleanup)(union drd_clientobj*); + void (*cleanup)(union drd_clientobj*); + void (*delete_thread)(union drd_clientobj*, DrdThreadId); ExeContext* first_observed_at; }; @@ -62,6 +63,7 @@ struct mutex_info Addr a1; ObjType type; void (*cleanup)(union drd_clientobj*); + void (*delete_thread)(union drd_clientobj*, DrdThreadId); ExeContext* first_observed_at; MutexT mutex_type; // pthread_mutex_t or pthread_spinlock_t. int recursion_count; // 0 if free, >= 1 if locked. @@ -75,7 +77,8 @@ struct cond_info { Addr a1; ObjType type; - void (*cleanup)(union drd_clientobj*); + void (*cleanup)(union drd_clientobj*); + void (*delete_thread)(union drd_clientobj*, DrdThreadId); ExeContext* first_observed_at; int waiter_count; Addr mutex; // Client mutex specified in pthread_cond_wait() call, and @@ -87,6 +90,7 @@ struct semaphore_info Addr a1; ObjType type; void (*cleanup)(union drd_clientobj*); + void (*delete_thread)(union drd_clientobj*, DrdThreadId); ExeContext* first_observed_at; UInt waits_to_skip; // Number of sem_wait() calls to skip // (due to the value assigned by sem_init()). @@ -101,14 +105,15 @@ struct barrier_info Addr a1; ObjType type; void (*cleanup)(union drd_clientobj*); + void (*delete_thread)(union drd_clientobj*, DrdThreadId); ExeContext* first_observed_at; BarrierT barrier_type; // pthread_barrier or gomp_barrier. Word count; // Participant count in a barrier wait. - Word pre_iteration; // pthread_barrier_wait() call count modulo two. - Word post_iteration; // pthread_barrier_wait() call count modulo two. + Word pre_iteration; // pre barrier completion count modulo two. + Word post_iteration; // post barrier completion count modulo two. Word pre_waiters_left; // number of waiters left for a complete barrier. Word post_waiters_left; // number of waiters left for a complete barrier. - OSet* oset; // Thread-specific barrier information. + OSet* oset; // Per-thread barrier information. }; struct rwlock_info @@ -116,6 +121,7 @@ struct rwlock_info Addr a1; ObjType type; void (*cleanup)(union drd_clientobj*); + void (*delete_thread)(union drd_clientobj*, DrdThreadId); ExeContext* first_observed_at; OSet* thread_info; ULong acquiry_time_ms; @@ -144,8 +150,7 @@ Bool DRD_(clientobj_present)(const Addr a1, const Addr a2); DrdClientobj* DRD_(clientobj_add)(const Addr a1, const ObjType t); Bool DRD_(clientobj_remove)(const Addr addr, const ObjType t); void DRD_(clientobj_stop_using_mem)(const Addr a1, const Addr a2); -void DRD_(clientobj_resetiter)(void); -DrdClientobj* DRD_(clientobj_next)(const ObjType t); +void DRD_(clientobj_delete_thread)(const DrdThreadId tid); const char* DRD_(clientobj_type_name)(const ObjType t); diff --git a/drd/drd_clientreq.c b/drd/drd_clientreq.c index d407f844a4..8a94741809 100644 --- a/drd/drd_clientreq.c +++ b/drd/drd_clientreq.c @@ -327,7 +327,7 @@ Bool DRD_(handle_client_request)(ThreadId vg_tid, UWord* arg, UWord* ret) case VG_USERREQ__POST_BARRIER_WAIT: if (DRD_(thread_leave_synchr)(drd_tid) == 0) - DRD_(barrier_post_wait)(drd_tid, arg[1], arg[2], arg[3]); + DRD_(barrier_post_wait)(drd_tid, arg[1], arg[2], arg[3], arg[4]); break; case VG_USERREQ__PRE_RWLOCK_INIT: diff --git a/drd/drd_clientreq.h b/drd/drd_clientreq.h index 82f58425a6..907e1e9d17 100644 --- a/drd/drd_clientreq.h +++ b/drd/drd_clientreq.h @@ -178,7 +178,7 @@ enum { /* args: Addr barrier, BarrierT type. */ /* To notify the drd tool of a pthread_barrier_wait call. */ VG_USERREQ__POST_BARRIER_WAIT, - /* args: Addr barrier, BarrierT type, Word has_waited */ + /* args: Addr barrier, BarrierT type, Word has_waited, Word serializing */ /* To notify the drd tool of a pthread_rwlock_init call. */ VG_USERREQ__PRE_RWLOCK_INIT, diff --git a/drd/drd_cond.c b/drd/drd_cond.c index 8d1bf7f615..afee3115c4 100644 --- a/drd/drd_cond.c +++ b/drd/drd_cond.c @@ -65,9 +65,10 @@ void DRD_(cond_initialize)(struct cond_info* const p, const Addr cond) tl_assert(p->a1 == cond); tl_assert(p->type == ClientCondvar); - p->cleanup = (void(*)(DrdClientobj*))(DRD_(cond_cleanup)); - p->waiter_count = 0; - p->mutex = 0; + p->cleanup = (void(*)(DrdClientobj*))(DRD_(cond_cleanup)); + p->delete_thread = 0; + p->waiter_count = 0; + p->mutex = 0; } /** @@ -328,7 +329,3 @@ void DRD_(cond_pre_broadcast)(Addr const cond) DRD_(cond_signal)(cond); } - -/** Called after pthread_cond_destroy(). */ -void DRD_(cond_thread_delete)(const DrdThreadId tid) -{ } diff --git a/drd/drd_cond.h b/drd/drd_cond.h index fed3f0f239..e75caef259 100644 --- a/drd/drd_cond.h +++ b/drd/drd_cond.h @@ -45,7 +45,6 @@ int DRD_(cond_pre_wait)(const Addr cond, const Addr mutex); int DRD_(cond_post_wait)(const Addr cond); void DRD_(cond_pre_signal)(const Addr cond); void DRD_(cond_pre_broadcast)(const Addr cond); -void DRD_(cond_thread_delete)(const DrdThreadId tid); #endif /* __DRD_COND_H */ diff --git a/drd/drd_error.c b/drd/drd_error.c index db42abb36e..42597513ee 100644 --- a/drd/drd_error.c +++ b/drd/drd_error.c @@ -42,12 +42,12 @@ /* Local variables. */ -static Bool DRD_(s_show_conflicting_segments) = True; +static Bool s_show_conflicting_segments = True; void DRD_(set_show_conflicting_segments)(const Bool scs) { - DRD_(s_show_conflicting_segments) = scs; + s_show_conflicting_segments = scs; } /** @@ -55,8 +55,7 @@ void DRD_(set_show_conflicting_segments)(const Bool scs) * messages, putting the result in ai. */ static -void DRD_(describe_malloced_addr)(Addr const a, SizeT const len, - AddrInfo* const ai) +void describe_malloced_addr(Addr const a, SizeT const len, AddrInfo* const ai) { Addr data; @@ -76,7 +75,7 @@ void DRD_(describe_malloced_addr)(Addr const a, SizeT const len, * call stack will either refer to a pthread_*_init() or a pthread_*lock() * call. */ -static void DRD_(first_observed)(const Addr obj) +static void first_observed(const Addr obj) { DrdClientobj* cl; @@ -93,8 +92,7 @@ static void DRD_(first_observed)(const Addr obj) } static -void DRD_(drd_report_data_race)(Error* const err, - const DataRaceErrInfo* const dri) +void drd_report_data_race(Error* const err, const DataRaceErrInfo* const dri) { AddrInfo ai; const unsigned descr_size = 256; @@ -112,7 +110,7 @@ void DRD_(drd_report_data_race)(Error* const err, VG_(get_data_description)(descr1, descr2, descr_size, dri->addr); if (descr1[0] == 0) { - DRD_(describe_malloced_addr)(dri->addr, dri->size, &ai); + describe_malloced_addr(dri->addr, dri->size, &ai); } VG_(message)(Vg_UserMsg, "Conflicting %s by thread %d/%d at 0x%08lx size %ld", @@ -153,7 +151,7 @@ void DRD_(drd_report_data_race)(Error* const err, VG_(message)(Vg_UserMsg, "Allocation context: unknown."); } } - if (DRD_(s_show_conflicting_segments)) + if (s_show_conflicting_segments) { DRD_(thread_report_conflicting_segments)(dri->tid, dri->addr, dri->size, @@ -164,17 +162,17 @@ void DRD_(drd_report_data_race)(Error* const err, VG_(free)(descr1); } -static Bool DRD_(drd_tool_error_eq)(VgRes res, Error* e1, Error* e2) +static Bool drd_tool_error_eq(VgRes res, Error* e1, Error* e2) { return False; } -static void DRD_(drd_tool_error_pp)(Error* const e) +static void drd_tool_error_pp(Error* const e) { switch (VG_(get_error_kind)(e)) { case DataRaceErr: { - DRD_(drd_report_data_race)(e, VG_(get_error_extra)(e)); + drd_report_data_race(e, VG_(get_error_extra)(e)); break; } case MutexErr: { @@ -196,7 +194,7 @@ static void DRD_(drd_tool_error_pp)(Error* const e) p->mutex); } VG_(pp_ExeContext)(VG_(get_error_where)(e)); - DRD_(first_observed)(p->mutex); + first_observed(p->mutex); break; } case CondErr: { @@ -206,7 +204,7 @@ static void DRD_(drd_tool_error_pp)(Error* const e) VG_(get_error_string)(e), cdei->cond); VG_(pp_ExeContext)(VG_(get_error_where)(e)); - DRD_(first_observed)(cdei->cond); + first_observed(cdei->cond); break; } case CondDestrErr: { @@ -217,7 +215,7 @@ static void DRD_(drd_tool_error_pp)(Error* const e) cdi->cond, cdi->mutex, DRD_(DrdThreadIdToVgThreadId)(cdi->tid), cdi->tid); VG_(pp_ExeContext)(VG_(get_error_where)(e)); - DRD_(first_observed)(cdi->mutex); + first_observed(cdi->mutex); break; } case CondRaceErr: { @@ -228,8 +226,8 @@ static void DRD_(drd_tool_error_pp)(Error* const e) " by the signalling thread.", cei->cond, cei->mutex); VG_(pp_ExeContext)(VG_(get_error_where)(e)); - DRD_(first_observed)(cei->cond); - DRD_(first_observed)(cei->mutex); + first_observed(cei->cond); + first_observed(cei->mutex); break; } case CondWaitErr: { @@ -241,9 +239,9 @@ static void DRD_(drd_tool_error_pp)(Error* const e) cwei->mutex1, cwei->mutex2); VG_(pp_ExeContext)(VG_(get_error_where)(e)); - DRD_(first_observed)(cwei->cond); - DRD_(first_observed)(cwei->mutex1); - DRD_(first_observed)(cwei->mutex2); + first_observed(cwei->cond); + first_observed(cwei->mutex1); + first_observed(cwei->mutex2); break; } case SemaphoreErr: { @@ -254,18 +252,26 @@ static void DRD_(drd_tool_error_pp)(Error* const e) VG_(get_error_string)(e), sei->semaphore); VG_(pp_ExeContext)(VG_(get_error_where)(e)); - DRD_(first_observed)(sei->semaphore); + first_observed(sei->semaphore); break; } case BarrierErr: { - BarrierErrInfo* bei =(BarrierErrInfo*)(VG_(get_error_extra)(e)); + BarrierErrInfo* bei = (BarrierErrInfo*)(VG_(get_error_extra)(e)); tl_assert(bei); VG_(message)(Vg_UserMsg, "%s: barrier 0x%lx", VG_(get_error_string)(e), bei->barrier); VG_(pp_ExeContext)(VG_(get_error_where)(e)); - DRD_(first_observed)(bei->barrier); + if (bei->other_context) + { + VG_(message)(Vg_UserMsg, + "Conflicting wait call by thread %d/%d:", + DRD_(DrdThreadIdToVgThreadId)(bei->other_tid), + bei->other_tid); + VG_(pp_ExeContext)(bei->other_context); + } + first_observed(bei->barrier); break; } case RwlockErr: { @@ -276,7 +282,7 @@ static void DRD_(drd_tool_error_pp)(Error* const e) VG_(get_error_string)(e), p->rwlock); VG_(pp_ExeContext)(VG_(get_error_where)(e)); - DRD_(first_observed)(p->rwlock); + first_observed(p->rwlock); break; } case HoldtimeErr: { @@ -292,7 +298,7 @@ static void DRD_(drd_tool_error_pp)(Error* const e) p->hold_time_ms, p->threshold_ms); VG_(pp_ExeContext)(VG_(get_error_where)(e)); - DRD_(first_observed)(p->synchronization_object); + first_observed(p->synchronization_object); break; } case GenericErr: { @@ -310,7 +316,7 @@ static void DRD_(drd_tool_error_pp)(Error* const e) } } -static UInt DRD_(drd_tool_error_update_extra)(Error* e) +static UInt drd_tool_error_update_extra(Error* e) { switch (VG_(get_error_kind)(e)) { @@ -342,7 +348,7 @@ static UInt DRD_(drd_tool_error_update_extra)(Error* e) } } -static Bool DRD_(drd_tool_error_recog)(Char* const name, Supp* const supp) +static Bool drd_tool_error_recog(Char* const name, Supp* const supp) { SuppKind skind = 0; @@ -376,12 +382,12 @@ static Bool DRD_(drd_tool_error_recog)(Char* const name, Supp* const supp) } static -Bool DRD_(drd_tool_error_read_extra)(Int fd, Char* buf, Int nBuf, Supp* supp) +Bool drd_tool_error_read_extra(Int fd, Char* buf, Int nBuf, Supp* supp) { return True; } -static Bool DRD_(drd_tool_error_matches)(Error* const e, Supp* const supp) +static Bool drd_tool_error_matches(Error* const e, Supp* const supp) { switch (VG_(get_supp_kind)(supp)) { @@ -389,7 +395,7 @@ static Bool DRD_(drd_tool_error_matches)(Error* const e, Supp* const supp) return True; } -static Char* DRD_(drd_tool_error_name)(Error* e) +static Char* drd_tool_error_name(Error* e) { switch (VG_(get_error_kind)(e)) { @@ -410,19 +416,19 @@ static Char* DRD_(drd_tool_error_name)(Error* e) return 0; } -static void DRD_(drd_tool_error_print_extra)(Error* e) +static void drd_tool_error_print_extra(Error* e) { } void DRD_(register_error_handlers)(void) { // Tool error reporting. - VG_(needs_tool_errors)(DRD_(drd_tool_error_eq), - DRD_(drd_tool_error_pp), + VG_(needs_tool_errors)(drd_tool_error_eq, + drd_tool_error_pp, True, - DRD_(drd_tool_error_update_extra), - DRD_(drd_tool_error_recog), - DRD_(drd_tool_error_read_extra), - DRD_(drd_tool_error_matches), - DRD_(drd_tool_error_name), - DRD_(drd_tool_error_print_extra)); + drd_tool_error_update_extra, + drd_tool_error_recog, + drd_tool_error_read_extra, + drd_tool_error_matches, + drd_tool_error_name, + drd_tool_error_print_extra); } diff --git a/drd/drd_error.h b/drd/drd_error.h index 2efa26fb8e..34fd62b114 100644 --- a/drd/drd_error.h +++ b/drd/drd_error.h @@ -128,7 +128,9 @@ typedef struct { } SemaphoreErrInfo; typedef struct { - Addr barrier; + Addr barrier; + DrdThreadId other_tid; + ExeContext* other_context; } BarrierErrInfo; typedef struct { diff --git a/drd/drd_mutex.c b/drd/drd_mutex.c index a55959b672..fecb35585f 100644 --- a/drd/drd_mutex.c +++ b/drd/drd_mutex.c @@ -38,16 +38,17 @@ /* Local functions. */ -static void DRD_(mutex_cleanup)(struct mutex_info* p); -static Bool DRD_(mutex_is_locked)(struct mutex_info* const p); +static void mutex_cleanup(struct mutex_info* p); +static Bool mutex_is_locked(struct mutex_info* const p); +static void mutex_delete_thread(struct mutex_info* p, const DrdThreadId tid); /* Local variables. */ -static Bool DRD_(s_trace_mutex); -static ULong DRD_(s_mutex_lock_count); -static ULong DRD_(s_mutex_segment_creation_count); -static UInt DRD_(s_mutex_lock_threshold_ms) = 1000 * 1000; +static Bool s_trace_mutex; +static ULong s_mutex_lock_count; +static ULong s_mutex_segment_creation_count; +static UInt s_mutex_lock_threshold_ms = 1000 * 1000; /* Function definitions. */ @@ -55,12 +56,12 @@ static UInt DRD_(s_mutex_lock_threshold_ms) = 1000 * 1000; void DRD_(mutex_set_trace)(const Bool trace_mutex) { tl_assert(!! trace_mutex == trace_mutex); - DRD_(s_trace_mutex) = trace_mutex; + s_trace_mutex = trace_mutex; } void DRD_(mutex_set_lock_threshold)(const UInt lock_threshold_ms) { - DRD_(s_mutex_lock_threshold_ms) = lock_threshold_ms; + s_mutex_lock_threshold_ms = lock_threshold_ms; } static @@ -71,7 +72,9 @@ void DRD_(mutex_initialize)(struct mutex_info* const p, tl_assert(mutex_type != mutex_type_unknown); tl_assert(p->a1 == mutex); - p->cleanup = (void(*)(DrdClientobj*))&(DRD_(mutex_cleanup)); + p->cleanup = (void(*)(DrdClientobj*))mutex_cleanup; + p->delete_thread + = (void(*)(DrdClientobj*, DrdThreadId))mutex_delete_thread; p->mutex_type = mutex_type; p->recursion_count = 0; p->owner = DRD_INVALID_THREADID; @@ -81,11 +84,11 @@ void DRD_(mutex_initialize)(struct mutex_info* const p, } /** Deallocate the memory that was allocated by mutex_initialize(). */ -static void DRD_(mutex_cleanup)(struct mutex_info* p) +static void mutex_cleanup(struct mutex_info* p) { tl_assert(p); - if (DRD_(s_trace_mutex)) + if (s_trace_mutex) { VG_(message)(Vg_UserMsg, "[%d/%d] mutex_destroy %s 0x%lx rc %d owner %d", @@ -97,7 +100,7 @@ static void DRD_(mutex_cleanup)(struct mutex_info* p) p ? p->owner : DRD_INVALID_THREADID); } - if (DRD_(mutex_is_locked)(p)) + if (mutex_is_locked(p)) { MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner }; VG_(maybe_record_error)(VG_(get_running_tid)(), @@ -162,7 +165,7 @@ DRD_(mutex_init)(const Addr mutex, const MutexT mutex_type) tl_assert(mutex_type != mutex_type_unknown); - if (DRD_(s_trace_mutex)) + if (s_trace_mutex) { VG_(message)(Vg_UserMsg, "[%d/%d] mutex_init %s 0x%lx", @@ -225,7 +228,7 @@ void DRD_(mutex_pre_lock)(const Addr mutex, MutexT mutex_type, if (mutex_type == mutex_type_unknown) mutex_type = p->mutex_type; - if (DRD_(s_trace_mutex)) + if (s_trace_mutex) { VG_(message)(Vg_UserMsg, "[%d/%d] %s %s 0x%lx rc %d owner %d", @@ -279,7 +282,7 @@ void DRD_(mutex_post_lock)(const Addr mutex, const Bool took_lock, p = DRD_(mutex_get)(mutex); - if (DRD_(s_trace_mutex)) + if (s_trace_mutex) { VG_(message)(Vg_UserMsg, "[%d/%d] %s %s 0x%lx rc %d owner %d%s", @@ -306,12 +309,12 @@ void DRD_(mutex_post_lock)(const Addr mutex, const Bool took_lock, DRD_(thread_combine_vc2)(drd_tid, &p->last_locked_segment->vc); } DRD_(thread_new_segment)(drd_tid); - DRD_(s_mutex_segment_creation_count)++; + s_mutex_segment_creation_count++; p->owner = drd_tid; p->acquiry_time_ms = VG_(read_millisecond_timer)(); p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0); - DRD_(s_mutex_lock_count)++; + s_mutex_lock_count++; } else if (p->owner != drd_tid) { @@ -346,7 +349,7 @@ void DRD_(mutex_unlock)(const Addr mutex, MutexT mutex_type) if (mutex_type == mutex_type_unknown) mutex_type = p->mutex_type; - if (DRD_(s_trace_mutex)) + if (s_trace_mutex) { VG_(message)(Vg_UserMsg, "[%d/%d] mutex_unlock %s 0x%lx rc %d", @@ -399,13 +402,13 @@ void DRD_(mutex_unlock)(const Addr mutex, MutexT mutex_type) if (p->recursion_count == 0) { - if (DRD_(s_mutex_lock_threshold_ms) > 0) + if (s_mutex_lock_threshold_ms > 0) { ULong held = VG_(read_millisecond_timer)() - p->acquiry_time_ms; - if (held > DRD_(s_mutex_lock_threshold_ms)) + if (held > s_mutex_lock_threshold_ms) { HoldtimeErrInfo HEI - = { mutex, p->acquired_at, held, DRD_(s_mutex_lock_threshold_ms) }; + = { mutex, p->acquired_at, held, s_mutex_lock_threshold_ms }; VG_(maybe_record_error)(vg_tid, HoldtimeErr, VG_(get_IP)(vg_tid), @@ -421,7 +424,7 @@ void DRD_(mutex_unlock)(const Addr mutex, MutexT mutex_type) DRD_(thread_get_latest_segment)(&p->last_locked_segment, drd_tid); DRD_(thread_new_segment)(drd_tid); p->acquired_at = 0; - DRD_(s_mutex_segment_creation_count)++; + s_mutex_segment_creation_count++; } } @@ -466,7 +469,7 @@ const char* DRD_(mutex_type_name)(const MutexT mt) } /** Return true if the specified mutex is locked by any thread. */ -static Bool DRD_(mutex_is_locked)(struct mutex_info* const p) +static Bool mutex_is_locked(struct mutex_info* const p) { tl_assert(p); return (p->recursion_count > 0); @@ -493,33 +496,29 @@ int DRD_(mutex_get_recursion_count)(const Addr mutex) * Call this function when thread tid stops to exist, such that the * "last owner" field can be cleared if it still refers to that thread. */ -void DRD_(mutex_thread_delete)(const DrdThreadId tid) +static void mutex_delete_thread(struct mutex_info* p, const DrdThreadId tid) { - struct mutex_info* p; + tl_assert(p); - DRD_(clientobj_resetiter)(); - for ( ; (p = &(DRD_(clientobj_next)(ClientMutex)->mutex)) != 0; ) + if (p->owner == tid && p->recursion_count > 0) { - if (p->owner == tid && p->recursion_count > 0) - { - MutexErrInfo MEI - = { p->a1, p->recursion_count, p->owner }; - VG_(maybe_record_error)(VG_(get_running_tid)(), - MutexErr, - VG_(get_IP)(VG_(get_running_tid)()), - "Mutex still locked at thread exit", - &MEI); - p->owner = VG_INVALID_THREADID; - } + MutexErrInfo MEI + = { p->a1, p->recursion_count, p->owner }; + VG_(maybe_record_error)(VG_(get_running_tid)(), + MutexErr, + VG_(get_IP)(VG_(get_running_tid)()), + "Mutex still locked at thread exit", + &MEI); + p->owner = VG_INVALID_THREADID; } } ULong DRD_(get_mutex_lock_count)(void) { - return DRD_(s_mutex_lock_count); + return s_mutex_lock_count; } ULong DRD_(get_mutex_segment_creation_count)(void) { - return DRD_(s_mutex_segment_creation_count); + return s_mutex_segment_creation_count; } diff --git a/drd/drd_mutex.h b/drd/drd_mutex.h index 07f2fb35f0..a36f6014f8 100644 --- a/drd/drd_mutex.h +++ b/drd/drd_mutex.h @@ -50,7 +50,6 @@ const char* DRD_(mutex_get_typename)(struct mutex_info* const p); const char* DRD_(mutex_type_name)(const MutexT mt); Bool DRD_(mutex_is_locked_by)(const Addr mutex, const DrdThreadId tid); int DRD_(mutex_get_recursion_count)(const Addr mutex); -void DRD_(mutex_thread_delete)(const DrdThreadId tid); ULong DRD_(get_mutex_lock_count)(void); ULong DRD_(get_mutex_segment_creation_count)(void); diff --git a/drd/drd_pthread_intercepts.c b/drd/drd_pthread_intercepts.c index 7530b6b0af..2c29c44d07 100644 --- a/drd/drd_pthread_intercepts.c +++ b/drd/drd_pthread_intercepts.c @@ -194,8 +194,10 @@ static void* DRD_(thread_wrapper)(void* arg) } /** - * Return 1 if the LinuxThread implementation has been detected, and 0 - * otherwise. For more information about the confstr() function, see also + * Return 1 if the LinuxThreads implementation of POSIX Threads has been + * detected, and 0 otherwise. + * + * @see For more information about the confstr() function, see also * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html */ static int DRD_(detected_linuxthreads)(void) @@ -283,7 +285,7 @@ PTH_FUNC(int, pthreadZucreateZa, // pthread_create* /* * Find out whether the thread will be started as a joinable thread * or as a detached thread. If no thread attributes have been specified, - * the new thread will be started as a joinable thread. + * this means that the new thread will be started as a joinable thread. */ thread_args.detachstate = PTHREAD_CREATE_JOINABLE; if (attr) @@ -706,7 +708,7 @@ PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_WAIT, barrier, pthread_barrier, ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD, - 0, 0); + ret == PTHREAD_BARRIER_SERIAL_THREAD, 0); return ret; } diff --git a/drd/drd_rwlock.c b/drd/drd_rwlock.c index 9b545d10f4..12d89200a9 100644 --- a/drd/drd_rwlock.c +++ b/drd/drd_rwlock.c @@ -49,7 +49,9 @@ struct rwlock_thread_info /* Local functions. */ -static void DRD_(rwlock_cleanup)(struct rwlock_info* p); +static void rwlock_cleanup(struct rwlock_info* p); +static void rwlock_delete_thread(struct rwlock_info* const p, + const DrdThreadId tid); /* Local variables. */ @@ -184,7 +186,8 @@ void DRD_(rwlock_initialize)(struct rwlock_info* const p, const Addr rwlock) tl_assert(p->a1 == rwlock); tl_assert(p->type == ClientRwlock); - p->cleanup = (void(*)(DrdClientobj*))&(DRD_(rwlock_cleanup)); + p->cleanup = (void(*)(DrdClientobj*))rwlock_cleanup; + p->delete_thread = (void(*)(DrdClientobj*, DrdThreadId))rwlock_delete_thread; p->thread_info = VG_(OSetGen_Create)( 0, 0, VG_(malloc), "drd.rwlock.ri.1", VG_(free)); p->acquiry_time_ms = 0; @@ -192,7 +195,7 @@ void DRD_(rwlock_initialize)(struct rwlock_info* const p, const Addr rwlock) } /** Deallocate the memory that was allocated by rwlock_initialize(). */ -static void DRD_(rwlock_cleanup)(struct rwlock_info* p) +static void rwlock_cleanup(struct rwlock_info* p) { struct rwlock_thread_info* q; @@ -568,26 +571,21 @@ void DRD_(rwlock_pre_unlock)(const Addr rwlock) * Call this function when thread tid stops to exist, such that the * "last owner" field can be cleared if it still refers to that thread. */ -void DRD_(rwlock_thread_delete)(const DrdThreadId tid) +static void rwlock_delete_thread(struct rwlock_info* const p, + const DrdThreadId tid) { - struct rwlock_info* p; - - DRD_(clientobj_resetiter)(); - for ( ; (p = &(DRD_(clientobj_next)(ClientRwlock)->rwlock)) != 0; ) + struct rwlock_thread_info* q; + if (DRD_(rwlock_is_locked_by)(p, tid)) { - struct rwlock_thread_info* q; - if (DRD_(rwlock_is_locked_by)(p, tid)) - { - RwlockErrInfo REI = { p->a1 }; - VG_(maybe_record_error)(VG_(get_running_tid)(), - RwlockErr, - VG_(get_IP)(VG_(get_running_tid)()), - "Reader-writer lock still locked at thread exit", - &REI); - q = DRD_(lookup_or_insert_node)(p->thread_info, tid); - q->reader_nesting_count = 0; - q->writer_nesting_count = 0; - } + RwlockErrInfo REI = { p->a1 }; + VG_(maybe_record_error)(VG_(get_running_tid)(), + RwlockErr, + VG_(get_IP)(VG_(get_running_tid)()), + "Reader-writer lock still locked at thread exit", + &REI); + q = DRD_(lookup_or_insert_node)(p->thread_info, tid); + q->reader_nesting_count = 0; + q->writer_nesting_count = 0; } } diff --git a/drd/drd_rwlock.h b/drd/drd_rwlock.h index 5f344e9dcc..abb59c7bbf 100644 --- a/drd/drd_rwlock.h +++ b/drd/drd_rwlock.h @@ -47,7 +47,6 @@ void DRD_(rwlock_post_rdlock)(const Addr rwlock, const Bool took_lock); void DRD_(rwlock_pre_wrlock)(const Addr rwlock); void DRD_(rwlock_post_wrlock)(const Addr rwlock, const Bool took_lock); void DRD_(rwlock_pre_unlock)(const Addr rwlock); -void DRD_(rwlock_thread_delete)(const DrdThreadId tid); ULong DRD_(get_rwlock_segment_creation_count)(void); diff --git a/drd/drd_semaphore.c b/drd/drd_semaphore.c index da99d06294..02d5c7d4f6 100644 --- a/drd/drd_semaphore.c +++ b/drd/drd_semaphore.c @@ -36,13 +36,13 @@ /* Local functions. */ -static void DRD_(semaphore_cleanup)(struct semaphore_info* p); +static void semaphore_cleanup(struct semaphore_info* p); /* Local variables. */ -static Bool DRD_(s_trace_semaphore); -static ULong DRD_(s_semaphore_segment_creation_count); +static Bool s_trace_semaphore; +static ULong s_semaphore_segment_creation_count; /* Function definitions. */ @@ -85,7 +85,7 @@ static Segment* DRD_(segment_pop)(struct semaphore_info* p) /** Enable or disable tracing of semaphore actions. */ void DRD_(semaphore_set_trace)(const Bool trace_semaphore) { - DRD_(s_trace_semaphore) = trace_semaphore; + s_trace_semaphore = trace_semaphore; } /** @@ -100,7 +100,8 @@ void DRD_(semaphore_initialize)(struct semaphore_info* const p, tl_assert(p->a1 == semaphore); tl_assert(p->type == ClientSemaphore); - p->cleanup = (void(*)(DrdClientobj*))(DRD_(semaphore_cleanup)); + p->cleanup = (void(*)(DrdClientobj*))semaphore_cleanup; + p->delete_thread = 0; p->waits_to_skip = 0; p->value = 0; p->waiters = 0; @@ -113,7 +114,7 @@ void DRD_(semaphore_initialize)(struct semaphore_info* const p, * Free the memory that was allocated by semaphore_initialize(). Called by * DRD_(clientobj_remove)(). */ -static void DRD_(semaphore_cleanup)(struct semaphore_info* p) +static void semaphore_cleanup(struct semaphore_info* p) { Segment* sg; @@ -172,7 +173,7 @@ struct semaphore_info* DRD_(semaphore_init)(const Addr semaphore, struct semaphore_info* p; Segment* sg; - if (DRD_(s_trace_semaphore)) + if (s_trace_semaphore) { VG_(message)(Vg_UserMsg, "[%d/%d] semaphore_init 0x%lx value %u", @@ -214,7 +215,7 @@ void DRD_(semaphore_destroy)(const Addr semaphore) p = DRD_(semaphore_get)(semaphore); - if (DRD_(s_trace_semaphore)) + if (s_trace_semaphore) { VG_(message)(Vg_UserMsg, "[%d/%d] semaphore_destroy 0x%lx value %u", @@ -262,7 +263,7 @@ void DRD_(semaphore_post_wait)(const DrdThreadId tid, const Addr semaphore, Segment* sg; p = DRD_(semaphore_get)(semaphore); - if (DRD_(s_trace_semaphore)) + if (s_trace_semaphore) { VG_(message)(Vg_UserMsg, "[%d/%d] semaphore_wait 0x%lx value %u -> %u", @@ -304,7 +305,7 @@ void DRD_(semaphore_post_wait)(const DrdThreadId tid, const Addr semaphore, } DRD_(sg_put)(sg); DRD_(thread_new_segment)(tid); - DRD_(s_semaphore_segment_creation_count)++; + s_semaphore_segment_creation_count++; } } } @@ -318,7 +319,7 @@ void DRD_(semaphore_pre_post)(const DrdThreadId tid, const Addr semaphore) p = DRD_(semaphore_get_or_allocate)(semaphore); p->value++; - if (DRD_(s_trace_semaphore)) + if (s_trace_semaphore) { VG_(message)(Vg_UserMsg, "[%d/%d] semaphore_post 0x%lx value %u -> %u", @@ -334,7 +335,7 @@ void DRD_(semaphore_pre_post)(const DrdThreadId tid, const Addr semaphore) DRD_(thread_get_latest_segment)(&sg, tid); tl_assert(sg); DRD_(segment_push)(p, sg); - DRD_(s_semaphore_segment_creation_count)++; + s_semaphore_segment_creation_count++; } /** Called after sem_post() finished successfully. */ @@ -352,10 +353,7 @@ void DRD_(semaphore_post_post)(const DrdThreadId tid, const Addr semaphore, /* redirected functions. */ } -void DRD_(semaphore_thread_delete)(const DrdThreadId threadid) -{ } - ULong DRD_(get_semaphore_segment_creation_count)(void) { - return DRD_(s_semaphore_segment_creation_count); + return s_semaphore_segment_creation_count; } diff --git a/drd/drd_semaphore.h b/drd/drd_semaphore.h index d57a23b466..e6b248fab8 100644 --- a/drd/drd_semaphore.h +++ b/drd/drd_semaphore.h @@ -47,7 +47,6 @@ void DRD_(semaphore_post_wait)(const DrdThreadId tid, const Addr semaphore, void DRD_(semaphore_pre_post)(const DrdThreadId tid, const Addr semaphore); void DRD_(semaphore_post_post)(const DrdThreadId tid, const Addr semaphore, const Bool waited); -void DRD_(semaphore_thread_delete)(const DrdThreadId tid); ULong DRD_(get_semaphore_segment_creation_count)(void); diff --git a/drd/drd_thread.c b/drd/drd_thread.c index aeacbfa620..5a8b130d2c 100644 --- a/drd/drd_thread.c +++ b/drd/drd_thread.c @@ -24,6 +24,7 @@ #include "drd_error.h" #include "drd_barrier.h" +#include "drd_clientobj.h" #include "drd_cond.h" #include "drd_mutex.h" #include "drd_segment.h" @@ -302,11 +303,8 @@ void DRD_(thread_post_join)(DrdThreadId drd_joiner, DrdThreadId drd_joinee) - DRD_(thread_get_stack_size)(drd_joinee), DRD_(thread_get_stack_max)(drd_joinee)); } + DRD_(clientobj_delete_thread)(drd_joinee); DRD_(thread_delete)(drd_joinee); - DRD_(mutex_thread_delete)(drd_joinee); - DRD_(cond_thread_delete)(drd_joinee); - DRD_(semaphore_thread_delete)(drd_joinee); - DRD_(barrier_thread_delete)(drd_joinee); } /** -- 2.47.3