- 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
This commit is contained in:
Bart Van Assche 2009-02-21 15:27:04 +00:00
parent 38e450b4c8
commit aaef6d016e
18 changed files with 420 additions and 307 deletions

View File

@ -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)
/* If the *_barrier_wait() call returned an error code, exit. */
if (! waited)
return;
q = VG_(OSetGen_Lookup)(p->oset, &word_tid);
if (q == 0)
{
const UWord word_tid = tid;
struct barrier_thread_info* q;
struct barrier_thread_info* r;
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_Lookup)(p->oset, &word_tid);
if (q == 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)
{
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_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; )
{
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 (--p->post_waiters_left <= 0)
{
p->post_iteration = 1 - p->post_iteration;
p->post_waiters_left = p->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;
}
}
/** Call this function when thread tid stops to exist. */
void DRD_(barrier_thread_delete)(const DrdThreadId tid)
/** Called when thread tid stops to exist. */
static void barrier_delete_thread(struct barrier_info* const p,
const DrdThreadId tid)
{
struct barrier_info* p;
struct barrier_thread_info* q;
const UWord word_tid = tid;
DRD_(clientobj_resetiter)();
for ( ; (p = &(DRD_(clientobj_next)(ClientBarrier)->barrier)) != 0; )
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)
{
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);
}
DRD_(barrier_thread_destroy)(q);
VG_(OSetGen_FreeNode)(p->oset, q);
}
}
static const char* DRD_(barrier_get_typename)(struct barrier_info* const p)
/**
* 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)
{
tl_assert(p);
tl_assert(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* 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;
}

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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:

View File

@ -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,

View File

@ -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)
{ }

View File

@ -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 */

View File

@ -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);
}

View File

@ -128,7 +128,9 @@ typedef struct {
} SemaphoreErrInfo;
typedef struct {
Addr barrier;
Addr barrier;
DrdThreadId other_tid;
ExeContext* other_context;
} BarrierErrInfo;
typedef struct {

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}
/**