drd: Ignore ordering introduced by a mutex used in the thread creation wrapper

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14015 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/drd/drd.h b/drd/drd.h
index f82c2b2..1e96857 100644
--- a/drd/drd.h
+++ b/drd/drd.h
@@ -488,6 +488,10 @@
    VG_USERREQ__DRD_ANNOTATE_SEM_POST_PRE,
    /* args: Addr. */
 
+   /* Tell DRD to ignore the inter-thread ordering introduced by a mutex. */
+   VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
+   /* args: Addr. */
+
    /* Tell DRD that a user-defined reader-writer synchronization object
     * has been created. */
    VG_USERREQ__DRD_ANNOTATE_RWLOCK_CREATE
diff --git a/drd/drd_clientobj.h b/drd/drd_clientobj.h
index d615d79..b3190ab 100644
--- a/drd/drd_clientobj.h
+++ b/drd/drd_clientobj.h
@@ -68,6 +68,7 @@
    ExeContext*     first_observed_at;
    MutexT          mutex_type;      // pthread_mutex_t or pthread_spinlock_t.
    int             recursion_count; // 0 if free, >= 1 if locked.
+   Bool            ignore_ordering;
    DrdThreadId     owner;           // owner if locked, last owner if free.
    struct segment* last_locked_segment;
    ULong           acquiry_time_ms;
diff --git a/drd/drd_clientreq.c b/drd/drd_clientreq.c
index 92ac92a..a3d485f 100644
--- a/drd/drd_clientreq.c
+++ b/drd/drd_clientreq.c
@@ -378,6 +378,10 @@
       DRD_(thread_leave_synchr)(drd_tid);
       break;
 
+   case VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING:
+      DRD_(mutex_ignore_ordering)(arg[1]);
+      break;
+
    case VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK:
       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
          DRD_(spinlock_init_or_unlock)(arg[1]);
diff --git a/drd/drd_mutex.c b/drd/drd_mutex.c
index 12ee4de..76cabcf 100644
--- a/drd/drd_mutex.c
+++ b/drd/drd_mutex.c
@@ -76,12 +76,30 @@
       = (void(*)(DrdClientobj*, DrdThreadId))mutex_delete_thread;
    p->mutex_type          = mutex_type;
    p->recursion_count     = 0;
+   p->ignore_ordering     = False;
    p->owner               = DRD_INVALID_THREADID;
    p->last_locked_segment = 0;
    p->acquiry_time_ms     = 0;
    p->acquired_at         = 0;
 }
 
+void DRD_(mutex_ignore_ordering)(const Addr mutex)
+{
+   struct mutex_info* p = DRD_(mutex_get)(mutex);
+
+   if (s_trace_mutex)
+      DRD_(trace_msg)("[%d] mutex_ignore_ordering %s 0x%lx",
+                      DRD_(thread_get_running_tid)(),
+                      p ? DRD_(mutex_type_name)(p->mutex_type) : "(?)",
+                      mutex);
+
+   if (p) {
+      p->ignore_ordering = True;
+   } else {
+      DRD_(not_a_mutex)(mutex);
+   }
+}
+
 /** Deallocate the memory that was allocated by mutex_initialize(). */
 static void mutex_cleanup(struct mutex_info* p)
 {
@@ -302,17 +320,18 @@
       return;
 
    if (p->recursion_count == 0) {
-      if (p->owner != drd_tid && p->owner != DRD_INVALID_THREADID)
-      {
-         tl_assert(p->last_locked_segment);
+      if (!p->ignore_ordering) {
+         if (p->owner != drd_tid && p->owner != DRD_INVALID_THREADID) {
+            tl_assert(p->last_locked_segment);
 
-         DRD_(thread_new_segment_and_combine_vc)(drd_tid,
-                                                 p->last_locked_segment);
+            DRD_(thread_new_segment_and_combine_vc)(drd_tid,
+                                                    p->last_locked_segment);
+         } else {
+            DRD_(thread_new_segment)(drd_tid);
+         }
+
+         s_mutex_segment_creation_count++;
       }
-      else
-         DRD_(thread_new_segment)(drd_tid);
-
-      s_mutex_segment_creation_count++;
 
       p->owner           = drd_tid;
       p->acquiry_time_ms = VG_(read_millisecond_timer)();
@@ -426,7 +445,8 @@
       /* this mutex is locked again.                                        */
 
       DRD_(thread_get_latest_segment)(&p->last_locked_segment, drd_tid);
-      DRD_(thread_new_segment)(drd_tid);
+      if (!p->ignore_ordering)
+         DRD_(thread_new_segment)(drd_tid);
       p->acquired_at = 0;
       s_mutex_segment_creation_count++;
    }
diff --git a/drd/drd_mutex.h b/drd/drd_mutex.h
index fb8a8bc..953045a 100644
--- a/drd/drd_mutex.h
+++ b/drd/drd_mutex.h
@@ -37,6 +37,7 @@
 void DRD_(mutex_set_trace)(const Bool trace_mutex);
 void DRD_(mutex_set_lock_threshold)(const UInt lock_threshold_ms);
 struct mutex_info* DRD_(mutex_init)(const Addr mutex, const MutexT mutex_type);
+void DRD_(mutex_ignore_ordering)(const Addr mutex);
 void DRD_(mutex_post_destroy)(const Addr mutex);
 void DRD_(not_a_mutex)(const Addr mutex);
 struct mutex_info* DRD_(mutex_get)(const Addr mutex);
diff --git a/drd/drd_pthread_intercepts.c b/drd/drd_pthread_intercepts.c
index e66297e..a3119de 100644
--- a/drd/drd_pthread_intercepts.c
+++ b/drd/drd_pthread_intercepts.c
@@ -179,10 +179,17 @@
    DRD_(set_main_thread_state)();
 }
 
+static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
+{
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING,
+                                   mutex, 0, 0, 0, 0);
+}
+
 static void DRD_(sema_init)(DrdSema* sema)
 {
-   DRD_IGNORE_VAR(sema->counter);
+   DRD_IGNORE_VAR(*sema);
    pthread_mutex_init(&sema->mutex, NULL);
+   DRD_(ignore_mutex_ordering)(&sema->mutex);
    sema->counter = 0;
    sema->waiters = 0;
 }