/** 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,
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));
}
/**
- * 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)()),
&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,
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,
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)()),
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)()),
}
p = DRD_(barrier_get_or_allocate)(barrier, barrier_type, count);
- if (DRD_(s_trace_barrier))
+ if (s_trace_barrier)
{
if (reinitialization)
{
"[%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);
"[%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);
}
}
{
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)()),
}
}
-/** 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);
}
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)()),
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)
{
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"
}
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)
{
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;
}
}
-/** Called after pthread_barrier_wait(). */
+/** Called after pthread_barrier_wait() / gomp_barrier_wait(). */
void DRD_(barrier_post_wait)(const DrdThreadId tid, const Addr barrier,
- const BarrierT barrier_type, const Bool waited)
+ const BarrierT barrier_type, const Bool waited,
+ const Bool serializing)
{
struct barrier_info* p;
+ const UWord word_tid = tid;
+ struct barrier_thread_info* q;
+ struct barrier_thread_info* r;
p = DRD_(barrier_get)(barrier);
- if (DRD_(s_trace_barrier))
+ if (s_trace_barrier)
{
VG_(message)(Vg_UserMsg,
- "[%d/%d] barrier_post_wait %s 0x%lx iteration %ld",
+ "[%d/%d] barrier_post_wait %s 0x%lx iteration %ld%s",
VG_(get_running_tid)(),
tid,
- p ? DRD_(barrier_get_typename)(p) : "(?)",
+ p ? barrier_get_typename(p) : "(?)",
barrier,
- p ? p->post_iteration : -1);
+ p ? p->post_iteration : -1,
+ serializing ? " (serializing)" : "");
}
- /* If p == 0, this means that the barrier has been destroyed after */
- /* *_barrier_wait() returned and before this function was called. Just */
- /* return in that case. */
+ /*
+ * If p == 0, this means that the barrier has been destroyed after
+ * *_barrier_wait() returned and before this function was called. Just
+ * return in that case -- race conditions between *_barrier_wait()
+ * and *_barrier_destroy() are detected by the *_barrier_destroy() wrapper.
+ */
if (p == 0)
return;
- if (waited)
- {
- const UWord word_tid = tid;
- struct barrier_thread_info* q;
- struct barrier_thread_info* r;
+ /* If the *_barrier_wait() call returned an error code, exit. */
+ if (! waited)
+ return;
- q = VG_(OSetGen_Lookup)(p->oset, &word_tid);
- if (q == 0)
- {
- BarrierErrInfo bei = { p->a1 };
- VG_(maybe_record_error)(VG_(get_running_tid)(),
- BarrierErr,
- VG_(get_IP)(VG_(get_running_tid)()),
- "Error in barrier implementation"
- " -- barrier_wait() started before"
- " barrier_destroy() and finished after"
- " barrier_destroy()",
- &bei);
+ q = VG_(OSetGen_Lookup)(p->oset, &word_tid);
+ if (q == 0)
+ {
+ BarrierErrInfo bei = { p->a1, 0, 0 };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ BarrierErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "Error in barrier implementation"
+ " -- barrier_wait() started before"
+ " barrier_destroy() and finished after"
+ " barrier_destroy()",
+ &bei);
- q = VG_(OSetGen_AllocNode)(p->oset, sizeof(*q));
- DRD_(barrier_thread_initialize)(q, tid, p->pre_iteration);
- VG_(OSetGen_Insert)(p->oset, q);
- tl_assert(VG_(OSetGen_Lookup)(p->oset, &word_tid) == q);
- }
- VG_(OSetGen_ResetIter)(p->oset);
- for ( ; (r = VG_(OSetGen_Next)(p->oset)) != 0; )
+ q = VG_(OSetGen_AllocNode)(p->oset, sizeof(*q));
+ DRD_(barrier_thread_initialize)(q, tid, p->pre_iteration);
+ VG_(OSetGen_Insert)(p->oset, q);
+ tl_assert(VG_(OSetGen_Lookup)(p->oset, &word_tid) == q);
+ }
+ /*
+ * Combine all vector clocks that were stored in the pre_barrier_wait
+ * wrapper with the vector clock of the current thread.
+ */
+ VG_(OSetGen_ResetIter)(p->oset);
+ for ( ; (r = VG_(OSetGen_Next)(p->oset)) != 0; )
+ {
+ if (r != q)
{
- if (r != q)
- {
- tl_assert(r->sg[p->post_iteration]);
- DRD_(thread_combine_vc2)(tid, &r->sg[p->post_iteration]->vc);
- }
+ tl_assert(r->sg[p->post_iteration]);
+ DRD_(thread_combine_vc2)(tid, &r->sg[p->post_iteration]->vc);
}
+ }
- DRD_(thread_new_segment)(tid);
- DRD_(s_barrier_segment_creation_count)++;
+ /* Create a new segment and store a pointer to that segment. */
+ DRD_(thread_new_segment)(tid);
+ DRD_(thread_get_latest_segment)(&q->post_wait_sg, tid);
+ s_barrier_segment_creation_count++;
+
+ /*
+ * If the same number of threads as the barrier count indicates have
+ * called the post *_barrier_wait() wrapper, toggle p->post_iteration and
+ * reset the p->post_waiters_left counter.
+ */
+ if (--p->post_waiters_left <= 0)
+ {
+ p->post_iteration = 1 - p->post_iteration;
+ p->post_waiters_left = p->count;
+ }
+}
- if (--p->post_waiters_left <= 0)
- {
- p->post_iteration = 1 - p->post_iteration;
- p->post_waiters_left = p->count;
- }
+/** Called when thread tid stops to exist. */
+static void barrier_delete_thread(struct barrier_info* const p,
+ const DrdThreadId tid)
+{
+ struct barrier_thread_info* q;
+ const UWord word_tid = tid;
+
+ q = VG_(OSetGen_Remove)(p->oset, &word_tid);
+
+ /*
+ * q is only non-zero if the barrier object has been used by thread tid
+ * after the barrier_init() call and before the thread finished.
+ */
+ if (q)
+ {
+ DRD_(barrier_thread_destroy)(q);
+ VG_(OSetGen_FreeNode)(p->oset, q);
}
}
-/** Call this function when thread tid stops to exist. */
-void DRD_(barrier_thread_delete)(const DrdThreadId tid)
+/**
+ * Report that *_barrier_destroy() has been called but that this call was
+ * not synchronized with the last *_barrier_wait() call on the same barrier.
+ */
+static
+void barrier_report_wait_delete_race(const struct barrier_info* const p,
+ const struct barrier_thread_info* const q)
{
- struct barrier_info* p;
+ tl_assert(p);
+ tl_assert(q);
- DRD_(clientobj_resetiter)();
- for ( ; (p = &(DRD_(clientobj_next)(ClientBarrier)->barrier)) != 0; )
{
- struct barrier_thread_info* q;
- const UWord word_tid = tid;
- q = VG_(OSetGen_Remove)(p->oset, &word_tid);
- /* q is only non-zero if the barrier object has been used by thread tid
- * after the barrier_init() call and before the thread finished.
- */
- if (q)
- {
- DRD_(barrier_thread_destroy)(q);
- VG_(OSetGen_FreeNode)(p->oset, q);
- }
+ BarrierErrInfo bei
+ = { p->a1, q->tid, q->wait_call_ctxt };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ BarrierErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "Destruction of barrier not synchronized with"
+ " barrier wait call",
+ &bei);
}
}
-static const char* DRD_(barrier_get_typename)(struct barrier_info* const p)
+static const char* barrier_get_typename(struct barrier_info* const p)
{
tl_assert(p);
- return DRD_(barrier_type_name)(p->barrier_type);
+ return barrier_type_name(p->barrier_type);
}
-static const char* DRD_(barrier_type_name)(const BarrierT bt)
+static const char* barrier_type_name(const BarrierT bt)
{
switch (bt)
{
ULong DRD_(get_barrier_segment_creation_count)(void)
{
- return DRD_(s_barrier_segment_creation_count);
+ return s_barrier_segment_creation_count;
}
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);
/* 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);
}
/**
*/
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
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;
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)
{
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;
}
{
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)
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)
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)
{
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;
};
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.
{
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
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()).
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
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;
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);
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:
/* 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,
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;
}
/**
DRD_(cond_signal)(cond);
}
-
-/** Called after pthread_cond_destroy(). */
-void DRD_(cond_thread_delete)(const DrdThreadId tid)
-{ }
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 */
/* 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;
}
/**
* 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;
* 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;
}
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;
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",
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,
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: {
p->mutex);
}
VG_(pp_ExeContext)(VG_(get_error_where)(e));
- DRD_(first_observed)(p->mutex);
+ first_observed(p->mutex);
break;
}
case CondErr: {
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: {
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: {
" 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: {
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: {
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: {
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: {
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: {
}
}
-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))
{
}
}
-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;
}
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))
{
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))
{
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);
}
} SemaphoreErrInfo;
typedef struct {
- Addr barrier;
+ Addr barrier;
+ DrdThreadId other_tid;
+ ExeContext* other_context;
} BarrierErrInfo;
typedef struct {
/* 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. */
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
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;
}
/** 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",
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)(),
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",
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",
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",
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)
{
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",
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),
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++;
}
}
}
/** 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);
* 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;
}
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);
}
/**
- * 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)
/*
* 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)
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;
}
/* 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. */
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;
}
/** 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;
* 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;
}
}
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);
/* 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. */
/** 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;
}
/**
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;
* 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;
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",
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",
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",
}
DRD_(sg_put)(sg);
DRD_(thread_new_segment)(tid);
- DRD_(s_semaphore_segment_creation_count)++;
+ s_semaphore_segment_creation_count++;
}
}
}
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",
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. */
/* 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;
}
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);
#include "drd_error.h"
#include "drd_barrier.h"
+#include "drd_clientobj.h"
#include "drd_cond.h"
#include "drd_mutex.h"
#include "drd_segment.h"
- 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);
}
/**