ovs-thread: Add checking for mutex and rwlock initialization.
authorBen Pfaff <blp@nicira.com>
Thu, 24 Apr 2014 23:49:05 +0000 (16:49 -0700)
committerBen Pfaff <blp@nicira.com>
Mon, 28 Apr 2014 22:54:45 +0000 (15:54 -0700)
With glibc, a mutex or rwlock filled with all-zero-bytes is properly
initialized for use, but this is not true for any other libc that OVS
supports.  However, OVS gets a lot more testing with glibc than any other
libc.  This means that developers keep introducing bugs that do not
manifest on the main development platform.

This commit should help avoid the problem, by reusing the existing 'where'
members to indicate whether a mutex or rwlock has been initialized.

Signed-off-by: Ben Pfaff <blp@nicira.com>
lib/ovs-thread.c
lib/ovs-thread.h

index 19edf8f..fbdd7fc 100644 (file)
@@ -52,12 +52,17 @@ static bool multithreaded;
         OVS_NO_THREAD_SAFETY_ANALYSIS \
     { \
         struct ovs_##TYPE *l = CONST_CAST(struct ovs_##TYPE *, l_); \
-        int error = pthread_##TYPE##_##FUN(&l->lock); \
+        int error; \
+ \
+        /* Verify that 'l' was initialized. */ \
+        ovs_assert(l->where); \
+ \
+        error = pthread_##TYPE##_##FUN(&l->lock); \
         if (OVS_UNLIKELY(error)) { \
             ovs_abort(error, "pthread_%s_%s failed", #TYPE, #FUN); \
         } \
         l->where = where; \
   }
+ }
 LOCK_FUNCTION(mutex, lock);
 LOCK_FUNCTION(rwlock, rdlock);
 LOCK_FUNCTION(rwlock, wrlock);
@@ -69,7 +74,12 @@ LOCK_FUNCTION(rwlock, wrlock);
         OVS_NO_THREAD_SAFETY_ANALYSIS \
     { \
         struct ovs_##TYPE *l = CONST_CAST(struct ovs_##TYPE *, l_); \
-        int error = pthread_##TYPE##_##FUN(&l->lock); \
+        int error; \
+ \
+        /* Verify that 'l' was initialized. */ \
+        ovs_assert(l->where); \
+ \
+        error = pthread_##TYPE##_##FUN(&l->lock); \
         if (OVS_UNLIKELY(error) && error != EBUSY) { \
             ovs_abort(error, "pthread_%s_%s failed", #TYPE, #FUN); \
         } \
@@ -82,23 +92,27 @@ TRY_LOCK_FUNCTION(mutex, trylock);
 TRY_LOCK_FUNCTION(rwlock, tryrdlock);
 TRY_LOCK_FUNCTION(rwlock, trywrlock);
 
-#define UNLOCK_FUNCTION(TYPE, FUN) \
+#define UNLOCK_FUNCTION(TYPE, FUN, WHERE) \
     void \
     ovs_##TYPE##_##FUN(const struct ovs_##TYPE *l_) \
         OVS_NO_THREAD_SAFETY_ANALYSIS \
     { \
         struct ovs_##TYPE *l = CONST_CAST(struct ovs_##TYPE *, l_); \
         int error; \
-        l->where = NULL; \
+ \
+        /* Verify that 'l' was initialized. */ \
+        ovs_assert(l->where); \
+ \
+        l->where = WHERE; \
         error = pthread_##TYPE##_##FUN(&l->lock); \
         if (OVS_UNLIKELY(error)) { \
             ovs_abort(error, "pthread_%s_%sfailed", #TYPE, #FUN); \
         } \
     }
-UNLOCK_FUNCTION(mutex, unlock);
-UNLOCK_FUNCTION(mutex, destroy);
-UNLOCK_FUNCTION(rwlock, unlock);
-UNLOCK_FUNCTION(rwlock, destroy);
+UNLOCK_FUNCTION(mutex, unlock, "<unlocked>");
+UNLOCK_FUNCTION(mutex, destroy, NULL);
+UNLOCK_FUNCTION(rwlock, unlock, "<unlocked>");
+UNLOCK_FUNCTION(rwlock, destroy, NULL);
 
 #define XPTHREAD_FUNC1(FUNCTION, PARAM1)                \
     void                                                \
@@ -164,7 +178,7 @@ ovs_mutex_init__(const struct ovs_mutex *l_, int type)
     pthread_mutexattr_t attr;
     int error;
 
-    l->where = NULL;
+    l->where = "<unlocked>";
     xpthread_mutexattr_init(&attr);
     xpthread_mutexattr_settype(&attr, type);
     error = pthread_mutex_init(&l->lock, &attr);
@@ -206,7 +220,7 @@ ovs_rwlock_init(const struct ovs_rwlock *l_)
     pthread_rwlockattr_t attr;
     int error;
 
-    l->where = NULL;
+    l->where = "<unlocked>";
 
     xpthread_rwlockattr_init(&attr);
 #ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
index 9527843..180b66f 100644 (file)
 /* Mutex. */
 struct OVS_LOCKABLE ovs_mutex {
     pthread_mutex_t lock;
-    const char *where;
+    const char *where;          /* NULL if and only if uninitialized. */
 };
 
 /* "struct ovs_mutex" initializer. */
 #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
-#define OVS_MUTEX_INITIALIZER { PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, NULL }
+#define OVS_MUTEX_INITIALIZER { PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, \
+                                "<unlocked>" }
 #else
-#define OVS_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, NULL }
+#define OVS_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, "<unlocked>" }
 #endif
 
 #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
@@ -91,15 +92,15 @@ void xpthread_mutexattr_gettype(pthread_mutexattr_t *, int *typep);
  *       than exposing them only to porters. */
 struct OVS_LOCKABLE ovs_rwlock {
     pthread_rwlock_t lock;
-    const char *where;
+    const char *where;          /* NULL if and only if uninitialized. */
 };
 
 /* Initializer. */
 #ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
 #define OVS_RWLOCK_INITIALIZER \
-        { PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP, NULL }
+        { PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP, "<unlocked>" }
 #else
-#define OVS_RWLOCK_INITIALIZER { PTHREAD_RWLOCK_INITIALIZER, NULL }
+#define OVS_RWLOCK_INITIALIZER { PTHREAD_RWLOCK_INITIALIZER, "<unlocked>" }
 #endif
 
 /* ovs_rwlock functions analogous to pthread_rwlock_*() functions.