Replaced code for suppressing the stack memory in use at the time a
thread is being created by code for suppressing the memory allocated
from inside the pthread_create() call. The new implementation should be
a more portable solution for suppressing data races triggered by the
thread-local-storage implementation of a Pthreads library.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10584 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/drd/drd_clientreq.c b/drd/drd_clientreq.c
index 3aca2d7..82820a1 100644
--- a/drd/drd_clientreq.c
+++ b/drd/drd_clientreq.c
@@ -47,7 +47,9 @@
/* Local function declarations. */
static Bool handle_client_request(ThreadId vg_tid, UWord* arg, UWord* ret);
+#if 0
static Addr highest_used_stack_address(const ThreadId vg_tid);
+#endif
/* Function definitions. */
@@ -175,6 +177,7 @@
case VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK:
{
+#if 0
const Addr topmost_sp = highest_used_stack_address(vg_tid);
#if 0
UInt nframes;
@@ -201,6 +204,7 @@
DRD_(thread_set_stack_startup)(drd_tid, VG_(get_SP)(vg_tid));
DRD_(start_suppression)(topmost_sp, VG_(thread_get_stack_max)(vg_tid),
"stack top");
+#endif
break;
}
@@ -235,6 +239,14 @@
(Bool)arg[2]);
break;
+ case VG_USERREQ__ENTERING_PTHREAD_CREATE:
+ DRD_(thread_entering_pthread_create)(drd_tid);
+ break;
+
+ case VG_USERREQ__LEFT_PTHREAD_CREATE:
+ DRD_(thread_left_pthread_create)(drd_tid);
+ break;
+
case VG_USERREQ__POST_THREAD_JOIN:
tl_assert(arg[1]);
DRD_(thread_post_join)(drd_tid, DRD_(PtThreadIdToDrdThreadId)(arg[1]));
@@ -492,6 +504,7 @@
return True;
}
+#if 0
/**
* Walk the stack up to the highest stack frame, and return the stack pointer
* of the highest stack frame. It is assumed that there are no more than
@@ -535,3 +548,4 @@
return husa;
}
+#endif
diff --git a/drd/drd_clientreq.h b/drd/drd_clientreq.h
index 190ead5..c282a73 100644
--- a/drd/drd_clientreq.h
+++ b/drd/drd_clientreq.h
@@ -62,6 +62,13 @@
VG_USERREQ__SET_JOINABLE,
/* args: pthread_t, Bool */
+ /* Tell DRD that the calling thread is about to enter pthread_create(). */
+ VG_USERREQ__ENTERING_PTHREAD_CREATE,
+ /* args: (none) */
+ /* Tell DRD that the calling thread has left pthread_create(). */
+ VG_USERREQ__LEFT_PTHREAD_CREATE,
+ /* args: (none) */
+
/* To notify drd that a thread finished because */
/* pthread_thread_join() was called on it. */
VG_USERREQ__POST_THREAD_JOIN,
diff --git a/drd/drd_main.c b/drd/drd_main.c
index b3b3708..ed6f269 100644
--- a/drd/drd_main.c
+++ b/drd/drd_main.c
@@ -291,6 +291,11 @@
{
DRD_(trace_mem_access)(a1, len, eStart);
}
+
+ if (UNLIKELY(DRD_(running_thread_inside_pthread_create)()))
+ {
+ DRD_(start_suppression)(a1, a1 + len, "pthread_create()");
+ }
}
static void drd_start_using_mem_w_ecu(const Addr a1,
diff --git a/drd/drd_pthread_intercepts.c b/drd/drd_pthread_intercepts.c
index b2ef018..b9ef24f 100644
--- a/drd/drd_pthread_intercepts.c
+++ b/drd/drd_pthread_intercepts.c
@@ -191,8 +191,25 @@
tid, joinable, 0, 0, 0);
}
+/** Tell DRD that the calling thread is about to enter pthread_create(). */
+static __inline__ void DRD_(entering_pthread_create)(void)
+{
+ int res;
+ VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__ENTERING_PTHREAD_CREATE,
+ 0, 0, 0, 0, 0);
+}
+
+/** Tell DRD that the calling thread has left pthread_create(). */
+static __inline__ void DRD_(left_pthread_create)(void)
+{
+ int res;
+ VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__LEFT_PTHREAD_CREATE,
+ 0, 0, 0, 0, 0);
+}
+
/**
- * The function called from the thread created by pthread_create().
+ * Entry point for newly created threads. This function is called from the
+ * thread created by pthread_create().
*/
static void* DRD_(thread_wrapper)(void* arg)
{
@@ -300,7 +317,8 @@
/*
- * Note: as of today there exist three different versions of pthread_create:
+ * Note: as of today there exist three different versions of pthread_create
+ * in Linux:
* - pthread_create@GLIBC_2.0
* - pthread_create@@GLIBC_2.1
* - pthread_create@@GLIBC_2.2.5
@@ -360,7 +378,10 @@
assert(thread_args_p->detachstate == PTHREAD_CREATE_JOINABLE
|| thread_args_p->detachstate == PTHREAD_CREATE_DETACHED);
+
+ DRD_(entering_pthread_create)();
CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), thread_args_p);
+ DRD_(left_pthread_create)();
#if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
if (ret == 0)
diff --git a/drd/drd_thread.c b/drd/drd_thread.c
index 04ec912..528b7b3 100644
--- a/drd/drd_thread.c
+++ b/drd/drd_thread.c
@@ -184,6 +184,7 @@
DRD_(thread_set_name)(i, "");
DRD_(g_threadinfo)[i].is_recording_loads = True;
DRD_(g_threadinfo)[i].is_recording_stores = True;
+ DRD_(g_threadinfo)[i].pthread_create_nesting_level = 0;
DRD_(g_threadinfo)[i].synchr_nesting = 0;
tl_assert(DRD_(g_threadinfo)[i].first == 0);
tl_assert(DRD_(g_threadinfo)[i].last == 0);
@@ -520,6 +521,28 @@
DRD_(g_threadinfo)[tid].detached_posix_thread = ! joinable;
}
+/** Tells DRD that the calling thread is about to enter pthread_create(). */
+void DRD_(thread_entering_pthread_create)(const DrdThreadId tid)
+{
+ tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
+ && tid != DRD_INVALID_THREADID);
+ tl_assert(DRD_(g_threadinfo)[tid].pt_threadid != INVALID_POSIX_THREADID);
+ tl_assert(DRD_(g_threadinfo)[tid].pthread_create_nesting_level >= 0);
+
+ DRD_(g_threadinfo)[tid].pthread_create_nesting_level++;
+}
+
+/** Tells DRD that the calling thread has left pthread_create(). */
+void DRD_(thread_left_pthread_create)(const DrdThreadId tid)
+{
+ tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
+ && tid != DRD_INVALID_THREADID);
+ tl_assert(DRD_(g_threadinfo)[tid].pt_threadid != INVALID_POSIX_THREADID);
+ tl_assert(DRD_(g_threadinfo)[tid].pthread_create_nesting_level > 0);
+
+ DRD_(g_threadinfo)[tid].pthread_create_nesting_level--;
+}
+
/** Obtain the thread number and the user-assigned thread name. */
const char* DRD_(thread_get_name)(const DrdThreadId tid)
{
diff --git a/drd/drd_thread.h b/drd/drd_thread.h
index 710f905..ea352b9 100644
--- a/drd/drd_thread.h
+++ b/drd/drd_thread.h
@@ -90,6 +90,8 @@
Bool is_recording_loads;
/** Wether recording of memory load accesses is currently enabled. */
Bool is_recording_stores;
+ /** pthread_create() nesting level. */
+ Int pthread_create_nesting_level;
/** Nesting level of synchronization functions called by the client. */
Int synchr_nesting;
} ThreadInfo;
@@ -143,6 +145,8 @@
void DRD_(thread_set_pthreadid)(const DrdThreadId tid, const PThreadId ptid);
Bool DRD_(thread_get_joinable)(const DrdThreadId tid);
void DRD_(thread_set_joinable)(const DrdThreadId tid, const Bool joinable);
+void DRD_(thread_entering_pthread_create)(const DrdThreadId tid);
+void DRD_(thread_left_pthread_create)(const DrdThreadId tid);
const char* DRD_(thread_get_name)(const DrdThreadId tid);
void DRD_(thread_set_name)(const DrdThreadId tid, const char* const name);
void DRD_(thread_set_vg_running_tid)(const ThreadId vg_tid);
@@ -209,7 +213,9 @@
static __inline__
DrdThreadId DRD_(thread_get_running_tid)(void)
{
+#ifdef ENABLE_DRD_CONSISTENCY_CHECKS
tl_assert(DRD_(g_drd_running_tid) != DRD_INVALID_THREADID);
+#endif
return DRD_(g_drd_running_tid);
}
@@ -221,8 +227,19 @@
}
/**
- * Reports whether or not memory access recording is enabled for the
- * currently running thread.
+ * Reports whether or not the currently running client thread is executing code
+ * inside the pthread_create() function.
+ */
+static __inline__
+Bool DRD_(running_thread_inside_pthread_create)(void)
+{
+ return (DRD_(g_threadinfo)[DRD_(g_drd_running_tid)]
+ .pthread_create_nesting_level > 0);
+}
+
+/**
+ * Reports whether or not recording of memory loads is enabled for the
+ * currently running client thread.
*/
static __inline__
Bool DRD_(running_thread_is_recording_loads)(void)
@@ -236,6 +253,10 @@
&& DRD_(g_threadinfo)[DRD_(g_drd_running_tid)].is_recording_loads);
}
+/**
+ * Reports whether or not recording memory stores is enabled for the
+ * currently running client thread.
+ */
static __inline__
Bool DRD_(running_thread_is_recording_stores)(void)
{