Modified drd client requests such that the mutex type can be passed from the intercepts to the tool. An error message is now printed in case a locked mutex is destroyed and in case a thread exits while it holds a lock on a mutex. Changed format of mutex error messages. Added recursive_mutex regression test. Fixed autogen warnings in exp-drd/tests/Makefile.am.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7489 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/exp-drd/drd_mutex.c b/exp-drd/drd_mutex.c
index 4fcf34e..d7a1072 100644
--- a/exp-drd/drd_mutex.c
+++ b/exp-drd/drd_mutex.c
@@ -49,6 +49,7 @@
 
 // Local functions.
 
+static Bool mutex_is_locked(struct mutex_info* const p);
 static void mutex_destroy(struct mutex_info* const p);
 
 
@@ -75,8 +76,10 @@
 {
   tl_assert(mutex != 0);
   tl_assert(size > 0);
+#if 0
   tl_assert(mutex_type == mutex_type_mutex
             || mutex_type == mutex_type_spinlock);
+#endif
 
   p->mutex           = mutex;
   p->size            = size;
@@ -94,13 +97,20 @@
 {
   int i;
 
+#if 0
   tl_assert(mutex_type == mutex_type_mutex
             || mutex_type == mutex_type_spinlock);
+#endif
 
   for (i = 0; i < sizeof(s_mutex)/sizeof(s_mutex[0]); i++)
   {
     if (s_mutex[i].mutex == mutex)
     {
+      if (s_mutex[i].mutex_type != mutex_type)
+      {
+        VG_(message)(Vg_DebugMsg, "??? mutex %p: type changed from %d into %d",
+	             s_mutex[i].mutex, s_mutex[i].mutex_type, mutex_type);
+      }
       tl_assert(s_mutex[i].mutex_type == mutex_type);
       tl_assert(s_mutex[i].size == size);
       return &s_mutex[i];
@@ -146,8 +156,11 @@
                  mutex);
   }
 
+#if 0
   tl_assert(mutex_type == mutex_type_mutex
             || mutex_type == mutex_type_spinlock);
+#endif
+
   mutex_p = mutex_get(mutex);
   if (mutex_p)
   {
@@ -179,6 +192,16 @@
                  p->mutex);
   }
 
+  if (mutex_is_locked(p))
+  {
+    MutexErrInfo MEI = { p->mutex, p->recursion_count, p->owner };
+    VG_(maybe_record_error)(VG_(get_running_tid)(),
+                            MutexErr,
+                            VG_(get_IP)(VG_(get_running_tid)()),
+                            "Destroying locked mutex",
+                            &MEI);
+  }
+
   drd_finish_suppression(p->mutex, p->mutex + p->size);
 
   vc_cleanup(&p->vc);
@@ -255,8 +278,11 @@
      return 0;
   }
 
+#if 0
   tl_assert(mutex_type == mutex_type_mutex
             || mutex_type == mutex_type_spinlock);
+#endif
+
   tl_assert(p->mutex_type == mutex_type);
   tl_assert(p->size == size);
 
@@ -321,7 +347,7 @@
                  p->owner);
   }
 
-  if (p == 0 || p->owner == DRD_INVALID_THREADID)
+  if (p == 0)
   {
      GenericErrInfo GEI;
      VG_(maybe_record_error)(vg_tid,
@@ -332,11 +358,29 @@
      return 0;
   }
 
+  if (p->owner == DRD_INVALID_THREADID)
+  {
+    MutexErrInfo MEI = { p->mutex, p->recursion_count, p->owner };
+    VG_(maybe_record_error)(vg_tid,
+                            MutexErr,
+                            VG_(get_IP)(vg_tid),
+                            "Mutex not locked",
+                            &MEI);
+     return 0;
+  }
+
   tl_assert(p);
+  if (p->mutex_type != mutex_type)
+  {
+    VG_(message)(Vg_DebugMsg, "??? mutex %p: type changed from %d into %d",
+	         p->mutex, p->mutex_type, mutex_type);
+  }
   tl_assert(p->mutex_type == mutex_type);
   tl_assert(p->owner != DRD_INVALID_THREADID);
+#if 0
   tl_assert(mutex_type == mutex_type_mutex
             || mutex_type == mutex_type_spinlock);
+#endif
 
   if (p->owner != drd_tid)
   {
@@ -383,7 +427,11 @@
 {
   switch (mt)
   {
-  case mutex_type_mutex:
+  case mutex_type_recursive_mutex:
+    return "recursive mutex";
+  case mutex_type_errorcheck_mutex:
+    return "error checking mutex";
+  case mutex_type_default_mutex:
     return "mutex";
   case mutex_type_spinlock:
     return "spinlock";
@@ -393,6 +441,13 @@
   return "?";
 }
 
+/** Return true if the specified mutex is locked by any thread. */
+static Bool mutex_is_locked(struct mutex_info* const p)
+{
+  tl_assert(p);
+  return (p->recursion_count > 0);
+}
+
 Bool mutex_is_locked_by(const Addr mutex, const DrdThreadId tid)
 {
   struct mutex_info* const p = mutex_get(mutex);
@@ -419,8 +474,6 @@
 /**
  * Call this function when thread tid stops to exist, such that the
  * "last owner" field can be cleared if it still refers to that thread.
- * TO DO: print an error message if a thread exits while it still has some
- * mutexes locked.
  */
 void mutex_thread_delete(const DrdThreadId tid)
 {
@@ -428,8 +481,15 @@
   for (i = 0; i < sizeof(s_mutex)/sizeof(s_mutex[0]); i++)
   {
     struct mutex_info* const p = &s_mutex[i];
-    if (p->mutex && p->owner == tid)
+    if (p->mutex && p->owner == tid && p->recursion_count > 0)
     {
+      MutexErrInfo MEI
+        = { p->mutex, p->recursion_count, p->owner };
+      VG_(maybe_record_error)(VG_(get_running_tid)(),
+                              MutexErr,
+                              VG_(get_IP)(VG_(get_running_tid)()),
+                              "Mutex still locked at thread exit",
+                              &MEI);
       p->owner = VG_INVALID_THREADID;
     }
   }