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)
 {