|
From: Jeremy F. <je...@go...> - 2005-03-03 05:06:10
|
CVS commit by fitzhardinge:
Thread modelling update. This version fixes up a couple of problems
with error reporting, turns off all the debug output by default, initial
stab at condition variables, but not enough to work, fails gracefully if
function wrapping hasn't managed to capture all the necessary functions.
M +9 -19 core.h 1.95
M +3 -1 vg_intercept.c 1.32
M +2 -0 vg_main.c 1.258
M +148 -39 vg_pthreadmodel.c 1.3
M +11 -4 vg_redir.c 1.8
M +32 -10 vg_symtab2.c 1.105
M +207 -59 vg_threadmodel.c 1.4
--- valgrind/coregrind/core.h #1.94:1.95
@@ -549,21 +549,4 @@ struct vg_mallocfunc_info {
extern Bool VG_(sk_malloc_called_by_scheduler);
-/* ---------------------------------------------------------------------
- Exports of vg_threadmodel.c
- ------------------------------------------------------------------ */
-
-extern void VG_(tm_threadcreate)(ThreadId creator, ThreadId tid, Bool detached);
-extern void VG_(tm_threadexit) (ThreadId tid);
-extern void VG_(tm_threadjoin) (ThreadId joiner, ThreadId joinee);
-extern void VG_(tm_switchto) (ThreadId tid);
-
-extern void VG_(tm_mutex_init) (ThreadId tid, Addr mutexp);
-extern void VG_(tm_mutex_destroy)(ThreadId tid, Addr mutexp);
-extern void VG_(tm_mutex_trylock)(ThreadId tid, Addr mutexp);
-extern void VG_(tm_mutex_giveup) (ThreadId tid, Addr mutexp);
-extern void VG_(tm_mutex_acquire)(ThreadId tid, Addr mutexp);
-extern void VG_(tm_mutex_unlock) (ThreadId tid, Addr mutexp);
-
-
/* ---------------------------------------------------------------------
@@ -1108,7 +1091,8 @@ extern Bool VG_(is_wrapper_return)(Addr
/* Primary interface for adding wrappers for client-side functions. */
-extern void VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
+extern CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
const FuncWrapper *wrapper);
+extern Bool VG_(is_resolved)(const CodeRedirect *redir);
/* ---------------------------------------------------------------------
@@ -1879,4 +1863,10 @@ extern void VG_(tm_error_print) (Error *
extern void VG_(tm_init) ();
+extern void VG_(tm_cond_init) (ThreadId tid, Addr condp);
+extern void VG_(tm_cond_destroy) (ThreadId tid, Addr condp);
+extern void VG_(tm_cond_wait) (ThreadId tid, Addr condp, Addr mutexp);
+extern void VG_(tm_cond_wakeup) (ThreadId tid, Addr condp, Addr mutexp);
+extern void VG_(tm_cond_signal) (ThreadId tid, Addr condp);
+
/* ----- pthreads ----- */
extern void VG_(pthread_init) ();
--- valgrind/coregrind/vg_threadmodel.c #1.3:1.4
@@ -67,4 +67,7 @@ struct mutex;
struct condvar;
+static const Bool debug_thread = False;
+static const Bool debug_mutex = False;
+
/* --------------------------------------------------
Thread lifetime
@@ -194,5 +197,6 @@ static void thread_setstate(struct threa
th->state = state;
-
+ if (debug_thread)
+ VG_(printf)("setting thread(%d) -> %s\n", th->tid, pp_threadstate(th));
thread_validate(th);
}
@@ -272,5 +276,5 @@ static void thread_report(ThreadId tid,
errdata.action = action;
- VG_(maybe_record_error)(tid, ThreadErr, 0, errstr, &errdata);
+ VG_(maybe_record_error)(VG_(get_running_tid)(), ThreadErr, 0, errstr, &errdata);
}
@@ -281,11 +285,13 @@ static void pp_thread_error(Error *err)
Char *errstr = VG_(get_error_string)(err);
- VG_(message)(Vg_UserMsg, "Found %s thread in state %s while %s\n",
+ VG_(message)(Vg_UserMsg, "Found %s thread in state %s while %s",
errstr, pp_threadstate(th), errdata->action);
VG_(pp_ExeContext)(VG_(get_error_where)(err));
- VG_(message)(Vg_UserMsg, "Thread was %s",
- th->state == TS_Dead ? "destroyed" : "created");
+ if (th) {
+ VG_(message)(Vg_UserMsg, " Thread %d was %s",
+ th->tid, th->state == TS_Dead ? "destroyed" : "created");
VG_(pp_ExeContext)(th->ec_created);
+ }
}
@@ -295,4 +301,5 @@ void VG_(tm_thread_create)(ThreadId crea
struct thread *th = thread_get(tid);
+ if (debug_thread)
VG_(printf)("thread %d creates %d %s\n", creator, tid, detached ? "detached" : "");
if (th != NULL) {
@@ -424,5 +431,5 @@ void VG_(tm_thread_join)(ThreadId joiner
/* now the joiner... */
if (joiner == NULL)
- thread_report(joinerid, THE_NotExist, "joining as joiner");
+ thread_report(joineeid, THE_NotExist, "joining as joiner");
else {
switch(joiner->state) {
@@ -433,5 +440,5 @@ void VG_(tm_thread_join)(ThreadId joiner
case TS_Zombie: /* back from the dead */
case TS_Dead:
- thread_report(joinerid, THE_NotAlive, "joining as joiner");
+ thread_report(joineeid, THE_NotAlive, "joining as joiner");
break;
@@ -439,11 +446,11 @@ void VG_(tm_thread_join)(ThreadId joiner
case TS_CVBlocked:
case TS_JoinBlocked:
- thread_report(joinerid, THE_Blocked, "joining as joiner");
+ thread_report(joineeid, THE_Blocked, "joining as joiner");
break;
}
if (joinee->detached)
- thread_report(joinerid, THE_Detached, "joining as joiner");
-
+ thread_report(joineeid, THE_Detached, "joining as joiner");
+ else {
/* block if the joinee hasn't exited yet */
if (joinee) {
@@ -453,5 +460,5 @@ void VG_(tm_thread_join)(ThreadId joiner
default:
- if (joinee->detached || joinee->state == TS_Zombie)
+ if (joinee->state == TS_Zombie)
do_thread_dead(joinee);
else
@@ -460,4 +467,5 @@ void VG_(tm_thread_join)(ThreadId joiner
}
}
+ }
}
@@ -570,5 +578,5 @@ struct mutex_error_data
};
-static struct mutex *mx_get(Addr mutexp);
+static struct mutex *mutex_get(Addr mutexp);
static const Char *pp_mutexstate(const struct mutex *mx)
@@ -615,4 +623,5 @@ static void mutex_setstate(ThreadId tid,
mx->state = st;
+ if (debug_mutex)
VG_(printf)("setting mutex(%p) -> %s\n", mx->mutex, pp_mutexstate(mx));
}
@@ -621,5 +630,5 @@ static void mutex_report(ThreadId tid, A
{
Char *errstr="?";
- struct mutex *mx = mx_get(mutexp);
+ struct mutex *mx = mutex_get(mutexp);
struct mutex_error_data errdata;
@@ -647,5 +656,5 @@ static void pp_mutex_error(Error *err)
Char *errstr = VG_(get_error_string)(err);
- VG_(message)(Vg_UserMsg, "Found %s mutex %p while %s\n",
+ VG_(message)(Vg_UserMsg, "Found %s mutex %p while %s",
errstr, mx ? mx->mutex : 0, errdata->action);
VG_(pp_ExeContext)(VG_(get_error_where)(err));
@@ -656,18 +665,18 @@ static void pp_mutex_error(Error *err)
break;
case MX_Locked:
- VG_(message)(Vg_UserMsg, "Mutex was locked by thread %d", mx->owner);
+ VG_(message)(Vg_UserMsg, " Mutex was locked by thread %d", mx->owner);
VG_(pp_ExeContext)(mx->ec_locked);
break;
case MX_Unlocking:
- VG_(message)(Vg_UserMsg, "Mutex being unlocked");
+ VG_(message)(Vg_UserMsg, " Mutex being unlocked");
VG_(pp_ExeContext)(mx->ec_locked);
break;
case MX_Free:
- VG_(message)(Vg_UserMsg, "Mutex was unlocked");
+ VG_(message)(Vg_UserMsg, " Mutex was unlocked");
VG_(pp_ExeContext)(mx->ec_locked);
break;
}
- VG_(message)(Vg_UserMsg, "Mutex was %s",
+ VG_(message)(Vg_UserMsg, " Mutex was %s",
mx->state == MX_Dead ? "destroyed" : "created");
VG_(pp_ExeContext)(mx->ec_create);
@@ -676,5 +685,5 @@ static void pp_mutex_error(Error *err)
static SkipList sk_mutex = SKIPLIST_INIT(struct mutex, mutex, VG_(cmp_Addr), NULL, VG_AR_CORE);
-static struct mutex *mx_get(Addr mutexp)
+static struct mutex *mutex_get(Addr mutexp)
{
return VG_(SkipList_Find_Exact)(&sk_mutex, &mutexp);
@@ -683,11 +692,13 @@ static struct mutex *mx_get(Addr mutexp)
static Bool mx_is_initialized(Addr mutexp)
{
- const struct mutex *mx = mx_get(mutexp);
+ const struct mutex *mx = mutex_get(mutexp);
return mx && mx->state != MX_Dead;
}
-static void mx_check_initialized(ThreadId tid, Addr mutexp, const Char *action)
+static struct mutex *mutex_check_initialized(ThreadId tid, Addr mutexp, const Char *action)
{
+ struct mutex *mx;
+
vg_assert(tid != VG_INVALID_THREADID);
@@ -696,9 +707,14 @@ static void mx_check_initialized(ThreadI
VG_(tm_mutex_init)(tid, mutexp);
}
+
+ mx = mutex_get(mutexp);
+ vg_assert(mx != NULL);
+
+ return mx;
}
static Bool mx_is_locked(Addr mutexp)
{
- const struct mutex *mx = mx_get(mutexp);
+ const struct mutex *mx = mutex_get(mutexp);
return mx && (mx->state == MX_Locked);
@@ -711,5 +727,5 @@ static Bool mx_is_locked(Addr mutexp)
void VG_(tm_mutex_init)(ThreadId tid, Addr mutexp)
{
- struct mutex *mx = mx_get(mutexp);
+ struct mutex *mx = mutex_get(mutexp);
if (mx == NULL) {
@@ -737,5 +753,5 @@ Bool VG_(tm_mutex_exists)(Addr mutexp)
void VG_(tm_mutex_destroy)(ThreadId tid, Addr mutexp)
{
- struct mutex *mx = mx_get(mutexp);
+ struct mutex *mx = mutex_get(mutexp);
if (mx == NULL)
@@ -774,7 +790,5 @@ void VG_(tm_mutex_trylock)(ThreadId tid,
struct mutex *mx;
- mx_check_initialized(tid, mutexp, "trylocking");
-
- mx = mx_get(mutexp);
+ mx = mutex_check_initialized(tid, mutexp, "trylocking");
thread_block_mutex(tid, mx);
@@ -793,6 +807,5 @@ void VG_(tm_mutex_giveup)(ThreadId tid,
struct mutex *mx;
- mx_check_initialized(tid, mutexp, "giving up");
- mx = mx_get(mutexp);
+ mx = mutex_check_initialized(tid, mutexp, "giving up");
thread_unblock_mutex(tid, mx, "giving up on mutex");
@@ -807,6 +820,5 @@ void VG_(tm_mutex_acquire)(ThreadId tid,
struct mutex *mx;
- mx_check_initialized(tid, mutexp, "acquiring");
- mx = mx_get(mutexp);
+ mx = mutex_check_initialized(tid, mutexp, "acquiring");
switch(mx->state) {
@@ -822,4 +834,5 @@ void VG_(tm_mutex_acquire)(ThreadId tid,
case MX_Locked:
+ if (debug_mutex)
VG_(printf)("mutex=%p mx->state=%s\n", mutexp, pp_mutexstate(mx));
VG_TRACK( post_mutex_unlock, mx->owner, (void *)mutexp );
@@ -847,7 +860,5 @@ void VG_(tm_mutex_tryunlock)(ThreadId ti
struct mutex *mx;
- mx_check_initialized(tid, mutexp, "try-unlocking");
- mx = mx_get(mutexp);
- vg_assert(mx != NULL);
+ mx = mutex_check_initialized(tid, mutexp, "try-unlocking");
th = thread_get(tid);
@@ -895,5 +906,4 @@ void VG_(tm_mutex_tryunlock)(ThreadId ti
mutex_setstate(tid, mx, MX_Unlocking);
- VG_TRACK( post_mutex_unlock, tid, (void *)mutexp );
}
@@ -909,5 +919,5 @@ void VG_(tm_mutex_unlock)(ThreadId tid,
struct thread *th;
- mx_check_initialized(tid, mutexp, "unlocking mutex");
+ mx = mutex_check_initialized(tid, mutexp, "unlocking mutex");
th = thread_get(tid);
@@ -935,7 +945,4 @@ void VG_(tm_mutex_unlock)(ThreadId tid,
}
- mx = mx_get(mutexp);
- vg_assert(mx != NULL);
-
switch(mx->state) {
case MX_Locked:
@@ -951,6 +958,6 @@ void VG_(tm_mutex_unlock)(ThreadId tid,
case MX_Unlocking:
/* OK - we need to complete the unlock */
- mutex_setstate(tid, mx, MX_Free);
VG_TRACK( post_mutex_unlock, tid, (void *)mutexp );
+ mutex_setstate(tid, mx, MX_Free);
break;
@@ -965,9 +972,90 @@ void VG_(tm_mutex_unlock)(ThreadId tid,
-------------------------------------------------- */
+struct condvar_waiter
+{
+ ThreadId waiter;
+
+ struct condvar *condvar;
+ struct mutex *mutex;
+
+ struct condvar_waiter *next;
+};
+
+struct condvar
+{
+ Addr condvar;
+
+ enum condvar_state {
+ CV_Dead,
+ CV_Alive,
+ } state;
+
+ struct condvar_waiter *waiters; // XXX skiplist?
+
+ ExeContext *ec_created; // where created
+ ExeContext *ec_signalled; // where last signalled
+};
+
+enum condvar_err {
+ CVE_NotExist,
+ CVE_NotInit,
+ CVE_ReInit,
+ CVE_Busy,
+ CVE_Blocked,
+};
+
+static SkipList sk_condvar = SKIPLIST_INIT(struct condvar, condvar, VG_(cmp_Addr),
+ NULL, VG_AR_CORE);
+
+static struct condvar *condvar_get(Addr condp)
+{
+ return VG_(SkipList_Find_Exact)(&sk_condvar, &condp);
+}
+
+static Bool condvar_is_initialized(Addr condp)
+{
+ const struct condvar *cv = condvar_get(condp);
+
+ return cv && cv->state != CV_Dead;
+}
+
+static void condvar_report(ThreadId tid, Addr condp, enum condvar_err err, const Char *action)
+{
+}
+
+static struct condvar *condvar_check_initialized(ThreadId tid, Addr condp, const Char *action)
+{
+ struct condvar *cv;
+ vg_assert(tid != VG_INVALID_THREADID);
+
+ if (!condvar_is_initialized(condp)) {
+ condvar_report(tid, condp, CVE_NotInit, action);
+ VG_(tm_cond_init)(tid, condp);
+ }
+
+ cv = condvar_get(condp);
+ vg_assert(cv != NULL);
+
+ return cv;
+}
+
/* Initialize a condition variable. Fails if:
- condp has already been initialized
*/
-void VG_(tm_cond_init)(void *condp)
+void VG_(tm_cond_init)(ThreadId tid, Addr condp)
{
+ struct condvar *cv = condvar_get(condp);
+
+ if (cv == NULL) {
+ cv = VG_(SkipNode_Alloc)(&sk_condvar);
+ cv->condvar = condp;
+ cv->waiters = NULL;
+ VG_(SkipList_Insert)(&sk_condvar, cv);
+ } else if (cv->state != CV_Dead) {
+ condvar_report(tid, condp, CVE_ReInit, "initializing");
+ /* ? what about existing waiters? */
+ }
+
+ cv->state = CV_Alive;
}
@@ -976,6 +1064,27 @@ void VG_(tm_cond_init)(void *condp)
- condp is currently being waited on
*/
-void VG_(tm_cond_destroy)(void *condp)
+void VG_(tm_cond_destroy)(ThreadId tid, Addr condp)
{
+ struct condvar *cv = condvar_get(condp);
+
+ if (cv == NULL)
+ condvar_report(tid, condp, CVE_NotExist, "destroying");
+ else {
+ if (cv->state != CV_Alive)
+ condvar_report(tid, condp, CVE_NotInit, "destroying");
+ if (cv->waiters != NULL)
+ condvar_report(tid, condp, CVE_Busy, "destroying");
+ cv->state = CV_Dead;
+ }
+}
+
+static struct condvar_waiter *get_waiter(const struct condvar *cv, ThreadId tid)
+{
+ struct condvar_waiter *w;
+
+ for(w = cv->waiters; w; w = w->next)
+ if (w->waiter == tid)
+ return w;
+ return NULL;
}
@@ -984,7 +1093,46 @@ void VG_(tm_cond_destroy)(void *condp)
- thread doesn't hold mutexp
- thread is blocked on some other object
+ - thread is already blocked on mutex
*/
-void VG_(tm_cond_wait)(ThreadId tid, void *condp, void *mutexp)
+void VG_(tm_cond_wait)(ThreadId tid, Addr condp, Addr mutexp)
{
+ struct thread *th = thread_get(tid);
+ struct mutex *mx;
+ struct condvar *cv;
+ struct condvar_waiter *waiter;
+
+ /* Condvar must exist */
+ cv = condvar_check_initialized(tid, condp, "waiting");
+
+ /* Mutex must exist */
+ mx = mutex_check_initialized(tid, mutexp, "waiting on condvar");
+
+ /* Thread must own mutex */
+ if (mx->state != MX_Locked) {
+ mutex_report(tid, mutexp, MXE_NotLocked, "waiting on condvar");
+ VG_(tm_mutex_trylock)(tid, mutexp);
+ VG_(tm_mutex_acquire)(tid, mutexp);
+ } else if (mx->owner != tid) {
+ mutex_report(tid, mutexp, MXE_NotOwner, "waiting on condvar");
+ mx->owner = tid;
+ }
+
+ /* Thread must not be already waiting for condvar */
+ waiter = get_waiter(cv, tid);
+ if (waiter != NULL)
+ condvar_report(tid, condp, CVE_Blocked, "waiting");
+ else {
+ waiter = VG_(arena_malloc)(VG_AR_CORE, sizeof(*waiter));
+ waiter->condvar = cv;
+ waiter->mutex = mx;
+ waiter->next = cv->waiters;
+ cv->waiters = waiter;
+ }
+
+ /* Thread is now blocking on condvar */
+ do_thread_block_condvar(th, cv);
+
+ /* (half) release mutex */
+ VG_(tm_mutex_tryunlock)(tid, mutexp);
}
@@ -993,5 +1141,5 @@ void VG_(tm_cond_wait)(ThreadId tid, voi
- thread is not waiting on condp
*/
-void VG_(tm_cond_wakeup)(ThreadId tid, void *condp)
+void VG_(tm_cond_wakeup)(ThreadId tid, Addr condp, Addr mutexp)
{
}
@@ -1000,5 +1148,5 @@ void VG_(tm_cond_wakeup)(ThreadId tid, v
- condp has not been initialized
*/
-void VG_(tm_cond_signal)(ThreadId tid, void *condp)
+void VG_(tm_cond_signal)(ThreadId tid, Addr condp)
{
}
--- valgrind/coregrind/vg_pthreadmodel.c #1.2:1.3
@@ -8,6 +8,6 @@
emulator for monitoring program execution on x86-Unixes.
- Copyright (C) 2000-2004 Julian Seward
- js...@ac...
+ Copyright (C) 2005 Jeremy Fitzhardinge
+ je...@go...
This program is free software; you can redistribute it and/or
@@ -57,6 +57,11 @@
#define __USE_GNU
+#define __USE_UNIX98
#include <pthread.h>
+static const Bool debug = False;
+
+static Bool check_wrappings(void);
+
#define ENTER(x) \
do { \
@@ -68,5 +73,5 @@
static const Char *pp_retval(enum return_type rt, Word retval)
{
- static Char buf[20];
+ static Char buf[50];
switch(rt) {
@@ -127,9 +132,10 @@ static ThreadId get_pthread_mapping(pthr
/* Create a mapping between a ThreadId and a pthread_t */
-void pthread_id_mapping(ThreadId tid, Addr idp, UInt idsz)
+static void pthread_id_mapping(ThreadId tid, Addr idp, UInt idsz)
{
pthread_t id = *(pthread_t *)idp;
struct pthread_map *m = VG_(SkipList_Find_Exact)(&sk_pthread_map, &id);
+ if (debug)
VG_(printf)("Thread %d maps to %p\n", tid, id);
@@ -150,4 +156,5 @@ static void check_thread_exists(ThreadId
{
if (!VG_(tm_thread_exists)(tid)) {
+ if (debug)
VG_(printf)("creating thread %d\n", tid);
VG_(tm_thread_create)(VG_INVALID_THREADID, tid, False);
@@ -174,4 +181,9 @@ static void *before_pthread_create(va_li
void *arg = va_arg(va, void *);
struct pthread_create_nonce *n;
+ struct vg_pthread_newthread_data *data;
+ ThreadState *tst;
+
+ if (!check_wrappings())
+ return NULL;
ENTER(pthread_create);
@@ -179,20 +191,25 @@ static void *before_pthread_create(va_li
/* Data is in the client heap and is freed by the client in the
startfunc_wrapper. */
- if (startfunc_wrapper != 0) {
- struct vg_pthread_newthread_data *data;
- ThreadState *tst = VG_(get_ThreadState)(VG_(get_running_tid)());
+ vg_assert(startfunc_wrapper != 0);
+
+ tst = VG_(get_ThreadState)(VG_(get_running_tid)());
VG_(sk_malloc_called_by_scheduler) = True;
data = SK_(malloc)(sizeof(*data));
VG_(sk_malloc_called_by_scheduler) = False;
+
+ VG_TRACK(pre_mem_write, Vg_CorePThread, tst->tid, "new thread data",
+ (Addr)data, sizeof(*data));
data->startfunc = start;
data->arg = arg;
+ VG_TRACK(post_mem_write, (Addr)data, sizeof(*data));
/* Substitute arguments
- XXX hack: need an API to do this.
- */
+ XXX hack: need an API to do this. */
((Word *)tst->arch.m_esp)[3] = startfunc_wrapper;
((Word *)tst->arch.m_esp)[4] = (Word)data;
- }
+
+ if (debug)
+ VG_(printf)("starting thread at wrapper %p\n", startfunc_wrapper);
n = VG_(arena_malloc)(VG_AR_CORE, sizeof(*n));
@@ -208,4 +225,7 @@ static void after_pthread_create(void *n
ThreadId tid = VG_(get_running_tid)();
+ if (n == NULL)
+ return;
+
if (rt == RT_RETURN && retval == 0) {
if (!VG_(tm_thread_exists)(tid))
@@ -227,8 +247,13 @@ static void *before_pthread_join(va_list
{
pthread_t pt_joinee = va_arg(va, pthread_t);
- ThreadId joinee = get_pthread_mapping(pt_joinee);
+ ThreadId joinee;
+
+ if (!check_wrappings())
+ return NULL;
ENTER(pthread_join);
+ joinee = get_pthread_mapping(pt_joinee);
+
VG_(tm_thread_join)(VG_(get_running_tid)(), joinee);
@@ -239,4 +264,7 @@ static void after_pthread_join(void *v,
{
/* nothing to be done? */
+ if (!check_wrappings())
+ return;
+
LEAVE(pthread_join, rt, retval);
}
@@ -249,9 +277,14 @@ static void *before_pthread_detach(va_li
{
pthread_t id = va_arg(va, pthread_t);
- struct pthread_detach_data *data = VG_(arena_malloc)(VG_AR_CORE, sizeof(*data));
- data->id = id;
+ struct pthread_detach_data *data;
+
+ if (!check_wrappings())
+ return NULL;
ENTER(pthread_detach);
+ data = VG_(arena_malloc)(VG_AR_CORE, sizeof(*data));
+ data->id = id;
+
return data;
}
@@ -260,5 +293,10 @@ static void after_pthread_detach(void *n
{
struct pthread_detach_data *data = (struct pthread_detach_data *)nonce;
- ThreadId tid = get_pthread_mapping(data->id);
+ ThreadId tid;
+
+ if (data == NULL)
+ return;
+
+ tid = get_pthread_mapping(data->id);
VG_(arena_free)(VG_AR_CORE, data);
@@ -277,4 +315,7 @@ static void *before_pthread_self(va_list
to the return value. On Linux/glibc, it's a simple scalar, so it is
returned normally. */
+ if (!check_wrappings())
+ return NULL;
+
ENTER(pthread_self);
@@ -287,4 +328,7 @@ static void after_pthread_self(void *non
pthread_t ret = (pthread_t)retval;
+ if (!check_wrappings())
+ return;
+
pthread_id_mapping(VG_(get_running_tid)(), (Addr)&ret, sizeof(ret));
@@ -323,4 +367,7 @@ static void *before_pthread_mutex_init(v
const pthread_mutexattr_t *attr = va_arg(va, const pthread_mutexattr_t *);
+ if (!check_wrappings())
+ return NULL;
+
ENTER(pthread_mutex_init);
@@ -334,4 +381,7 @@ static void *before_pthread_mutex_init(v
static void after_pthread_mutex_init(void *nonce, enum return_type rt, Word retval)
{
+ if (!check_wrappings())
+ return;
+
if (rt == RT_RETURN && retval == 0)
VG_(tm_mutex_init)(VG_(get_running_tid)(), (Addr)nonce);
@@ -344,4 +394,7 @@ static void *before_pthread_mutex_destro
pthread_mutex_t *mx = va_arg(va, pthread_mutex_t *);
+ if (!check_wrappings())
+ return NULL;
+
ENTER(pthread_mutex_destroy);
@@ -353,4 +406,7 @@ static void *before_pthread_mutex_destro
static void after_pthread_mutex_destroy(void *nonce, enum return_type rt, Word retval)
{
+ if (!check_wrappings())
+ return;
+
LEAVE(pthread_mutex_destroy, rt, retval);
}
@@ -360,6 +416,10 @@ static void *before_pthread_mutex_lock(v
pthread_mutex_t *mx = va_arg(va, pthread_mutex_t *);
+ if (!check_wrappings())
+ return NULL;
+
ENTER(pthread_mutex_lock);
+ if (debug)
VG_(printf)("%d locking %p\n", VG_(get_running_tid)(), mx);
check_thread_exists(VG_(get_running_tid)());
@@ -372,7 +432,11 @@ static void *before_pthread_mutex_lock(v
static void after_pthread_mutex_lock(void *nonce, enum return_type rt, Word retval)
{
+ if (!check_wrappings())
+ return;
+
if (rt == RT_RETURN && retval == 0)
VG_(tm_mutex_acquire)(VG_(get_running_tid)(), (Addr)nonce);
else {
+ if (debug)
VG_(printf)("after mutex_lock failed: rt=%d ret=%d\n", rt, retval);
VG_(tm_mutex_giveup)(VG_(get_running_tid)(), (Addr)nonce);
@@ -386,6 +450,10 @@ static void *before_pthread_mutex_tryloc
pthread_mutex_t *mx = va_arg(va, pthread_mutex_t *);
+ if (!check_wrappings())
+ return NULL;
+
ENTER(pthread_mutex_trylock);
+ if (debug)
VG_(printf)("%d trylocking %p\n", VG_(get_running_tid)(), mx);
check_thread_exists(VG_(get_running_tid)());
@@ -398,7 +466,11 @@ static void *before_pthread_mutex_tryloc
static void after_pthread_mutex_trylock(void *nonce, enum return_type rt, Word retval)
{
+ if (nonce == NULL)
+ return;
+
if (rt == RT_RETURN && retval == 0)
VG_(tm_mutex_acquire)(VG_(get_running_tid)(), (Addr)nonce);
else {
+ if (debug)
VG_(printf)("after mutex_trylock failed: rt=%d ret=%d\n", rt, retval);
VG_(tm_mutex_giveup)(VG_(get_running_tid)(), (Addr)nonce);
@@ -412,5 +484,9 @@ static void *before_pthread_mutex_unlock
pthread_mutex_t *mx = va_arg(va, pthread_mutex_t *);
+ if (!check_wrappings())
+ return NULL;
+
ENTER(pthread_mutex_unlock);
+
VG_(tm_mutex_tryunlock)(VG_(get_running_tid)(), (Addr)mx);
@@ -420,4 +496,7 @@ static void *before_pthread_mutex_unlock
static void after_pthread_mutex_unlock(void *nonce, enum return_type rt, Word retval)
{
+ if (nonce == NULL)
+ return;
+
if (rt == RT_RETURN && retval == 0)
VG_(tm_mutex_unlock)(VG_(get_running_tid)(), (Addr)nonce); /* complete unlock */
@@ -432,4 +511,5 @@ static struct pt_wraps {
const Char *name;
FuncWrapper wrapper;
+ const CodeRedirect *redir;
} wraps[] = {
#define WRAP(func, extra) { #func extra, { before_##func, after_##func } }
@@ -448,4 +528,33 @@ static struct pt_wraps {
};
+/* Check to see if all the wrappers are resolved */
+static Bool check_wrappings()
+{
+ Int i;
+ static Bool ok = True;
+ static Bool checked = False;
+
+ if (checked)
+ return ok;
+
+ for(i = 0; i < sizeof(wraps)/sizeof(*wraps); i++) {
+ if (!VG_(is_resolved)(wraps[i].redir)) {
+ VG_(message)(Vg_DebugMsg, "Pthread wrapper for \"%s\" is not resolved",
+ wraps[i].name);
+ ok = False;
+ }
+ }
+
+ if (startfunc_wrapper == 0) {
+ VG_(message)(Vg_DebugMsg, "Pthread wrapper for thread start function is not resolved");
+ ok = False;
+ }
+
+ if (!ok)
+ VG_(message)(Vg_DebugMsg, "Missing intercepts; model disabled");
+
+ checked = True;
+ return ok;
+}
/*
@@ -457,7 +566,7 @@ void VG_(pthread_init)()
for(i = 0; i < sizeof(wraps)/sizeof(*wraps); i++) {
- VG_(printf)("adding pthread wrapper for %s\n", wraps[i].name);
- //VG_(add_wrapper)("soname:libpthread.so.0", wraps[i].name, &wraps[i].wrapper);
- VG_(add_wrapper)("soname:libpthread.so.0", wraps[i].name, &wraps[i].wrapper);
+ //VG_(printf)("adding pthread wrapper for %s\n", wraps[i].name);
+ wraps[i].redir = VG_(add_wrapper)("soname:libpthread.so.0",
+ wraps[i].name, &wraps[i].wrapper);
}
VG_(tm_init)();
--- valgrind/coregrind/vg_intercept.c #1.31:1.32
@@ -75,5 +75,5 @@ void *VG_WRAPPER(pthread_startfunc_wrapp
static pthread_t (*pthread_selfp)(void);
- //VALGRIND_PRINTF("intercepted thread start: real start is %p(%p)\n", func, arg);
+ //VALGRIND_PRINTF("intercepted thread start: real start is %p(%p)", func, arg);
/* Do this rather than a direct call so we don't make an explicit
@@ -85,4 +85,6 @@ void *VG_WRAPPER(pthread_startfunc_wrapp
if (pthread_selfp != NULL)
(*pthread_selfp)(); /* just calling this is enough */
+ else
+ VALGRIND_PRINTF("pthread_self pointer is NULL!");
/* Free the data the before_pthread_create wrapper left for us. */
--- valgrind/coregrind/vg_redir.c #1.7:1.8
@@ -128,4 +128,9 @@ static inline Bool to_resolved(const Cod
}
+Bool VG_(is_resolved)(const CodeRedirect *redir)
+{
+ return from_resolved(redir) && to_resolved(redir);
+}
+
/* Resolve a redir using si if possible, and add it to the resolved
list */
@@ -141,5 +146,5 @@ Bool VG_(resolve_redir)(CodeRedirect *re
return False;
- resolved = from_resolved(redir) && to_resolved(redir);
+ resolved = VG_(is_resolved)(redir);
if (0 && VG_(clo_trace_redir))
@@ -335,5 +340,5 @@ void VG_(add_redirect_addr)(const Char *
}
-void VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
+CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
const FuncWrapper *wrapper)
{
@@ -363,4 +368,6 @@ void VG_(add_wrapper)(const Char *from_l
unresolved_redir = redir;
}
+
+ return redir;
}
--- valgrind/coregrind/vg_symtab2.c #1.104:1.105
@@ -409,20 +409,42 @@ static Int compare_RiSym(void *va, void
/* Two symbols have the same address. Which name do we prefer?
- The shortest. Always. Hm, well, prefer the ones with '@' symbol versioning in them.
- If they're the same length, then alphabetical.
+ The general rule is to prefer the shorter symbol name. If the
+ symbol contains a '@', which means its versioned, then the length
+ up to the '@' is used for length comparison purposes (so
+ "foo@GLIBC_2.4.2" is considered shorter than "foobar"), but if two
+ symbols have the same length, the one with the version string is
+ preferred. If all else fails, use alphabetical ordering.
*/
static RiSym *prefersym(RiSym *a, RiSym *b)
{
- Int lena, lenb;
- Bool va = VG_(strchr)(a->name, '@') != NULL;
- Bool vb = VG_(strchr)(b->name, '@') != NULL;
+ Int lena, lenb; /* full length */
+ Int vlena, vlenb; /* length without version */
+ const Char *vpa, *vpb;
- lena = VG_(strlen)(a->name);
- lenb = VG_(strlen)(b->name);
- if (va || lena < lenb)
+ vlena = lena = VG_(strlen)(a->name);
+ vlenb = lenb = VG_(strlen)(b->name);
+
+ vpa = VG_(strchr)(a->name, '@');
+ vpb = VG_(strchr)(b->name, '@');
+
+ if (vpa)
+ vlena = vpa - a->name;
+ if (vpb)
+ vlenb = vpb - b->name;
+
+ /* Select the shortest unversioned name */
+ if (vlena < vlenb)
return a;
- else if (vb || lenb < lena)
+ else if (vlenb < vlena)
+ return b;
+
+ /* Equal lengths; select the versioned name */
+ if (vpa && !vpb)
+ return a;
+ if (vpb && !vpa)
return b;
+ /* Either both versioned or neither is versioned; select them
+ alphabetically */
if (VG_(strcmp)(a->name, b->name) < 0)
return a;
--- valgrind/coregrind/vg_main.c #1.257:1.258
@@ -2669,4 +2669,6 @@ void VG_(shutdown_actions)(ThreadId tid)
VGA_(reap_threads)(tid);
+ VG_(clo_model_pthreads) = False;
+
// Clean the client up before the final report
VGA_(final_tidyup)(tid);
|