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>
OVS_NO_THREAD_SAFETY_ANALYSIS \
{ \
struct ovs_##TYPE *l = CONST_CAST(struct ovs_##TYPE *, l_); \
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; \
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);
LOCK_FUNCTION(mutex, lock);
LOCK_FUNCTION(rwlock, rdlock);
LOCK_FUNCTION(rwlock, wrlock);
OVS_NO_THREAD_SAFETY_ANALYSIS \
{ \
struct ovs_##TYPE *l = CONST_CAST(struct ovs_##TYPE *, l_); \
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); \
} \
if (OVS_UNLIKELY(error) && error != EBUSY) { \
ovs_abort(error, "pthread_%s_%s failed", #TYPE, #FUN); \
} \
TRY_LOCK_FUNCTION(rwlock, tryrdlock);
TRY_LOCK_FUNCTION(rwlock, trywrlock);
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; \
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; \
+ \
+ /* 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); \
} \
}
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 \
#define XPTHREAD_FUNC1(FUNCTION, PARAM1) \
void \
pthread_mutexattr_t attr;
int error;
pthread_mutexattr_t attr;
int error;
+ l->where = "<unlocked>";
xpthread_mutexattr_init(&attr);
xpthread_mutexattr_settype(&attr, type);
error = pthread_mutex_init(&l->lock, &attr);
xpthread_mutexattr_init(&attr);
xpthread_mutexattr_settype(&attr, type);
error = pthread_mutex_init(&l->lock, &attr);
pthread_rwlockattr_t attr;
int error;
pthread_rwlockattr_t attr;
int error;
+ l->where = "<unlocked>";
xpthread_rwlockattr_init(&attr);
#ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
xpthread_rwlockattr_init(&attr);
#ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
/* Mutex. */
struct OVS_LOCKABLE ovs_mutex {
pthread_mutex_t lock;
/* Mutex. */
struct OVS_LOCKABLE ovs_mutex {
pthread_mutex_t lock;
+ const char *where; /* NULL if and only if uninitialized. */
};
/* "struct ovs_mutex" initializer. */
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
};
/* "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>" }
-#define OVS_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, NULL }
+#define OVS_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, "<unlocked>" }
#endif
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
#endif
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
* than exposing them only to porters. */
struct OVS_LOCKABLE ovs_rwlock {
pthread_rwlock_t lock;
* than exposing them only to porters. */
struct OVS_LOCKABLE ovs_rwlock {
pthread_rwlock_t lock;
+ const char *where; /* NULL if and only if uninitialized. */
};
/* Initializer. */
#ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
#define OVS_RWLOCK_INITIALIZER \
};
/* 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>" }
-#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.
#endif
/* ovs_rwlock functions analogous to pthread_rwlock_*() functions.