drd_clientreq.h \
drd_cond.h \
drd_error.h \
+ drd_hb.h \
drd_load_store.h \
drd_malloc_wrappers.h \
drd_mutex.h \
drd_clientreq.c \
drd_cond.c \
drd_error.c \
+ drd_hb.c \
drd_load_store.c \
drd_main.c \
drd_malloc_wrappers.c \
struct barrier_thread_info
{
UWord tid; // A DrdThreadId declared as UWord because
- // this member variable is the key of an OSet.
+ // this member variable is the key of an OSet.
Word iteration; // iteration of last pthread_barrier_wait()
- // call thread tid participated in.
+ // call thread tid participated in.
Segment* sg[2]; // Segments of the last two
- // pthread_barrier() calls by thread tid.
+ // pthread_barrier() calls by thread tid.
ExeContext* wait_call_ctxt;// call stack for *_barrier_wait() call.
Segment* post_wait_sg; // Segment created after *_barrier_wait() finished
};
if (p == 0)
{
- GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+ GenericErrInfo GEI = {
+ .tid = DRD_(thread_get_running_tid)(),
+ .addr = barrier,
+ };
VG_(maybe_record_error)(VG_(get_running_tid)(),
GenericErr,
VG_(get_IP)(VG_(get_running_tid)()),
{
case ClientMutex: return "mutex";
case ClientCondvar: return "cond";
+ case ClientHbvar: return "order annotation";
case ClientSemaphore: return "semaphore";
case ClientBarrier: return "barrier";
case ClientRwlock: return "rwlock";
typedef enum {
ClientMutex = 1,
ClientCondvar = 2,
- ClientSemaphore = 3,
- ClientBarrier = 4,
- ClientRwlock = 5,
+ ClientHbvar = 3,
+ ClientSemaphore = 4,
+ ClientBarrier = 5,
+ ClientRwlock = 6,
} ObjType;
struct any
ExeContext* first_observed_at;
int waiter_count;
Addr mutex; // Client mutex specified in pthread_cond_wait() call, and
- // null if no client threads are currently waiting on this cond.var.
+ // null if no client threads are currently waiting on this cond.var.
+};
+
+struct hb_info
+{
+ Addr a1;
+ ObjType type;
+ void (*cleanup)(union drd_clientobj*);
+ void (*delete_thread)(union drd_clientobj*, DrdThreadId);
+ ExeContext* first_observed_at;
+ OSet* oset; // Per-thread order annotation information.
+ Bool done; // Whether happens-done has already been invoked.
};
struct semaphore_info
struct any any;
struct mutex_info mutex;
struct cond_info cond;
+ struct hb_info hb;
struct semaphore_info semaphore;
struct barrier_info barrier;
struct rwlock_info rwlock;
#include "drd_clientreq.h"
#include "drd_cond.h"
#include "drd_error.h"
+#include "drd_hb.h"
#include "drd_load_store.h"
#include "drd_malloc_wrappers.h"
#include "drd_mutex.h"
case VG_USERREQ__FREELIKE_BLOCK:
if (arg[1] && ! DRD_(freelike_block)(vg_tid, arg[1]/*addr*/))
{
- GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+ GenericErrInfo GEI = {
+ .tid = DRD_(thread_get_running_tid)(),
+ .addr = 0,
+ };
VG_(maybe_record_error)(vg_tid,
GenericErr,
VG_(get_IP)(vg_tid),
break;
case VG_USERREQ__DRD_ANNOTATE_HAPPENS_BEFORE:
- {
- struct cond_info* const cond_p = DRD_(cond_get)(arg[1]);
- if (! cond_p)
- {
- DRD_(mutex_init)(arg[1], mutex_type_order_annotation);
- DRD_(mutex_pre_lock)(arg[1], mutex_type_order_annotation, False);
- DRD_(mutex_post_lock)(arg[1], mutex_type_order_annotation, False);
- DRD_(mutex_unlock)(arg[1], mutex_type_order_annotation);
- }
- }
+ DRD_(hb_happens_before)(drd_tid, arg[1]);
break;
case VG_USERREQ__DRD_ANNOTATE_HAPPENS_AFTER:
- {
- struct cond_info* const cond_p = DRD_(cond_get)(arg[1]);
- if (! cond_p)
- {
- DRD_(mutex_pre_lock)(arg[1], mutex_type_order_annotation, False);
- DRD_(mutex_post_lock)(arg[1], mutex_type_order_annotation, False);
- DRD_(mutex_unlock)(arg[1], mutex_type_order_annotation);
- }
- }
+ DRD_(hb_happens_after)(drd_tid, arg[1]);
+ break;
+
+ case VG_USERREQ__DRD_ANNOTATE_HAPPENS_DONE:
+ DRD_(hb_happens_done)(drd_tid, arg[1]);
break;
case VG_USERREQ__DRD_ANNOTATE_RWLOCK_CREATE:
mutex_type_errorcheck_mutex = 2,
mutex_type_default_mutex = 3,
mutex_type_spinlock = 4,
- mutex_type_order_annotation = 5,
} MutexT;
/**
#include "drd_cond.h"
#include "drd_error.h"
#include "drd_mutex.h"
-#include "drd_suppression.h"
#include "pub_tool_errormgr.h" /* VG_(maybe_record_error)() */
#include "pub_tool_libcassert.h" /* tl_assert() */
#include "pub_tool_libcprint.h" /* VG_(printf)() */
#include "pub_tool_machine.h" /* VG_(get_IP)() */
-#include "pub_tool_options.h" /* VG_(clo_backtrace_size) */
#include "pub_tool_threadstate.h" /* VG_(get_running_tid)() */
void DRD_(cond_initialize)(struct cond_info* const p, const Addr cond)
{
tl_assert(cond != 0);
- tl_assert(p->a1 == cond);
- tl_assert(p->type == ClientCondvar);
+ tl_assert(p->a1 == cond);
+ tl_assert(p->type == ClientCondvar);
p->cleanup = (void(*)(DrdClientobj*))(DRD_(cond_cleanup));
p->delete_thread = 0;
{
struct mutex_info* q;
q = &(DRD_(clientobj_get)(p->mutex, ClientMutex)->mutex);
- tl_assert(q);
{
- CondDestrErrInfo cde = { DRD_(thread_get_running_tid)(),
- p->a1, q->a1, q->owner };
+ CondDestrErrInfo cde = {
+ DRD_(thread_get_running_tid)(),
+ p->a1,
+ q ? q->a1 : 0,
+ q ? q->owner : DRD_INVALID_THREADID
+ };
VG_(maybe_record_error)(VG_(get_running_tid)(),
CondDestrErr,
VG_(get_IP)(VG_(get_running_tid)()),
}
}
+/**
+ * Report that the synchronization object at address 'addr' is of the
+ * wrong type.
+ */
+static void wrong_type(const Addr addr)
+{
+ GenericErrInfo gei = {
+ .tid = DRD_(thread_get_running_tid)(),
+ .addr = addr,
+ };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ GenericErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "wrong type of synchronization object",
+ &gei);
+}
+
static struct cond_info* cond_get_or_allocate(const Addr cond)
{
struct cond_info *p;
tl_assert(offsetof(DrdClientobj, cond) == 0);
p = &(DRD_(clientobj_get)(cond, ClientCondvar)->cond);
- if (p == 0)
+ if (p)
+ return p;
+
+ if (DRD_(clientobj_present)(cond, cond + 1))
{
- p = &(DRD_(clientobj_add)(cond, ClientCondvar)->cond);
- DRD_(cond_initialize)(p, cond);
+ wrong_type(cond);
+ return 0;
}
+
+ p = &(DRD_(clientobj_add)(cond, ClientCondvar)->cond);
+ DRD_(cond_initialize)(p, cond);
return p;
}
DRD_(clientobj_remove)(p->a1, ClientCondvar);
}
-/** Called before pthread_cond_wait(). Note: before this function is called,
- * mutex_unlock() has already been called from drd_clientreq.c.
+/**
+ * Called before pthread_cond_wait(). Note: before this function is called,
+ * mutex_unlock() has already been called from drd_clientreq.c.
*/
-int DRD_(cond_pre_wait)(const Addr cond, const Addr mutex)
+void DRD_(cond_pre_wait)(const Addr cond, const Addr mutex)
{
struct cond_info* p;
struct mutex_info* q;
}
p = cond_get_or_allocate(cond);
- tl_assert(p);
+ if (!p)
+ {
+ CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ CondErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "not a condition variable",
+ &cei);
+ return;
+ }
if (p->waiter_count == 0)
{
DRD_(not_a_mutex)(p->mutex);
}
- return ++p->waiter_count;
+ ++p->waiter_count;
}
-/** Called after pthread_cond_wait(). */
-int DRD_(cond_post_wait)(const Addr cond)
+/**
+ * Called after pthread_cond_wait().
+ */
+void DRD_(cond_post_wait)(const Addr cond)
{
struct cond_info* p;
}
p = DRD_(cond_get)(cond);
- if (p)
+ if (!p)
{
- if (p->waiter_count > 0)
+ struct mutex_info* q;
+ q = &(DRD_(clientobj_get)(p->mutex, ClientMutex)->mutex);
{
- --p->waiter_count;
- if (p->waiter_count == 0)
- {
- p->mutex = 0;
- }
+ CondDestrErrInfo cde = {
+ DRD_(thread_get_running_tid)(),
+ p->a1,
+ q ? q->a1 : 0,
+ q ? q->owner : DRD_INVALID_THREADID
+ };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ CondDestrErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "condition variable has been destroyed while"
+ " being waited upon",
+ &cde);
+ }
+ return;
+ }
+
+ if (p->waiter_count > 0)
+ {
+ --p->waiter_count;
+ if (p->waiter_count == 0)
+ {
+ p->mutex = 0;
}
- return p->waiter_count;
}
- return 0;
}
-static void DRD_(cond_signal)(Addr const cond)
+static void cond_signal(const DrdThreadId tid, struct cond_info* const cond_p)
{
const ThreadId vg_tid = VG_(get_running_tid)();
const DrdThreadId drd_tid = DRD_(VgThreadIdToDrdThreadId)(vg_tid);
- struct cond_info* const cond_p = DRD_(cond_get)(cond);
- if (cond_p && cond_p->waiter_count > 0)
+ tl_assert(cond_p);
+
+ if (cond_p->waiter_count > 0)
{
if (DRD_(s_report_signal_unlocked)
- && ! DRD_(mutex_is_locked_by)(cond_p->mutex, drd_tid))
+ && ! DRD_(mutex_is_locked_by)(cond_p->mutex, drd_tid))
{
- /* A signal is sent while the associated mutex has not been locked. */
- /* This can indicate but is not necessarily a race condition. */
- CondRaceErrInfo cei = { .tid = DRD_(thread_get_running_tid)(),
- .cond = cond,
- .mutex = cond_p->mutex,
- };
- VG_(maybe_record_error)(vg_tid,
- CondRaceErr,
- VG_(get_IP)(vg_tid),
- "CondErr",
- &cei);
+ /*
+ * A signal is sent while the associated mutex has not been locked.
+ * This can indicate but is not necessarily a race condition.
+ */
+ CondRaceErrInfo cei = { .tid = DRD_(thread_get_running_tid)(),
+ .cond = cond_p->a1,
+ .mutex = cond_p->mutex,
+ };
+ VG_(maybe_record_error)(vg_tid,
+ CondRaceErr,
+ VG_(get_IP)(vg_tid),
+ "CondErr",
+ &cei);
}
}
else
{
- /* No other thread is waiting for the signal, hence the signal will be */
- /* lost. This is normal in a POSIX threads application. */
+ /*
+ * No other thread is waiting for the signal, hence the signal will
+ * be lost. This is normal in a POSIX threads application.
+ */
}
}
+static void not_initialized(Addr const cond)
+{
+ CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ CondErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "condition variable has not been initialized",
+ &cei);
+}
+
/** Called before pthread_cond_signal(). */
void DRD_(cond_pre_signal)(Addr const cond)
{
+ struct cond_info* p;
+
+ p = DRD_(cond_get)(cond);
if (DRD_(s_trace_cond))
{
VG_(message)(Vg_UserMsg,
cond);
}
- DRD_(cond_signal)(cond);
+ if (!p)
+ {
+ not_initialized(cond);
+ return;
+ }
+
+ cond_signal(DRD_(thread_get_running_tid)(), p);
}
/** Called before pthread_cond_broadcast(). */
void DRD_(cond_pre_broadcast)(Addr const cond)
{
+ struct cond_info* p;
+
if (DRD_(s_trace_cond))
{
VG_(message)(Vg_UserMsg,
cond);
}
- DRD_(cond_signal)(cond);
+ p = DRD_(cond_get)(cond);
+ if (!p)
+ {
+ not_initialized(cond);
+ return;
+ }
+
+ cond_signal(DRD_(thread_get_running_tid)(), p);
}
struct cond_info* DRD_(cond_get)(const Addr cond);
void DRD_(cond_pre_init)(const Addr cond);
void DRD_(cond_post_destroy)(const Addr cond);
-int DRD_(cond_pre_wait)(const Addr cond, const Addr mutex);
-int DRD_(cond_post_wait)(const Addr cond);
+void DRD_(cond_pre_wait)(const Addr cond, const Addr mutex);
+void DRD_(cond_post_wait)(const Addr cond);
void DRD_(cond_pre_signal)(const Addr cond);
void DRD_(cond_pre_broadcast)(const Addr cond);
break;
}
case GenericErr: {
- //GenericErrInfo* gei =(GenericErrInfo*)(VG_(get_error_extra)(e));
+ GenericErrInfo* gei = (GenericErrInfo*)(VG_(get_error_extra)(e));
VG_(message)(Vg_UserMsg, "%s\n", VG_(get_error_string)(e));
VG_(pp_ExeContext)(VG_(get_error_where)(e));
+ if (gei->addr)
+ first_observed(gei->addr);
break;
}
case InvalidThreadId: {
typedef struct {
DrdThreadId tid;
+ Addr addr;
} GenericErrInfo;
typedef struct {
--- /dev/null
+/* -*- mode: C; c-basic-offset: 3; -*- */
+/*
+ This file is part of drd, a thread error detector.
+
+ Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+
+#include "drd_clientobj.h"
+#include "drd_hb.h"
+#include "drd_error.h"
+#include "pub_tool_errormgr.h" /* VG_(maybe_record_error)() */
+#include "pub_tool_libcassert.h" /* tl_assert() */
+#include "pub_tool_libcprint.h" /* VG_(printf)() */
+#include "pub_tool_machine.h" /* VG_(get_IP)() */
+#include "pub_tool_mallocfree.h" /* VG_(malloc)(), VG_(free)()*/
+#include "pub_tool_threadstate.h" /* VG_(get_running_tid)() */
+
+
+/* Type definitions. */
+
+/** Per-thread hb information. */
+struct hb_thread_info
+{
+ UWord tid; // A DrdThreadId declared as UWord because
+ // this member variable is the key of an OSet.
+ Segment* sg; // Segment created before most recent
+ // ANNOTATE_HAPPENS_BEFORE().
+};
+
+
+/* Local functions. */
+
+static void DRD_(hb_cleanup)(struct hb_info* p);
+
+
+/* Local variables. */
+
+static Bool DRD_(s_trace_hb);
+
+
+/* Function definitions. */
+
+void DRD_(hb_set_trace)(const Bool trace_hb)
+{
+ DRD_(s_trace_hb) = trace_hb;
+}
+
+/**
+ * Initialize the structure *p with the specified thread ID.
+ */
+static
+void DRD_(hb_thread_initialize)(struct hb_thread_info* const p,
+ const DrdThreadId tid)
+{
+ p->tid = tid;
+ p->sg = 0;
+}
+
+/**
+ * Deallocate the memory that is owned by members of struct hb_thread_info.
+ */
+static void DRD_(hb_thread_destroy)(struct hb_thread_info* const p)
+{
+ tl_assert(p);
+ DRD_(sg_put)(p->sg);
+}
+
+static
+void DRD_(hb_initialize)(struct hb_info* const p, const Addr hb)
+{
+ tl_assert(hb != 0);
+ tl_assert(p->a1 == hb);
+ tl_assert(p->type == ClientHbvar);
+
+ p->cleanup = (void(*)(DrdClientobj*))(DRD_(hb_cleanup));
+ p->delete_thread = 0;
+ p->oset = VG_(OSetGen_Create)(0, 0, VG_(malloc), "drd.hb",
+ VG_(free));
+ p->done = False;
+}
+
+/**
+ * Free the memory that was allocated by hb_initialize(). Called by
+ * DRD_(clientobj_remove)().
+ */
+static void DRD_(hb_cleanup)(struct hb_info* p)
+{
+ struct hb_thread_info* r;
+
+ tl_assert(p);
+ VG_(OSetGen_ResetIter)(p->oset);
+ for ( ; (r = VG_(OSetGen_Next)(p->oset)) != 0; )
+ DRD_(hb_thread_destroy)(r);
+ VG_(OSetGen_Destroy)(p->oset);
+}
+
+/**
+ * Report that the synchronization object at address 'addr' is of the
+ * wrong type.
+ */
+static void wrong_type(const Addr addr)
+{
+ GenericErrInfo gei = {
+ .tid = DRD_(thread_get_running_tid)(),
+ .addr = addr,
+ };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ GenericErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "wrong type of synchronization object",
+ &gei);
+}
+
+struct hb_info* DRD_(hb_get_or_allocate)(const Addr hb)
+{
+ struct hb_info *p;
+
+ tl_assert(offsetof(DrdClientobj, hb) == 0);
+ p = &(DRD_(clientobj_get)(hb, ClientHbvar)->hb);
+ if (p)
+ return p;
+
+ if (DRD_(clientobj_present)(hb, hb + 1))
+ {
+ wrong_type(hb);
+ return 0;
+ }
+
+ p = &(DRD_(clientobj_add)(hb, ClientHbvar)->hb);
+ DRD_(hb_initialize)(p, hb);
+ return p;
+}
+
+struct hb_info* DRD_(hb_get)(const Addr hb)
+{
+ tl_assert(offsetof(DrdClientobj, hb) == 0);
+ return &(DRD_(clientobj_get)(hb, ClientHbvar)->hb);
+}
+
+/** Called because of a happens-before annotation. */
+void DRD_(hb_happens_before)(const DrdThreadId tid, Addr const hb)
+{
+ const ThreadId vg_tid = VG_(get_running_tid)();
+ const DrdThreadId drd_tid = DRD_(VgThreadIdToDrdThreadId)(vg_tid);
+ const UWord word_tid = tid;
+ struct hb_info* p;
+ struct hb_thread_info* q;
+
+ p = DRD_(hb_get_or_allocate)(hb);
+ if (DRD_(s_trace_hb))
+ {
+ VG_(message)(Vg_UserMsg,
+ "[%d] happens_before 0x%lx\n",
+ DRD_(thread_get_running_tid)(),
+ hb);
+ }
+
+ if (!p)
+ return;
+
+ if (p->done)
+ {
+ GenericErrInfo gei = {
+ .tid = DRD_(thread_get_running_tid)(),
+ .addr = hb,
+ };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ GenericErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "happens-before after happens-after",
+ &gei);
+ return;
+ }
+
+ /* Allocate the per-thread data structure if necessary. */
+ q = VG_(OSetGen_Lookup)(p->oset, &word_tid);
+ if (!q)
+ {
+ q = VG_(OSetGen_AllocNode)(p->oset, sizeof(*q));
+ DRD_(hb_thread_initialize)(q, tid);
+ VG_(OSetGen_Insert)(p->oset, q);
+ tl_assert(VG_(OSetGen_Lookup)(p->oset, &word_tid) == q);
+ }
+
+ /*
+ * Store a pointer to the latest segment of the current thread in the
+ * per-thread data structure.
+ */
+ DRD_(thread_get_latest_segment)(&q->sg, tid);
+ DRD_(thread_new_segment)(drd_tid);
+}
+
+/** Called because of a happens-after annotation. */
+void DRD_(hb_happens_after)(const DrdThreadId tid, const Addr hb)
+{
+ struct hb_info* p;
+ struct hb_thread_info* q;
+ VectorClock old_vc;
+
+ p = DRD_(hb_get)(hb);
+
+ if (DRD_(s_trace_hb))
+ {
+ VG_(message)(Vg_UserMsg, "[%d] happens_after 0x%lx\n",
+ DRD_(thread_get_running_tid)(), hb);
+ }
+
+ if (!p)
+ {
+ GenericErrInfo gei = {
+ .tid = DRD_(thread_get_running_tid)(),
+ .addr = hb,
+ };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ GenericErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "missing happens-before annotation",
+ &gei);
+ return;
+ }
+
+ p->done = True;
+
+ /*
+ * Combine all vector clocks that were stored because of happens-before
+ * annotations with the vector clock of the current thread.
+ */
+ DRD_(vc_copy)(&old_vc, &DRD_(g_threadinfo)[tid].last->vc);
+ VG_(OSetGen_ResetIter)(p->oset);
+ for ( ; (q = VG_(OSetGen_Next)(p->oset)) != 0; )
+ {
+ if (q->tid != tid)
+ {
+ tl_assert(q->sg);
+ DRD_(vc_combine)(&DRD_(g_threadinfo)[tid].last->vc, &q->sg->vc);
+ }
+ }
+ DRD_(thread_update_conflict_set)(tid, &old_vc);
+ DRD_(vc_cleanup)(&old_vc);
+}
+
+/** Called because of a happens-done annotation. */
+void DRD_(hb_happens_done)(const DrdThreadId tid, const Addr hb)
+{
+ struct hb_info* p;
+
+ if (DRD_(s_trace_hb))
+ {
+ VG_(message)(Vg_UserMsg, "[%d] happens_done 0x%lx\n",
+ DRD_(thread_get_running_tid)(), hb);
+ }
+
+ p = DRD_(hb_get)(hb);
+ if (!p)
+ {
+ GenericErrInfo gei = {
+ .tid = DRD_(thread_get_running_tid)(),
+ .addr = hb,
+ };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ GenericErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "missing happens-before annotation",
+ &gei);
+ return;
+ }
+
+ DRD_(clientobj_remove)(p->a1, ClientHbvar);
+}
--- /dev/null
+/* -*- mode: C; c-basic-offset: 3; -*- */
+/*
+ This file is part of drd, a thread error detector.
+
+ Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+
+#ifndef __DRD_HB_H
+#define __DRD_HB_H
+
+
+#include "drd_thread.h" /* DrdThreadid */
+#include "pub_tool_basics.h" /* Addr */
+
+
+/* Forward declarations. */
+
+struct hb_info;
+
+
+/* Function declarations. */
+
+void DRD_(hb_set_trace)(const Bool trace_hb);
+struct hb_info* DRD_(hb_get)(const Addr hb);
+struct hb_info* DRD_(hb_get_or_allocate)(const Addr hb);
+void DRD_(hb_init)(const Addr hb);
+void DRD_(hb_destroy)(const Addr hb);
+void DRD_(hb_happens_after)(const DrdThreadId tid, const Addr hb);
+void DRD_(hb_happens_before)(const DrdThreadId tid, const Addr hb);
+void DRD_(hb_happens_done)(const DrdThreadId tid, const Addr hb);
+
+
+#endif /* __DRD_HB_H */
p->last_locked_segment = 0;
}
-/** Let Valgrind report that there is no mutex object at address 'mutex'. */
+/** Report that address 'mutex' is not the address of a mutex object. */
void DRD_(not_a_mutex)(const Addr mutex)
{
MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
&MEI);
}
+/**
+ * Report that address 'mutex' is not the address of a mutex object of the
+ * expected type.
+ */
+static void wrong_mutex_type(const Addr mutex)
+{
+ MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
+ mutex, -1, DRD_INVALID_THREADID };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ MutexErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "Mutex type mismatch",
+ &MEI);
+}
+
static
struct mutex_info*
DRD_(mutex_get_or_allocate)(const Addr mutex, const MutexT mutex_type)
p = &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex);
if (p)
{
- return p;
+ if (mutex_type == mutex_type_unknown || p->mutex_type == mutex_type)
+ return p;
+ else
+ {
+ wrong_mutex_type(mutex);
+ return 0;
+ }
}
if (DRD_(clientobj_present)(mutex, mutex + 1))
DRD_(clientobj_remove)(mutex, ClientMutex);
}
-/** Called before pthread_mutex_lock() is invoked. If a data structure for
- * the client-side object was not yet created, do this now. Also check whether
- * an attempt is made to lock recursively a synchronization object that must
- * not be locked recursively.
+/**
+ * Called before pthread_mutex_lock() is invoked. If a data structure for the
+ * client-side object was not yet created, do this now. Also check whether an
+ * attempt is made to lock recursively a synchronization object that must not
+ * be locked recursively.
*/
void DRD_(mutex_pre_lock)(const Addr mutex, MutexT mutex_type,
const Bool trylock)
struct mutex_info* p;
p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
- if (mutex_type == mutex_type_unknown)
+ if (p && mutex_type == mutex_type_unknown)
mutex_type = p->mutex_type;
if (s_trace_mutex)
return "mutex";
case mutex_type_spinlock:
return "spinlock";
- case mutex_type_order_annotation:
- return "order annotation mutex";
- default:
- tl_assert(0);
}
+ tl_assert(0);
return "?";
}
if (DRD_(clientobj_present)(rwlock, rwlock + 1))
{
- GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+ GenericErrInfo GEI = {
+ .tid = DRD_(thread_get_running_tid)(),
+ .addr = rwlock,
+ };
VG_(maybe_record_error)(VG_(get_running_tid)(),
GenericErr,
VG_(get_IP)(VG_(get_running_tid)()),
p = DRD_(rwlock_get)(rwlock);
if (p == 0)
{
- GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+ GenericErrInfo GEI = {
+ .tid = DRD_(thread_get_running_tid)(),
+ .addr = rwlock,
+ };
VG_(maybe_record_error)(VG_(get_running_tid)(),
GenericErr,
VG_(get_IP)(VG_(get_running_tid)()),
p = DRD_(rwlock_get)(rwlock);
if (p == 0)
{
- GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+ GenericErrInfo GEI = {
+ .tid = DRD_(thread_get_running_tid)(),
+ .addr = rwlock,
+ };
VG_(maybe_record_error)(VG_(get_running_tid)(),
GenericErr,
VG_(get_IP)(VG_(get_running_tid)()),
if (p == 0)
{
- GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+ GenericErrInfo GEI = {
+ .tid = DRD_(thread_get_running_tid)(),
+ .addr = semaphore,
+ };
VG_(maybe_record_error)(VG_(get_running_tid)(),
GenericErr,
VG_(get_IP)(VG_(get_running_tid)()),
if (p == 0)
{
- GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+ GenericErrInfo GEI = {
+ .tid = DRD_(thread_get_running_tid)(),
+ .addr = semaphore,
+ };
VG_(maybe_record_error)(VG_(get_running_tid)(),
GenericErr,
VG_(get_IP)(VG_(get_running_tid)()),