X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fovs-thread.h;h=02a81f7dfd362822342f71ab021ec454fefc4144;hb=28c5588e8e1a8d091c5d2275232c35f2968a97fa;hp=8cf2ecca3f217fd391ab77c03fdc68e54af14d5b;hpb=e9020da2d229a48296d829ac40eb4a374063ae49;p=sliver-openvswitch.git diff --git a/lib/ovs-thread.h b/lib/ovs-thread.h index 8cf2ecca3..02a81f7df 100644 --- a/lib/ovs-thread.h +++ b/lib/ovs-thread.h @@ -37,6 +37,13 @@ struct OVS_LOCKABLE ovs_mutex { #define OVS_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, NULL } #endif +#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP +#define OVS_ADAPTIVE_MUTEX_INITIALIZER \ + { PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP, NULL } +#else +#define OVS_ADAPTIVE_MUTEX_INITIALIZER OVS_MUTEX_INITIALIZER +#endif + /* ovs_mutex functions analogous to pthread_mutex_*() functions. * * Most of these functions abort the process with an error message on any @@ -44,6 +51,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 +77,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; }; /* Initializer. */ +#ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP +#define OVS_RWLOCK_INITIALIZER \ + { PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP, NULL } +#else #define OVS_RWLOCK_INITIALIZER { PTHREAD_RWLOCK_INITIALIZER, NULL } +#endif /* ovs_rwlock functions analogous to pthread_rwlock_*() functions. * @@ -87,6 +111,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,16 +146,11 @@ 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); @@ -444,9 +470,15 @@ void xpthread_join(pthread_t, void **); * (by recompiling). Thus, one may more freely use this form of * thread-specific data. * - * Compared to pthread_key_t, ovsthread_key_t has the follow limitations: + * ovsthread_key_t also differs from pthread_key_t in the following ways: * * - Destructors must not access thread-specific data (via ovsthread_key). + * + * - The pthread_key_t API allows concurrently exiting threads to start + * executing the destructor after pthread_key_delete() returns. The + * ovsthread_key_t API guarantees that, when ovsthread_key_delete() + * returns, all destructors have returned and no new ones will start + * execution. */ typedef struct ovsthread_key *ovsthread_key_t; @@ -560,17 +592,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);