The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/ck/include/ck_brlock.h

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright 2011-2015 Samy Al Bahra.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #ifndef CK_BRLOCK_H
   28 #define CK_BRLOCK_H
   29 
   30 /*
   31  * Big reader spinlocks provide cache-local contention-free read
   32  * lock acquisition in the absence of writers. This comes at the
   33  * cost of O(n) write lock acquisition. They were first implemented
   34  * in the Linux kernel by Ingo Molnar and David S. Miller around the
   35  * year 2000.
   36  *
   37  * This implementation is thread-agnostic which comes at the cost
   38  * of larger reader objects due to necessary linkage overhead. In
   39  * order to cut down on TLB pressure, it is recommended to allocate
   40  * these objects on the same page.
   41  */
   42 
   43 #include <ck_pr.h>
   44 #include <ck_stdbool.h>
   45 #include <ck_stddef.h>
   46 
   47 struct ck_brlock_reader {
   48         unsigned int n_readers;
   49         struct ck_brlock_reader *previous;
   50         struct ck_brlock_reader *next;
   51 };
   52 typedef struct ck_brlock_reader ck_brlock_reader_t;
   53 
   54 #define CK_BRLOCK_READER_INITIALIZER {0}
   55 
   56 struct ck_brlock {
   57         struct ck_brlock_reader *readers;
   58         unsigned int writer;
   59 };
   60 typedef struct ck_brlock ck_brlock_t;
   61 
   62 #define CK_BRLOCK_INITIALIZER {NULL, false}
   63 
   64 CK_CC_INLINE static void
   65 ck_brlock_init(struct ck_brlock *br)
   66 {
   67 
   68         br->readers = NULL;
   69         br->writer = false;
   70         ck_pr_barrier();
   71         return;
   72 }
   73 
   74 CK_CC_INLINE static void
   75 ck_brlock_write_lock(struct ck_brlock *br)
   76 {
   77         struct ck_brlock_reader *cursor;
   78 
   79         /*
   80          * As the frequency of write acquisitions should be low,
   81          * there is no point to more advanced contention avoidance.
   82          */
   83         while (ck_pr_fas_uint(&br->writer, true) == true)
   84                 ck_pr_stall();
   85 
   86         ck_pr_fence_atomic_load();
   87 
   88         /* The reader list is protected under the writer br. */
   89         for (cursor = br->readers; cursor != NULL; cursor = cursor->next) {
   90                 while (ck_pr_load_uint(&cursor->n_readers) != 0)
   91                         ck_pr_stall();
   92         }
   93 
   94         ck_pr_fence_lock();
   95         return;
   96 }
   97 
   98 CK_CC_INLINE static void
   99 ck_brlock_write_unlock(struct ck_brlock *br)
  100 {
  101 
  102         ck_pr_fence_unlock();
  103         ck_pr_store_uint(&br->writer, false);
  104         return;
  105 }
  106 
  107 CK_CC_INLINE static bool
  108 ck_brlock_write_trylock(struct ck_brlock *br, unsigned int factor)
  109 {
  110         struct ck_brlock_reader *cursor;
  111         unsigned int steps = 0;
  112 
  113         while (ck_pr_fas_uint(&br->writer, true) == true) {
  114                 if (++steps >= factor)
  115                         return false;
  116 
  117                 ck_pr_stall();
  118         }
  119 
  120         /*
  121          * We do not require a strict fence here as atomic RMW operations
  122          * are serializing.
  123          */
  124         ck_pr_fence_atomic_load();
  125 
  126         for (cursor = br->readers; cursor != NULL; cursor = cursor->next) {
  127                 while (ck_pr_load_uint(&cursor->n_readers) != 0) {
  128                         if (++steps >= factor) {
  129                                 ck_brlock_write_unlock(br);
  130                                 return false;
  131                         }
  132 
  133                         ck_pr_stall();
  134                 }
  135         }
  136 
  137         ck_pr_fence_lock();
  138         return true;
  139 }
  140 
  141 CK_CC_INLINE static void
  142 ck_brlock_read_register(struct ck_brlock *br, struct ck_brlock_reader *reader)
  143 {
  144 
  145         reader->n_readers = 0;
  146         reader->previous = NULL;
  147 
  148         /* Implicit compiler barrier. */
  149         ck_brlock_write_lock(br);
  150 
  151         reader->next = ck_pr_load_ptr(&br->readers);
  152         if (reader->next != NULL)
  153                 reader->next->previous = reader;
  154         ck_pr_store_ptr(&br->readers, reader);
  155 
  156         ck_brlock_write_unlock(br);
  157         return;
  158 }
  159 
  160 CK_CC_INLINE static void
  161 ck_brlock_read_unregister(struct ck_brlock *br, struct ck_brlock_reader *reader)
  162 {
  163 
  164         ck_brlock_write_lock(br);
  165 
  166         if (reader->next != NULL)
  167                 reader->next->previous = reader->previous;
  168 
  169         if (reader->previous != NULL)
  170                 reader->previous->next = reader->next;
  171         else
  172                 br->readers = reader->next;
  173 
  174         ck_brlock_write_unlock(br);
  175         return;
  176 }
  177 
  178 CK_CC_INLINE static void
  179 ck_brlock_read_lock(struct ck_brlock *br, struct ck_brlock_reader *reader)
  180 {
  181 
  182         if (reader->n_readers >= 1) {
  183                 ck_pr_store_uint(&reader->n_readers, reader->n_readers + 1);
  184                 return;
  185         }
  186 
  187         for (;;) {
  188                 while (ck_pr_load_uint(&br->writer) == true)
  189                         ck_pr_stall();
  190 
  191 #if defined(__x86__) || defined(__x86_64__)
  192                 ck_pr_fas_uint(&reader->n_readers, 1);
  193 
  194                 /*
  195                  * Serialize reader counter update with respect to load of
  196                  * writer.
  197                  */
  198                 ck_pr_fence_atomic_load();
  199 #else
  200                 ck_pr_store_uint(&reader->n_readers, 1);
  201 
  202                 /*
  203                  * Serialize reader counter update with respect to load of
  204                  * writer.
  205                  */
  206                 ck_pr_fence_store_load();
  207 #endif
  208 
  209                 if (ck_pr_load_uint(&br->writer) == false)
  210                         break;
  211 
  212                 ck_pr_store_uint(&reader->n_readers, 0);
  213         }
  214 
  215         ck_pr_fence_lock();
  216         return;
  217 }
  218 
  219 CK_CC_INLINE static bool
  220 ck_brlock_read_trylock(struct ck_brlock *br,
  221                        struct ck_brlock_reader *reader,
  222                        unsigned int factor)
  223 {
  224         unsigned int steps = 0;
  225 
  226         if (reader->n_readers >= 1) {
  227                 ck_pr_store_uint(&reader->n_readers, reader->n_readers + 1);
  228                 return true;
  229         }
  230 
  231         for (;;) {
  232                 while (ck_pr_load_uint(&br->writer) == true) {
  233                         if (++steps >= factor)
  234                                 return false;
  235 
  236                         ck_pr_stall();
  237                 }
  238 
  239 #if defined(__x86__) || defined(__x86_64__)
  240                 ck_pr_fas_uint(&reader->n_readers, 1);
  241 
  242                 /*
  243                  * Serialize reader counter update with respect to load of
  244                  * writer.
  245                  */
  246                 ck_pr_fence_atomic_load();
  247 #else
  248                 ck_pr_store_uint(&reader->n_readers, 1);
  249 
  250                 /*
  251                  * Serialize reader counter update with respect to load of
  252                  * writer.
  253                  */
  254                 ck_pr_fence_store_load();
  255 #endif
  256 
  257                 if (ck_pr_load_uint(&br->writer) == false)
  258                         break;
  259 
  260                 ck_pr_store_uint(&reader->n_readers, 0);
  261 
  262                 if (++steps >= factor)
  263                         return false;
  264         }
  265 
  266         ck_pr_fence_lock();
  267         return true;
  268 }
  269 
  270 CK_CC_INLINE static void
  271 ck_brlock_read_unlock(struct ck_brlock_reader *reader)
  272 {
  273 
  274         ck_pr_fence_unlock();
  275         ck_pr_store_uint(&reader->n_readers, reader->n_readers - 1);
  276         return;
  277 }
  278 
  279 #endif /* CK_BRLOCK_H */

Cache object: 09972548279be3bea70a3a8f56734662


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.