+#include "vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(ovs_thread);
+
+/* If there is a reason that we cannot fork anymore (unless the fork will be
+ * immediately followed by an exec), then this points to a string that
+ * explains why. */
+static const char *must_not_fork;
+
+/* True if we created any threads beyond the main initial thread. */
+static bool multithreaded;
+
+#define LOCK_FUNCTION(TYPE, FUN) \
+ void \
+ ovs_##TYPE##_##FUN##_at(const struct ovs_##TYPE *l_, \
+ const char *where) \
+ OVS_NO_THREAD_SAFETY_ANALYSIS \
+ { \
+ struct ovs_##TYPE *l = CONST_CAST(struct ovs_##TYPE *, l_); \
+ int 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);
+
+#define TRY_LOCK_FUNCTION(TYPE, FUN) \
+ int \
+ ovs_##TYPE##_##FUN##_at(const struct ovs_##TYPE *l_, \
+ const char *where) \
+ OVS_NO_THREAD_SAFETY_ANALYSIS \
+ { \
+ struct ovs_##TYPE *l = CONST_CAST(struct ovs_##TYPE *, l_); \
+ int error = pthread_##TYPE##_##FUN(&l->lock); \
+ if (OVS_UNLIKELY(error) && error != EBUSY) { \
+ ovs_abort(error, "pthread_%s_%s failed", #TYPE, #FUN); \
+ } \
+ if (!error) { \
+ l->where = where; \
+ } \
+ return error; \
+ }
+TRY_LOCK_FUNCTION(mutex, trylock);
+TRY_LOCK_FUNCTION(rwlock, tryrdlock);
+TRY_LOCK_FUNCTION(rwlock, trywrlock);
+
+#define UNLOCK_FUNCTION(TYPE, FUN) \
+ 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; \
+ 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);
+