Eliminated per-thread start/stop recording mechanism, which should make DRD a little bit faster. malloc()/free() is now intercepted on all platforms instead of just on i386.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7519 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/exp-drd/Makefile.am b/exp-drd/Makefile.am
index daca9f2..49c6b34 100644
--- a/exp-drd/Makefile.am
+++ b/exp-drd/Makefile.am
@@ -28,42 +28,47 @@
 vgpreload_exp_drd_x86_linux_so_CCASFLAGS    = $(AM_CCASFLAGS_X86_LINUX)
 vgpreload_exp_drd_x86_linux_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_LINUX)
 vgpreload_exp_drd_x86_linux_so_LDFLAGS      = $(PRELOAD_LDFLAGS_X86_LINUX)\
-                                          $(LIBREPLACEMALLOC_LDFLAGS_X86_LINUX)
+                                        $(LIBREPLACEMALLOC_LDFLAGS_X86_LINUX)
 
 vgpreload_exp_drd_amd64_linux_so_SOURCES      = $(VGPRELOAD_DRD_SOURCES_COMMON)
 vgpreload_exp_drd_amd64_linux_so_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_LINUX)
 vgpreload_exp_drd_amd64_linux_so_CFLAGS       = $(AM_CFLAGS_AMD64_LINUX) $(AM_CFLAGS_PIC)
 vgpreload_exp_drd_amd64_linux_so_CCASFLAGS    = $(AM_CCASFLAGS_AMD64_LINUX)
 vgpreload_exp_drd_amd64_linux_so_DEPENDENCIES =
-vgpreload_exp_drd_amd64_linux_so_LDFLAGS      = $(PRELOAD_LDFLAGS_AMD64_LINUX)
+vgpreload_exp_drd_amd64_linux_so_LDFLAGS      = $(PRELOAD_LDFLAGS_AMD64_LINUX)\
+                                        $(LIBREPLACEMALLOC_LDFLAGS_AMD64_LINUX)
 
 vgpreload_exp_drd_ppc32_linux_so_SOURCES      = $(VGPRELOAD_DRD_SOURCES_COMMON)
 vgpreload_exp_drd_ppc32_linux_so_CPPFLAGS     = $(AM_CPPFLAGS_PPC32_LINUX)
 vgpreload_exp_drd_ppc32_linux_so_CFLAGS       = $(AM_CFLAGS_PPC32_LINUX) $(AM_CFLAGS_PIC)
 vgpreload_exp_drd_ppc32_linux_so_CCASFLAGS    = $(AM_CCASFLAGS_PPC32_LINUX)
 vgpreload_exp_drd_ppc32_linux_so_DEPENDENCIES =
-vgpreload_exp_drd_ppc32_linux_so_LDFLAGS      = $(PRELOAD_LDFLAGS_PPC32_LINUX)
+vgpreload_exp_drd_ppc32_linux_so_LDFLAGS      = $(PRELOAD_LDFLAGS_PPC32_LINUX)\
+                                        $(LIBREPLACEMALLOC_LDFLAGS_PPC32_LINUX)
 
 vgpreload_exp_drd_ppc64_linux_so_SOURCES      = $(VGPRELOAD_DRD_SOURCES_COMMON)
 vgpreload_exp_drd_ppc64_linux_so_CPPFLAGS     = $(AM_CPPFLAGS_PPC64_LINUX)
 vgpreload_exp_drd_ppc64_linux_so_CFLAGS       = $(AM_CFLAGS_PPC64_LINUX) $(AM_CFLAGS_PIC)
 vgpreload_exp_drd_ppc64_linux_so_CCASFLAGS    = $(AM_CCASFLAGS_PPC64_LINUX)
 vgpreload_exp_drd_ppc64_linux_so_DEPENDENCIES =
-vgpreload_exp_drd_ppc64_linux_so_LDFLAGS      = $(PRELOAD_LDFLAGS_PPC64_LINUX)
+vgpreload_exp_drd_ppc64_linux_so_LDFLAGS      = $(PRELOAD_LDFLAGS_PPC64_LINUX)\
+                                        $(LIBREPLACEMALLOC_LDFLAGS_PPC64_LINUX)
 
 vgpreload_exp_drd_ppc32_aix5_so_SOURCES      = $(VGPRELOAD_DRD_SOURCES_COMMON)
 vgpreload_exp_drd_ppc32_aix5_so_CPPFLAGS     = $(AM_CPPFLAGS_PPC32_AIX5)
 vgpreload_exp_drd_ppc32_aix5_so_CFLAGS       = $(AM_CFLAGS_PPC32_AIX5) $(AM_CFLAGS_PIC)
 vgpreload_exp_drd_ppc32_aix5_so_CCASFLAGS    = $(AM_CCASFLAGS_PPC32_AIX5)
 vgpreload_exp_drd_ppc32_aix5_so_DEPENDENCIES =
-vgpreload_exp_drd_ppc32_aix5_so_LDFLAGS      = $(PRELOAD_LDFLAGS_PPC32_AIX5)
+vgpreload_exp_drd_ppc32_aix5_so_LDFLAGS      = $(PRELOAD_LDFLAGS_PPC32_AIX5)\
+                                        $(LIBREPLACEMALLOC_LDFLAGS_PPC32_AIX5)
 
 vgpreload_exp_drd_ppc64_aix5_so_SOURCES      = $(VGPRELOAD_DRD_SOURCES_COMMON)
 vgpreload_exp_drd_ppc64_aix5_so_CPPFLAGS     = $(AM_CPPFLAGS_PPC64_AIX5)
 vgpreload_exp_drd_ppc64_aix5_so_CFLAGS       = $(AM_CFLAGS_PPC64_AIX5) $(AM_CFLAGS_PIC)
 vgpreload_exp_drd_ppc64_aix5_so_CCASFLAGS    = $(AM_CCASFLAGS_PPC64_AIX5)
 vgpreload_exp_drd_ppc64_aix5_so_DEPENDENCIES =
-vgpreload_exp_drd_ppc64_aix5_so_LDFLAGS      = $(PRELOAD_LDFLAGS_PPC64_AIX5)
+vgpreload_exp_drd_ppc64_aix5_so_LDFLAGS      = $(PRELOAD_LDFLAGS_PPC64_AIX5)\
+                                        $(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
 
 
 DRD_SOURCES_COMMON =    \
diff --git a/exp-drd/drd_clientreq.c b/exp-drd/drd_clientreq.c
index 1de6851..07d101b 100644
--- a/exp-drd/drd_clientreq.c
+++ b/exp-drd/drd_clientreq.c
@@ -94,11 +94,11 @@
       break;
 
    case VG_USERREQ__DRD_START_SUPPRESSION:
-      drd_start_suppression(arg[1], arg[1] + arg[2], "client");
+      drd_start_suppression(arg[1], arg[2], "client");
       break;
 
    case VG_USERREQ__DRD_FINISH_SUPPRESSION:
-      drd_finish_suppression(arg[1], arg[1] + arg[2]);
+      drd_finish_suppression(arg[1], arg[2]);
       break;
 
    case VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK:
@@ -110,14 +110,6 @@
       thread_new_segment(PtThreadIdToDrdThreadId(arg[1]));
       break;
 
-   case VG_USERREQ__DRD_START_RECORDING:
-      thread_start_recording(PtThreadIdToDrdThreadId(arg[1]));
-      break;
-
-   case VG_USERREQ__DRD_STOP_RECORDING:
-      thread_stop_recording(PtThreadIdToDrdThreadId(arg[1]));
-      break;
-
    case VG_USERREQ__SET_PTHREADID:
       thread_set_pthreadid(thread_get_running_tid(), arg[1]);
       break;
diff --git a/exp-drd/drd_clientreq.h b/exp-drd/drd_clientreq.h
index 68cf741..daed51f 100644
--- a/exp-drd/drd_clientreq.h
+++ b/exp-drd/drd_clientreq.h
@@ -16,11 +16,11 @@
   /* To tell the drd tool to suppress data race detection on the specified */
   /* address range. */
   VG_USERREQ__DRD_START_SUPPRESSION,
-  /* args: start address, size in bytes */
+  /* args: start address, end address */
   /* To tell the drd tool no longer to suppress data race detection on the */
   /* specified address range. */
   VG_USERREQ__DRD_FINISH_SUPPRESSION,
-  /* args: start address, size in bytes */
+  /* args: start address, end address */
   /* Ask drd to suppress data race reports on all currently allocated stack */
   /* data of the current thread.                                            */
   VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
@@ -29,15 +29,6 @@
   VG_USERREQ__DRD_START_NEW_SEGMENT,
   /* args: POSIX thread ID. */
 
-  /* To tell the drd tool to start again recording memory accesses for the */
-  /* specified thread. */
-  VG_USERREQ__DRD_START_RECORDING,
-  /* args: POSIX thread ID. */
-  /* To tell the drd tool to stop recording memory accesses for the */
-  /* specified thread. */
-  VG_USERREQ__DRD_STOP_RECORDING,
-  /* args: POSIX thread ID. */
-
   /* Tell the core the pthread_t of the running thread */
   VG_USERREQ__SET_PTHREADID,
   /* args: pthread_t. */
diff --git a/exp-drd/drd_intercepts.c b/exp-drd/drd_intercepts.c
index fd2ee2b..4c54f5d 100644
--- a/exp-drd/drd_intercepts.c
+++ b/exp-drd/drd_intercepts.c
@@ -40,7 +40,8 @@
    originates from Valgrind.
    ------------------------------------------------------------------ */
 
-// Make sure pthread_spinlock_t is available on glibc 2.3.2 systems.
+// Make sure pthread_spinlock_t is available when compiling with older glibc
+// versions (2.3 or before).
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
@@ -125,30 +126,7 @@
 {
    int res;
    VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_START_SUPPRESSION,
-                              p, size, 0, 0, 0);
-}
-
-#if 0
-static void vg_finish_suppression(const void* const p, size_t const size)
-{
-   int res;
-   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_FINISH_SUPPRESSION,
-                              p, size, 0, 0, 0);
-}
-#endif
-
-static void vg_start_recording(void)
-{
-   int res;
-   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_START_RECORDING,
-                              pthread_self(), 0, 0, 0, 0);
-}
-
-static void vg_stop_recording(void)
-{
-   int res;
-   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_STOP_RECORDING,
-                              pthread_self(), 0, 0, 0, 0);
+                              p, (char*)p + size, 0, 0, 0);
 }
 
 static void vg_set_joinable(const pthread_t tid, const int joinable)
@@ -249,9 +227,7 @@
    pthread_cond_init(&vgargs.cond, 0);
    pthread_mutex_lock(&vgargs.mutex);
 #endif
-   vg_stop_recording();
    CALL_FN_W_WWWW(ret, fn, thread, attr, vg_thread_wrapper, &vgargs);
-   vg_start_recording();
 #if 0
    pthread_cond_wait(&vgargs.cond, &vgargs.mutex);
    pthread_mutex_unlock(&vgargs.mutex);
diff --git a/exp-drd/drd_main.c b/exp-drd/drd_main.c
index c4de749..67b583f 100644
--- a/exp-drd/drd_main.c
+++ b/exp-drd/drd_main.c
@@ -150,10 +150,8 @@
 {
    Segment* sg;
 
-   thread_set_vg_running_tid(VG_(get_running_tid)());
-
-   if (! thread_is_recording(thread_get_running_tid()))
-      return;
+   tl_assert(thread_get_running_tid()
+             == VgThreadIdToDrdThreadId(VG_(get_running_tid())));
 
 #if 1
    if (drd_trace_mem || (addr == drd_trace_address))
@@ -192,10 +190,8 @@
 {
    Segment* sg;
 
-   thread_set_vg_running_tid(VG_(get_running_tid)());
-
-   if (! thread_is_recording(thread_get_running_tid()))
-      return;
+   tl_assert(thread_get_running_tid()
+             == VgThreadIdToDrdThreadId(VG_(get_running_tid())));
 
 #if 1
    if (drd_trace_mem || (addr == drd_trace_address))
@@ -242,23 +238,50 @@
    }
 }
 
+static void drd_pre_mem_read_asciiz(const CorePart part,
+                                    const ThreadId tid,
+                                    Char* const s,
+                                    const Addr a)
+{
+   const char* p = (void*)a;
+   SizeT size = 0;
+
+   /* Note: the expression '*p' reads client memory and may crash if the */
+   /* client provided an invalid pointer !                               */
+   while (*p)
+   {
+      p++;
+      size++;
+   }
+   // To do: find out what a reasonable upper limit on 'size' is.
+   tl_assert(size < 4096);
+   if (size > 0)
+   {
+      drd_trace_load(a, size);
+   }
+}
+
 static void drd_post_mem_write(const CorePart part,
                                const ThreadId tid,
                                const Addr a,
                                const SizeT size)
 {
+   thread_set_vg_running_tid(VG_(get_running_tid)());
    if (size > 0)
    {
       drd_trace_store(a, size);
    }
 }
 
-static void drd_start_using_mem(const Addr a1, const Addr a2)
+static void drd_start_using_mem(const Addr a1, const SizeT len)
 {
+   const Addr a2 = a1 + len;
+
+   tl_assert(a1 < a2);
+
    thread_set_vg_running_tid(VG_(get_running_tid)());
 
-   if (a1 <= drd_trace_address && drd_trace_address < a2
-       && thread_is_recording(thread_get_running_tid()))
+   if (a1 <= drd_trace_address && drd_trace_address < a2)
    {
       VG_(message)(Vg_UserMsg, "start 0x%lx size %ld %s (tracing 0x%lx)",
                    a1, a2 - a1, thread_get_name(thread_get_running_tid()),
@@ -268,10 +291,13 @@
    }
 }
 
-static void drd_stop_using_mem(const Addr a1, const Addr a2)
+static void drd_stop_using_mem(const Addr a1, const SizeT len)
 {
-   if (a1 <= drd_trace_address && drd_trace_address < a2
-       && thread_is_recording(thread_get_running_tid()))
+   const Addr a2 = a1 + len;
+
+   tl_assert(a1 < a2);
+
+   if (a1 <= drd_trace_address && drd_trace_address < a2)
    {
       VG_(message)(Vg_UserMsg, "end   0x%lx size %ld %s (tracing 0x%lx)",
                    a1, a2 - a1, thread_get_name(thread_get_running_tid()),
@@ -284,13 +310,20 @@
    drd_suppression_stop_using_mem(a1, a2);
 }
 
+static
+void drd_start_using_mem_w_perms(const Addr a, const SizeT len,
+                                 const Bool rr, const Bool ww, const Bool xx)
+{
+   drd_start_using_mem(a, len);
+}
+
 /* Called by the core when the stack of a thread grows, to indicate that */
 /* the addresses in range [ a, a + len [ may now be used by the client.  */
 /* Assumption: stacks grow downward.                                     */
 static void drd_start_using_mem_stack(const Addr a, const SizeT len)
 {
    thread_set_stack_min(thread_get_running_tid(), a - VG_STACK_REDZONE_SZB);
-   drd_start_using_mem(a, a + len);
+   drd_start_using_mem(a, len);
 }
 
 /* Called by the core when the stack of a thread shrinks, to indicate that */
@@ -301,18 +334,17 @@
    thread_set_vg_running_tid(VG_(get_running_tid)());
    thread_set_stack_min(thread_get_running_tid(),
                         a + len - VG_STACK_REDZONE_SZB);
-   drd_stop_using_mem(a, a + len);
+   drd_stop_using_mem(a, len);
 }
 
-static void drd_start_using_mem_mmap(Addr a, SizeT len,
-                                     Bool rr, Bool ww, Bool xx)
+static void drd_start_using_mem_stack_signal(const Addr a, const SizeT len)
 {
-   drd_start_using_mem(a, a + len);
+   drd_start_using_mem(a, len);
 }
 
-static void drd_stop_using_mem_munmap(Addr a, SizeT len)
+static void drd_stop_using_mem_stack_signal(Addr a, SizeT len)
 {
-   drd_stop_using_mem(a, a + len);
+   drd_stop_using_mem(a, len);
 }
 
 static
@@ -797,15 +829,22 @@
                                    drd_print_usage,
                                    drd_print_debug_usage);
 
+   // Error handling.
    drd_register_error_handlers();
 
    // Core event tracking.
    VG_(track_pre_mem_read)         (drd_pre_mem_read);
+   VG_(track_pre_mem_read_asciiz)  (drd_pre_mem_read_asciiz);
    VG_(track_post_mem_write)       (drd_post_mem_write);
+   VG_(track_new_mem_brk)          (drd_start_using_mem);
+   VG_(track_new_mem_mmap)         (drd_start_using_mem_w_perms);
    VG_(track_new_mem_stack)        (drd_start_using_mem_stack);
+   VG_(track_new_mem_stack_signal) (drd_start_using_mem_stack_signal);
+   VG_(track_new_mem_startup)      (drd_start_using_mem_w_perms);
+   VG_(track_die_mem_brk)          (drd_stop_using_mem);
+   VG_(track_die_mem_munmap)       (drd_stop_using_mem);
    VG_(track_die_mem_stack)        (drd_stop_using_mem_stack);
-   VG_(track_new_mem_mmap)         (drd_start_using_mem_mmap);
-   VG_(track_die_mem_munmap)       (drd_stop_using_mem_munmap);
+   VG_(track_die_mem_stack_signal) (drd_stop_using_mem_stack_signal);
    VG_(track_start_client_code)    (drd_start_client_code);
    VG_(track_pre_thread_ll_create) (drd_pre_thread_create);
    VG_(track_pre_thread_first_insn)(drd_post_thread_create);
diff --git a/exp-drd/drd_thread.c b/exp-drd/drd_thread.c
index b233199..6a151d4 100644
--- a/exp-drd/drd_thread.c
+++ b/exp-drd/drd_thread.c
@@ -63,7 +63,6 @@
    /// If true, indicates that there is a corresponding POSIX thread ID and
    /// a corresponding OS thread that is detached.
    Bool      detached_posix_thread;
-   Bool      is_recording;
 } ThreadInfo;
 
 
@@ -155,7 +154,6 @@
          VG_(snprintf)(s_threadinfo[i].name, sizeof(s_threadinfo[i].name),
                        "thread %d", tid);
          s_threadinfo[i].name[sizeof(s_threadinfo[i].name) - 1] = 0;
-         s_threadinfo[i].is_recording  = True;
          if (s_threadinfo[i].first != 0)
             VG_(printf)("drd thread id = %d\n", i);
          tl_assert(s_threadinfo[i].first == 0);
@@ -723,26 +721,6 @@
    }
 }
 
-void thread_start_recording(const DrdThreadId tid)
-{
-   tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
-   tl_assert(! s_threadinfo[tid].is_recording);
-   s_threadinfo[tid].is_recording = True;
-}
-
-void thread_stop_recording(const DrdThreadId tid)
-{
-   tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
-   tl_assert(s_threadinfo[tid].is_recording);
-   s_threadinfo[tid].is_recording = False;
-}
-
-Bool thread_is_recording(const DrdThreadId tid)
-{
-   tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
-   return s_threadinfo[tid].is_recording;
-}
-
 void thread_print_all(void)
 {
    unsigned i;
diff --git a/exp-drd/drd_thread.h b/exp-drd/drd_thread.h
index d08d75c..7e47ed9 100644
--- a/exp-drd/drd_thread.h
+++ b/exp-drd/drd_thread.h
@@ -81,9 +81,6 @@
 void thread_combine_vc(const DrdThreadId joiner, const DrdThreadId joinee);
 void thread_combine_vc2(const DrdThreadId tid, const VectorClock* const vc);
 void thread_stop_using_mem(const Addr a1, const Addr a2);
-void thread_start_recording(const DrdThreadId tid);
-void thread_stop_recording(const DrdThreadId tid);
-Bool thread_is_recording(const DrdThreadId tid);
 void thread_print_all(void);
 void thread_report_races(const DrdThreadId tid);
 void thread_report_races_segment(const DrdThreadId tid,
diff --git a/exp-drd/tests/tc20_verifywrap2.stderr.exp2 b/exp-drd/tests/tc20_verifywrap2.stderr.exp2
index a05efce..92f7898 100644
--- a/exp-drd/tests/tc20_verifywrap2.stderr.exp2
+++ b/exp-drd/tests/tc20_verifywrap2.stderr.exp2
@@ -5,9 +5,6 @@
 
 ---------------- pthread_create/join ----------------
 
-[1/1] mutex_init      recursive mutex 0x........
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 0
-[1/1] mutex_unlock    recursive mutex 0x........ rc 1
 Conflicting store by thread 1 at 0x........ size 2
    at 0x........: main (tc20_verifywrap.c:78)
 Allocation context: unknown
@@ -115,7 +112,8 @@
 [1/1] mutex_destroy   error checking mutex 0x........
 [1/1] mutex_destroy   invalid mutex 0x........
 [1/1] mutex_destroy   invalid mutex 0x........
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
+[1/1] mutex_init      recursive mutex 0x........
+[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 0
 [1/1] mutex_unlock    recursive mutex 0x........ rc 1
 [1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
 [1/1] mutex_unlock    recursive mutex 0x........ rc 1
diff --git a/exp-drd/tests/tc22_exit_w_lock.stderr.exp-64bit b/exp-drd/tests/tc22_exit_w_lock.stderr.exp-64bit
index bcf8ef6..e8139b5 100644
--- a/exp-drd/tests/tc22_exit_w_lock.stderr.exp-64bit
+++ b/exp-drd/tests/tc22_exit_w_lock.stderr.exp-64bit
@@ -1,127 +1,6 @@
 
-Conflicting load by thread 1 at 0x........ size 4
-   at 0x........: __deallocate_stack (in libpthread-?.?.so)
-   by 0x........: pthread_join (in libpthread-?.?.so)
-   by 0x........: pthread_join (drd_intercepts.c:?)
-   by 0x........: main (tc22_exit_w_lock.c:43)
-Allocation context: stack_cache_lock (offset 0, size 4) in libpthread-?.?.so, libpthread.so.0:BSS
-Other segment start (thread 2)
-   (thread finished, call stack no longer available)
-Other segment end (thread 2)
-   (thread finished, call stack no longer available)
-
-Conflicting store by thread 1 at 0x........ size 4
-   at 0x........: __deallocate_stack (in libpthread-?.?.so)
-   by 0x........: pthread_join (in libpthread-?.?.so)
-   by 0x........: pthread_join (drd_intercepts.c:?)
-   by 0x........: main (tc22_exit_w_lock.c:43)
-Allocation context: stack_cache_lock (offset 0, size 4) in libpthread-?.?.so, libpthread.so.0:BSS
-Other segment start (thread 2)
-   (thread finished, call stack no longer available)
-Other segment end (thread 2)
-   (thread finished, call stack no longer available)
-
-Conflicting store by thread 1 at 0x........ size 8
-   at 0x........: __deallocate_stack (in libpthread-?.?.so)
-   by 0x........: pthread_join (in libpthread-?.?.so)
-   by 0x........: pthread_join (drd_intercepts.c:?)
-   by 0x........: main (tc22_exit_w_lock.c:43)
-Allocation context: stack_used (offset 8, size 16) in libpthread-?.?.so, libpthread.so.0:Data
-Other segment start (thread 2)
-   (thread finished, call stack no longer available)
-Other segment end (thread 2)
-   (thread finished, call stack no longer available)
-
-Conflicting store by thread 1 at 0x........ size 8
-   at 0x........: __deallocate_stack (in libpthread-?.?.so)
-   by 0x........: pthread_join (in libpthread-?.?.so)
-   by 0x........: pthread_join (drd_intercepts.c:?)
-   by 0x........: main (tc22_exit_w_lock.c:43)
-Allocation context: stack_used (offset 0, size 16) in libpthread-?.?.so, libpthread.so.0:Data
-Other segment start (thread 2)
-   (thread finished, call stack no longer available)
-Other segment end (thread 2)
-   (thread finished, call stack no longer available)
-
-Conflicting load by thread 1 at 0x........ size 8
-   at 0x........: __deallocate_stack (in libpthread-?.?.so)
-   by 0x........: pthread_join (in libpthread-?.?.so)
-   by 0x........: pthread_join (drd_intercepts.c:?)
-   by 0x........: main (tc22_exit_w_lock.c:43)
-Allocation context: stack_cache (offset 0, size 16) in libpthread-?.?.so, libpthread.so.0:Data
-Other segment start (thread 2)
-   (thread finished, call stack no longer available)
-Other segment end (thread 2)
-   (thread finished, call stack no longer available)
-
-Conflicting store by thread 1 at 0x........ size 8
-   at 0x........: __deallocate_stack (in libpthread-?.?.so)
-   by 0x........: pthread_join (in libpthread-?.?.so)
-   by 0x........: pthread_join (drd_intercepts.c:?)
-   by 0x........: main (tc22_exit_w_lock.c:43)
-Allocation context: stack_cache (offset 8, size 16) in libpthread-?.?.so, libpthread.so.0:Data
-Other segment start (thread 2)
-   (thread finished, call stack no longer available)
-Other segment end (thread 2)
-   (thread finished, call stack no longer available)
-
-Conflicting store by thread 1 at 0x........ size 8
-   at 0x........: __deallocate_stack (in libpthread-?.?.so)
-   by 0x........: pthread_join (in libpthread-?.?.so)
-   by 0x........: pthread_join (drd_intercepts.c:?)
-   by 0x........: main (tc22_exit_w_lock.c:43)
-Allocation context: stack_cache (offset 0, size 16) in libpthread-?.?.so, libpthread.so.0:Data
-Other segment start (thread 2)
-   (thread finished, call stack no longer available)
-Other segment end (thread 2)
-   (thread finished, call stack no longer available)
-
-Conflicting load by thread 1 at 0x........ size 8
-   at 0x........: __deallocate_stack (in libpthread-?.?.so)
-   by 0x........: pthread_join (in libpthread-?.?.so)
-   by 0x........: pthread_join (drd_intercepts.c:?)
-   by 0x........: main (tc22_exit_w_lock.c:43)
-Allocation context: stack_cache_actsize (offset 0, size 8) in libpthread-?.?.so, libpthread.so.0:BSS
-Other segment start (thread 2)
-   (thread finished, call stack no longer available)
-Other segment end (thread 2)
-   (thread finished, call stack no longer available)
-
-Conflicting store by thread 1 at 0x........ size 8
-   at 0x........: __deallocate_stack (in libpthread-?.?.so)
-   by 0x........: pthread_join (in libpthread-?.?.so)
-   by 0x........: pthread_join (drd_intercepts.c:?)
-   by 0x........: main (tc22_exit_w_lock.c:43)
-Allocation context: stack_cache_actsize (offset 0, size 8) in libpthread-?.?.so, libpthread.so.0:BSS
-Other segment start (thread 2)
-   (thread finished, call stack no longer available)
-Other segment end (thread 2)
-   (thread finished, call stack no longer available)
-
-Conflicting load by thread 1 at 0x........ size 4
-   at 0x........: __deallocate_stack (in libpthread-?.?.so)
-   by 0x........: pthread_join (in libpthread-?.?.so)
-   by 0x........: pthread_join (drd_intercepts.c:?)
-   by 0x........: main (tc22_exit_w_lock.c:43)
-Allocation context: stack_cache_lock (offset 0, size 4) in libpthread-?.?.so, libpthread.so.0:BSS
-Other segment start (thread 2)
-   (thread finished, call stack no longer available)
-Other segment end (thread 2)
-   (thread finished, call stack no longer available)
-
-Conflicting store by thread 1 at 0x........ size 4
-   at 0x........: __deallocate_stack (in libpthread-?.?.so)
-   by 0x........: pthread_join (in libpthread-?.?.so)
-   by 0x........: pthread_join (drd_intercepts.c:?)
-   by 0x........: main (tc22_exit_w_lock.c:43)
-Allocation context: stack_cache_lock (offset 0, size 4) in libpthread-?.?.so, libpthread.so.0:BSS
-Other segment start (thread 2)
-   (thread finished, call stack no longer available)
-Other segment end (thread 2)
-   (thread finished, call stack no longer available)
-
 Mutex still locked at thread exit: address 0x........, recursion count 1, owner 3.
    at 0x........: pthread_join (drd_intercepts.c:?)
    by 0x........: main (tc22_exit_w_lock.c:43)
 
-ERROR SUMMARY: 12 errors from 12 contexts (suppressed: 0 from 0)
+ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)