X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fovs-thread.h;h=68db71fbaa89f14cb1807af892412016cbff0fb8;hb=0ef165ecb57943e17a8ee8270df68ffb8d032e29;hp=f0318948b9e99db34fd513f51e8ab4217cf16de0;hpb=9a1a10918615d2138d93a315a6af83253e9d88dd;p=sliver-openvswitch.git diff --git a/lib/ovs-thread.h b/lib/ovs-thread.h index f0318948b..68db71fba 100644 --- a/lib/ovs-thread.h +++ b/lib/ovs-thread.h @@ -27,14 +27,22 @@ /* 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, \ + "" } #else -#define OVS_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, NULL } +#define OVS_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, "" } +#endif + +#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP +#define OVS_ADAPTIVE_MUTEX_INITIALIZER \ + { PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP, "" } +#else +#define OVS_ADAPTIVE_MUTEX_INITIALIZER OVS_MUTEX_INITIALIZER #endif /* ovs_mutex functions analogous to pthread_mutex_*() functions. @@ -44,6 +52,7 @@ struct OVS_LOCKABLE ovs_mutex { * return value to the caller and aborts on any other error. */ void ovs_mutex_init(const struct ovs_mutex *); void ovs_mutex_init_recursive(const struct ovs_mutex *); +void ovs_mutex_init_adaptive(const struct ovs_mutex *); void ovs_mutex_destroy(const struct ovs_mutex *); void ovs_mutex_unlock(const struct ovs_mutex *mutex) OVS_RELEASES(mutex); void ovs_mutex_lock_at(const struct ovs_mutex *mutex, const char *where) @@ -69,14 +78,30 @@ void xpthread_mutexattr_destroy(pthread_mutexattr_t *); void xpthread_mutexattr_settype(pthread_mutexattr_t *, int type); void xpthread_mutexattr_gettype(pthread_mutexattr_t *, int *typep); -/* Read-write lock. */ +/* Read-write lock. + * + * An ovs_rwlock does not support recursive readers, because POSIX allows + * taking the reader lock recursively to deadlock when a thread is waiting on + * the write-lock. (NetBSD does deadlock.) glibc rwlocks in their default + * configuration do not deadlock, but ovs_rwlock_init() initializes rwlocks as + * non-recursive (which will deadlock) for two reasons: + * + * - glibc only provides fairness to writers in this mode. + * + * - It's better to find bugs in the primary Open vSwitch target rather + * 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. */ -#define OVS_RWLOCK_INITIALIZER { PTHREAD_RWLOCK_INITIALIZER, NULL } +#ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP +#define OVS_RWLOCK_INITIALIZER \ + { PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP, "" } +#else +#define OVS_RWLOCK_INITIALIZER { PTHREAD_RWLOCK_INITIALIZER, "" } +#endif /* ovs_rwlock functions analogous to pthread_rwlock_*() functions. * @@ -87,6 +112,13 @@ void ovs_rwlock_init(const struct ovs_rwlock *); void ovs_rwlock_destroy(const struct ovs_rwlock *); void ovs_rwlock_unlock(const struct ovs_rwlock *rwlock) OVS_RELEASES(rwlock); +/* Wrappers for pthread_rwlockattr_*() that abort the process on any error. */ +void xpthread_rwlockattr_init(pthread_rwlockattr_t *); +void xpthread_rwlockattr_destroy(pthread_rwlockattr_t *); +#ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP +void xpthread_rwlockattr_setkind_np(pthread_rwlockattr_t *, int kind); +#endif + void ovs_rwlock_wrlock_at(const struct ovs_rwlock *rwlock, const char *where) OVS_ACQ_WRLOCK(rwlock); #define ovs_rwlock_wrlock(rwlock) \ @@ -115,22 +147,17 @@ void xpthread_cond_destroy(pthread_cond_t *); void xpthread_cond_signal(pthread_cond_t *); void xpthread_cond_broadcast(pthread_cond_t *); -#ifdef __CHECKER__ -/* Replace these functions by the macros already defined in the - * annotations, because the macro definitions have correct semantics for the - * conditional acquisition that can't be captured in a function annotation. - * The difference in semantics from pthread_*() to xpthread_*() does not matter - * because sparse is not a compiler. */ -#define xpthread_mutex_trylock pthread_mutex_trylock -#define xpthread_rwlock_tryrdlock pthread_rwlock_tryrdlock -#define xpthread_rwlock_trywrlock pthread_rwlock_trywrlock -#endif +/* Wrappers for pthread_barrier_*() that abort the process on any error. */ +void xpthread_barrier_init(pthread_barrier_t *, pthread_barrierattr_t *, + unsigned int count); +int xpthread_barrier_wait(pthread_barrier_t *); +void xpthread_barrier_destroy(pthread_barrier_t *); void xpthread_key_create(pthread_key_t *, void (*destructor)(void *)); void xpthread_key_delete(pthread_key_t); void xpthread_setspecific(pthread_key_t, const void *); -void xpthread_create(pthread_t *, pthread_attr_t *, void *(*)(void *), void *); +pthread_t ovs_thread_create(const char *name, void *(*)(void *), void *); void xpthread_join(pthread_t, void **); /* Per-thread data. @@ -566,17 +593,34 @@ ovsthread_id_self(void) * * Fully thread-safe. */ -struct ovsthread_counter *ovsthread_counter_create(void); -void ovsthread_counter_destroy(struct ovsthread_counter *); -void ovsthread_counter_inc(struct ovsthread_counter *, unsigned long long int); -unsigned long long int ovsthread_counter_read( - const struct ovsthread_counter *); +struct ovsthread_stats { + struct ovs_mutex mutex; + void *volatile buckets[16]; +}; + +void ovsthread_stats_init(struct ovsthread_stats *); +void ovsthread_stats_destroy(struct ovsthread_stats *); + +void *ovsthread_stats_bucket_get(struct ovsthread_stats *, + void *(*new_bucket)(void)); + +#define OVSTHREAD_STATS_FOR_EACH_BUCKET(BUCKET, IDX, STATS) \ + for ((IDX) = ovs_thread_stats_next_bucket(STATS, 0); \ + ((IDX) < ARRAY_SIZE((STATS)->buckets) \ + ? ((BUCKET) = (STATS)->buckets[IDX], true) \ + : false); \ + (IDX) = ovs_thread_stats_next_bucket(STATS, (IDX) + 1)) +size_t ovs_thread_stats_next_bucket(const struct ovsthread_stats *, size_t); +bool single_threaded(void); + void assert_single_threaded_at(const char *where); #define assert_single_threaded() assert_single_threaded_at(SOURCE_LOCATOR) +#ifndef _WIN32 pid_t xfork_at(const char *where); #define xfork() xfork_at(SOURCE_LOCATOR) +#endif void forbid_forking(const char *reason); bool may_fork(void);