mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 18:13:01 +00:00
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
This commit is contained in:
parent
38e450b4c8
commit
aaef6d016e
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
{ }
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -128,7 +128,9 @@ typedef struct {
|
||||
} SemaphoreErrInfo;
|
||||
|
||||
typedef struct {
|
||||
Addr barrier;
|
||||
Addr barrier;
|
||||
DrdThreadId other_tid;
|
||||
ExeContext* other_context;
|
||||
} BarrierErrInfo;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user