Acked-by: Andy Zhou <az...@nicira.com>

On Tue, Mar 11, 2014 at 1:56 PM, Ben Pfaff <b...@nicira.com> wrote:

> This factors code out of fat-rwlock, making it easily usable by other code.
>
> Signed-off-by: Ben Pfaff <b...@nicira.com>
> ---
>  lib/fat-rwlock.c |   29 ++------------------------
>  lib/util.c       |   60
> +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  lib/util.h       |    6 +++++-
>  3 files changed, 66 insertions(+), 29 deletions(-)
>
> diff --git a/lib/fat-rwlock.c b/lib/fat-rwlock.c
> index 3866dda..82dfbfe 100644
> --- a/lib/fat-rwlock.c
> +++ b/lib/fat-rwlock.c
> @@ -57,16 +57,6 @@ struct fat_rwlock_slot {
>       * Accessed only by the slot's own thread, so no synchronization is
>       * needed. */
>      unsigned int depth;
> -
> -    /* To prevent two of these structures from accidentally occupying the
> same
> -     * cache line (causing "false sharing"), we cache-align each of these
> data
> -     * structures.  That requires malloc()ing extra space and throwing
> away
> -     * some space at the beginning, which means that the pointer to this
> struct
> -     * isn't necessarily the pointer to the beginning of the block, and
> so we
> -     * need to retain the original pointer to free later.
> -     *
> -     * Accessed only by a single thread, so no synchronization is needed.
> */
> -    void *base;                /* Pointer to pass to free() for this
> block.  */
>  };
>
>  static void
> @@ -77,7 +67,7 @@ free_slot(struct fat_rwlock_slot *slot)
>      }
>
>      list_remove(&slot->list_node);
> -    free(slot->base);
> +    free_cacheline(slot);
>  }
>
>  static void
> @@ -124,7 +114,6 @@ static struct fat_rwlock_slot *
>  fat_rwlock_get_slot__(struct fat_rwlock *rwlock)
>  {
>      struct fat_rwlock_slot *slot;
> -    void *base;
>
>      /* Fast path. */
>      slot = ovsthread_getspecific(rwlock->key);
> @@ -134,21 +123,7 @@ fat_rwlock_get_slot__(struct fat_rwlock *rwlock)
>
>      /* Slow path: create a new slot for 'rwlock' in this thread. */
>
> -    /* Allocate room for:
> -     *
> -     *     - Up to CACHE_LINE_SIZE - 1 bytes before the per-thread, so
> that
> -     *       the start of the slot doesn't potentially share a cache line.
> -     *
> -     *     - The slot itself.
> -     *
> -     *     - Space following the slot up to the end of the cache line, so
> -     *       that the end of the slot doesn't potentially share a cache
> -     *       line. */
> -    base = xmalloc((CACHE_LINE_SIZE - 1)
> -                   + ROUND_UP(sizeof *slot, CACHE_LINE_SIZE));
> -    slot = (void *) ROUND_UP((uintptr_t) base, CACHE_LINE_SIZE);
> -
> -    slot->base = base;
> +    slot = xmalloc_cacheline(sizeof *slot);
>      slot->rwlock = rwlock;
>      ovs_mutex_init(&slot->mutex);
>      slot->depth = 0;
> diff --git a/lib/util.c b/lib/util.c
> index 911cc3e..f3a0e41 100644
> --- a/lib/util.c
> +++ b/lib/util.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -174,6 +174,64 @@ x2nrealloc(void *p, size_t *n, size_t s)
>      return xrealloc(p, *n * s);
>  }
>
> +/* The desired minimum alignment for an allocated block of memory. */
> +#define MEM_ALIGN MAX(sizeof(void *), 8)
> +BUILD_ASSERT_DECL(IS_POW2(MEM_ALIGN));
> +BUILD_ASSERT_DECL(CACHE_LINE_SIZE >= MEM_ALIGN);
> +
> +/* Allocates and returns 'size' bytes of memory in dedicated cache lines.
>  That
> + * is, the memory block returned will not share a cache line with other
> data,
> + * avoiding "false sharing".  (The memory returned will not be at the
> start of
> + * a cache line, though, so don't assume such alignment.)
> + *
> + * Use free_cacheline() to free the returned memory block. */
> +void *
> +xmalloc_cacheline(size_t size)
> +{
> +    void **payload;
> +    void *base;
> +
> +    /* Allocate room for:
> +     *
> +     *     - Up to CACHE_LINE_SIZE - 1 bytes before the payload, so that
> the
> +     *       start of the payload doesn't potentially share a cache line.
> +     *
> +     *     - A payload consisting of a void *, followed by padding out to
> +     *       MEM_ALIGN bytes, followed by 'size' bytes of user data.
> +     *
> +     *     - Space following the payload up to the end of the cache line,
> so
> +     *       that the end of the payload doesn't potentially share a
> cache line
> +     *       with some following block. */
> +    base = xmalloc((CACHE_LINE_SIZE - 1)
> +                   + ROUND_UP(MEM_ALIGN + size, CACHE_LINE_SIZE));
> +
> +    /* Locate the payload and store a pointer to the base at the
> beginning. */
> +    payload = (void **) ROUND_UP((uintptr_t) base, CACHE_LINE_SIZE);
> +    *payload = base;
> +
> +    return (char *) payload + MEM_ALIGN;
> +}
> +
> +/* Like xmalloc_cacheline() but clears the allocated memory to all zero
> + * bytes. */
> +void *
> +xzalloc_cacheline(size_t size)
> +{
> +    void *p = xmalloc_cacheline(size);
> +    memset(p, 0, size);
> +    return p;
> +}
> +
> +/* Frees a memory block allocated with xmalloc_cacheline() or
> + * xzalloc_cacheline(). */
> +void
> +free_cacheline(void *p)
> +{
> +    if (p) {
> +        free(*(void **) ((uintptr_t) p - MEM_ALIGN));
> +    }
> +}
> +
>  char *
>  xasprintf(const char *format, ...)
>  {
> diff --git a/lib/util.h b/lib/util.h
> index 64516a8..9f1dc4c 100644
> --- a/lib/util.h
> +++ b/lib/util.h
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -264,6 +264,10 @@ char *xasprintf(const char *format, ...)
> PRINTF_FORMAT(1, 2) MALLOC_LIKE;
>  char *xvasprintf(const char *format, va_list) PRINTF_FORMAT(1, 0)
> MALLOC_LIKE;
>  void *x2nrealloc(void *p, size_t *n, size_t s);
>
> +void *xmalloc_cacheline(size_t) MALLOC_LIKE;
> +void *xzalloc_cacheline(size_t) MALLOC_LIKE;
> +void free_cacheline(void *);
> +
>  void ovs_strlcpy(char *dst, const char *src, size_t size);
>  void ovs_strzcpy(char *dst, const char *src, size_t size);
>
> --
> 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