lib/ovs-rcu.h had some of the comments duplicated. Add ovsrcu_init() that can be used like ovsrcu_set() when the RCU protected pointer is not yet visible any readers.
Use OVS_CONSTRUCTOR to initialize the ovs-rcu module. Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- lib/ovs-rcu.c | 46 +++++++++++++++++----------------------------- lib/ovs-rcu.h | 52 +++++++++++++++++++++++----------------------------- 2 files changed, 40 insertions(+), 58 deletions(-) diff --git a/lib/ovs-rcu.c b/lib/ovs-rcu.c index 7aed6db..c11c0f0 100644 --- a/lib/ovs-rcu.c +++ b/lib/ovs-rcu.c @@ -55,20 +55,34 @@ static struct ovs_mutex ovsrcu_threads_mutex; static struct guarded_list flushed_cbsets; static struct seq *flushed_cbsets_seq; -static void ovsrcu_init(void); static void ovsrcu_flush_cbset(struct ovsrcu_perthread *); static void ovsrcu_unregister__(struct ovsrcu_perthread *); static bool ovsrcu_call_postponed(void); static void *ovsrcu_postpone_thread(void *arg OVS_UNUSED); static void ovsrcu_synchronize(void); +static void +ovsrcu_thread_exit_cb(void *perthread) +{ + ovsrcu_unregister__(perthread); +} + +OVS_CONSTRUCTOR(ovsrcu_constructor) +{ + global_seqno = seq_create(); + xpthread_key_create(&perthread_key, ovsrcu_thread_exit_cb); + list_init(&ovsrcu_threads); + ovs_mutex_init(&ovsrcu_threads_mutex); + + guarded_list_init(&flushed_cbsets); + flushed_cbsets_seq = seq_create(); +} + static struct ovsrcu_perthread * ovsrcu_perthread_get(void) { struct ovsrcu_perthread *perthread; - ovsrcu_init(); - perthread = pthread_getspecific(perthread_key); if (!perthread) { const char *name = get_subprogram_name(); @@ -121,7 +135,6 @@ ovsrcu_quiesce_start(void) { struct ovsrcu_perthread *perthread; - ovsrcu_init(); perthread = pthread_getspecific(perthread_key); if (perthread) { pthread_setspecific(perthread_key, NULL); @@ -136,7 +149,6 @@ ovsrcu_quiesce_start(void) void ovsrcu_quiesce(void) { - ovsrcu_init(); ovsrcu_perthread_get()->seqno = seq_read(global_seqno); seq_change(global_seqno); @@ -146,7 +158,6 @@ ovsrcu_quiesce(void) bool ovsrcu_is_quiescent(void) { - ovsrcu_init(); return pthread_getspecific(perthread_key) == NULL; } @@ -300,26 +311,3 @@ ovsrcu_unregister__(struct ovsrcu_perthread *perthread) seq_change(global_seqno); } - -static void -ovsrcu_thread_exit_cb(void *perthread) -{ - ovsrcu_unregister__(perthread); -} - -static void -ovsrcu_init(void) -{ - static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; - if (ovsthread_once_start(&once)) { - global_seqno = seq_create(); - xpthread_key_create(&perthread_key, ovsrcu_thread_exit_cb); - list_init(&ovsrcu_threads); - ovs_mutex_init(&ovsrcu_threads_mutex); - - guarded_list_init(&flushed_cbsets); - flushed_cbsets_seq = seq_create(); - - ovsthread_once_done(&once); - } -} diff --git a/lib/ovs-rcu.h b/lib/ovs-rcu.h index 0b40133..775b829 100644 --- a/lib/ovs-rcu.h +++ b/lib/ovs-rcu.h @@ -78,27 +78,33 @@ * Use ovsrcu_get(TYPE, VAR) to read an RCU-protected pointer, e.g. to read the * pointer variable declared above: * - * struct flow *flow = ovsrcu_get(struct flow *, flowp); + * struct flow *flow = ovsrcu_get(struct flow *, &flowp); + * + * If the pointer variable is currently protected against change (because + * the current thread holds a mutex that protects it), ovsrcu_get_protected() + * may be used instead. Only on the Alpha architecture is this likely to + * generate different code, but it may be useful documentation. + * + * (With GNU C or Clang, you get a compiler error if TYPE is wrong; other + * compilers will merrily carry along accepting the wrong type.) * * Use ovsrcu_set() to write an RCU-protected pointer and ovsrcu_postpone() to - * free the previous data. If more than one thread can write the pointer, then - * some form of external synchronization, e.g. a mutex, is needed to prevent - * writers from interfering with one another. For example, to write the - * pointer variable declared above while safely freeing the old value: + * free the previous data. ovsrcu_init() can be used on (newly created) RCU- + * protected pointer that is not yet visible to the readers. If more than one + * thread can write the pointer, then some form of external synchronization, + * e.g. a mutex, is needed to prevent writers from interfering with one + * another. For example, to write the pointer variable declared above while + * safely freeing the old value: * * static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER; * - * static void - * free_flow(struct flow *flow) - * { - * free(flow); - * } + * OVSRCU_TYPE(struct flow *) flowp; * * void * change_flow(struct flow *new_flow) * { * ovs_mutex_lock(&mutex); - * ovsrcu_postpone(free_flow, + * ovsrcu_postpone(free, * ovsrcu_get_protected(struct flow *, &flowp)); * ovsrcu_set(&flowp, new_flow); * ovs_mutex_unlock(&mutex); @@ -109,24 +115,6 @@ #include "compiler.h" #include "ovs-atomic.h" -/* Use OVSRCU_TYPE(TYPE) to declare a pointer to RCU-protected data, e.g. the - * following declares an RCU-protected "struct flow *" named flowp: - * - * OVSRCU_TYPE(struct flow *) flowp; - * - * Use ovsrcu_get(TYPE, VAR) to read an RCU-protected pointer, e.g. to read the - * pointer variable declared above: - * - * struct flow *flow = ovsrcu_get(struct flow *, &flowp); - * - * If the pointer variable is currently protected against change (because - * the current thread holds a mutex that protects it), ovsrcu_get_protected() - * may be used instead. Only on the Alpha architecture is this likely to - * generate different code, but it may be useful documentation. - * - * (With GNU C or Clang, you get a compiler error if TYPE is wrong; other - * compilers will merrily carry along accepting the wrong type.) - */ #if __GNUC__ #define OVSRCU_TYPE(TYPE) struct { ATOMIC(TYPE) p; } #define OVSRCU_TYPE_INITIALIZER { NULL } @@ -168,6 +156,12 @@ ovsrcu_get__(const struct ovsrcu_pointer *pointer, memory_order order) #define ovsrcu_set(VAR, VALUE) \ atomic_store_explicit(&(VAR)->p, VALUE, memory_order_release) +/* This can be used for initializing RCU pointers before any readers can + * see them. A later ovsrcu_set() needs to make the bigger structure this + * is part of visible to the readers. */ +#define ovsrcu_init(VAR, VALUE) \ + atomic_store_explicit(&(VAR)->p, VALUE, memory_order_relaxed) + /* Calls FUNCTION passing ARG as its pointer-type argument following the next * grace period. See "Usage" above for example. */ void ovsrcu_postpone__(void (*function)(void *aux), void *aux); -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev