> ovsrcu_init() was named after the atomic_init(), but the semantics are
> different enough to warrant a different name.  Basically C11
> atomic_init is defined in a way that allows the implementation to
> assign the value without any syncronization, so in theory stores via
> atomic_init could be seen by others after stores via atomic_set, even
> if the atomic_init appeared earlier in the code.
> 
> ovsrcu_set_hidden() can be used to set an RCU protected variable when
> it is not yet accessible by any active reader, but will be made
> visible later via an ovsrcu_set call on some other pointer.
> 
> This patch also adds a new ovsrcu_init() that can be used to initilize
> RCU protected variables when the readers are not yet executing.  The
> new ovsrcu_init() is implemented with atomic_init(), so it does not
> provide any kind of syncronization.
> 
> Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com>

Acked-by: YAMAMOTO Takashi <yamam...@valinux.co.jp>

> ---
>  lib/cmap.c    |    6 +++---
>  lib/ovs-rcu.h |   20 +++++++++++++-------
>  2 files changed, 16 insertions(+), 10 deletions(-)
> 
> diff --git a/lib/cmap.c b/lib/cmap.c
> index a760235..ae362f5 100644
> --- a/lib/cmap.c
> +++ b/lib/cmap.c
> @@ -448,7 +448,7 @@ cmap_insert_dup(struct cmap_node *new_node, uint32_t hash,
>                      }
>                      p = next;
>                  }
> -                ovsrcu_init(&p->next, node);
> +                ovsrcu_set_hidden(&p->next, node);
>              } else {
>                  /* The hash value is there from some previous insertion, but
>                   * the associated node has been removed.  We're not really
> @@ -660,7 +660,7 @@ cmap_insert(struct cmap *cmap, struct cmap_node *node, 
> uint32_t hash)
>  {
>      struct cmap_impl *impl = cmap_get_impl(cmap);
>  
> -    ovsrcu_init(&node->next, NULL);
> +    ovsrcu_set_hidden(&node->next, NULL);
>  
>      if (OVS_UNLIKELY(impl->n >= impl->max_n)) {
>          impl = cmap_rehash(cmap, (impl->mask << 1) | 1);
> @@ -690,7 +690,7 @@ cmap_replace__(struct cmap_impl *impl, struct cmap_node 
> *node,
>          replacement = cmap_node_next_protected(node);
>      } else {
>          /* 'replacement' takes the position of 'node' in the list. */
> -        ovsrcu_init(&replacement->next, cmap_node_next_protected(node));
> +        ovsrcu_set_hidden(&replacement->next, 
> cmap_node_next_protected(node));
>      }
>  
>      struct cmap_node *iter = &b->nodes[slot];
> diff --git a/lib/ovs-rcu.h b/lib/ovs-rcu.h
> index e27dfad..571a139 100644
> --- a/lib/ovs-rcu.h
> +++ b/lib/ovs-rcu.h
> @@ -89,12 +89,14 @@
>   * 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.  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:
> + * free the previous data.  ovsrcu_set_hidden() can be used on RCU protected
> + * data not visible to any readers yet, but will be made visible by a later
> + * ovsrcu_set().   ovsrcu_init() can be used to initialize RCU pointers when
> + * no readers are yet executing.  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;
>   *
> @@ -180,9 +182,13 @@ static inline void ovsrcu_set__(struct ovsrcu_pointer 
> *pointer,
>  /* 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) \
> +#define ovsrcu_set_hidden(VAR, VALUE) \
>      ovsrcu_set__(VAR, VALUE, memory_order_relaxed)
>  
> +/* This can be used for initializing RCU pointers before any readers are
> + * executing. */
> +#define ovsrcu_init(VAR, VALUE) atomic_init(&(VAR)->p, VALUE)
> +
>  /* 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
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to