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/kern/subr_specificdata.c

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 /*      $NetBSD: subr_specificdata.c,v 1.14 2017/06/01 02:45:13 chs Exp $       */
    2 
    3 /*-
    4  * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*-
   33  * Copyright (c) 2006 YAMAMOTO Takashi.
   34  * All rights reserved.
   35  *
   36  * Redistribution and use in source and binary forms, with or without
   37  * modification, are permitted provided that the following conditions
   38  * are met:
   39  * 1. Redistributions of source code must retain the above copyright
   40  *    notice, this list of conditions and the following disclaimer.
   41  * 2. Redistributions in binary form must reproduce the above copyright
   42  *    notice, this list of conditions and the following disclaimer in the
   43  *    documentation and/or other materials provided with the distribution.
   44  *
   45  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   55  * SUCH DAMAGE.
   56  */
   57 
   58 #include <sys/cdefs.h>
   59 __KERNEL_RCSID(0, "$NetBSD: subr_specificdata.c,v 1.14 2017/06/01 02:45:13 chs Exp $");
   60 
   61 #include <sys/param.h>
   62 #include <sys/kmem.h>
   63 #include <sys/specificdata.h>
   64 #include <sys/queue.h>
   65 #include <sys/mutex.h>
   66 
   67 /*
   68  * Locking notes:
   69  *
   70  * The specdataref_container pointer in the specificdata_reference
   71  * is volatile.  To read it, you must hold EITHER the domain lock
   72  * or the ref lock.  To write it, you must hold BOTH the domain lock
   73  * and the ref lock.  The locks must be acquired in the following
   74  * order:
   75  *      domain -> ref
   76  */
   77 
   78 typedef struct {
   79         specificdata_dtor_t     ski_dtor;
   80 } specificdata_key_impl;
   81 
   82 struct specificdata_container {
   83         size_t          sc_nkey;
   84         LIST_ENTRY(specificdata_container) sc_list;
   85         void *          sc_data[];      /* variable length */
   86 };
   87 
   88 #define SPECIFICDATA_CONTAINER_BYTESIZE(n)              \
   89         (sizeof(struct specificdata_container) + ((n) * sizeof(void *)))
   90 
   91 struct specificdata_domain {
   92         kmutex_t        sd_lock;
   93         unsigned int    sd_nkey;
   94         LIST_HEAD(, specificdata_container) sd_list;
   95         specificdata_key_impl *sd_keys;
   96 };
   97 
   98 static void
   99 specificdata_container_link(specificdata_domain_t sd,
  100                             specificdata_container_t sc)
  101 {
  102 
  103         LIST_INSERT_HEAD(&sd->sd_list, sc, sc_list);
  104 }
  105 
  106 static void
  107 specificdata_container_unlink(specificdata_domain_t sd,
  108                               specificdata_container_t sc)
  109 {
  110 
  111         LIST_REMOVE(sc, sc_list);
  112 }
  113 
  114 static void
  115 specificdata_destroy_datum(specificdata_domain_t sd,
  116                            specificdata_container_t sc, specificdata_key_t key)
  117 {
  118         specificdata_dtor_t dtor;
  119         void *data;
  120 
  121         if (key >= sc->sc_nkey)
  122                 return;
  123 
  124         KASSERT(key < sd->sd_nkey);
  125         
  126         data = sc->sc_data[key];
  127         dtor = sd->sd_keys[key].ski_dtor;
  128 
  129         if (dtor != NULL) {
  130                 if (data != NULL) {
  131                         sc->sc_data[key] = NULL;
  132                         (*dtor)(data);
  133                 }
  134         } else {
  135                 KASSERT(data == NULL);
  136         }
  137 }
  138 
  139 static void
  140 specificdata_noop_dtor(void *data)
  141 {
  142 
  143         /* nothing */
  144 }
  145 
  146 /*
  147  * specificdata_domain_create --
  148  *      Create a specificdata domain.
  149  */
  150 specificdata_domain_t
  151 specificdata_domain_create(void)
  152 {
  153         specificdata_domain_t sd;
  154 
  155         sd = kmem_zalloc(sizeof(*sd), KM_SLEEP);
  156         mutex_init(&sd->sd_lock, MUTEX_DEFAULT, IPL_NONE);
  157         LIST_INIT(&sd->sd_list);
  158 
  159         return (sd);
  160 }
  161 
  162 /*
  163  * specificdata_domain_delete --
  164  *      Destroy a specificdata domain.
  165  */
  166 void
  167 specificdata_domain_delete(specificdata_domain_t sd)
  168 {
  169 
  170         panic("specificdata_domain_delete: not implemented");
  171 }
  172 
  173 /*
  174  * specificdata_key_create --
  175  *      Create a specificdata key for a domain.
  176  *
  177  *      Note: This is a rare operation.
  178  */
  179 int
  180 specificdata_key_create(specificdata_domain_t sd, specificdata_key_t *keyp,
  181                         specificdata_dtor_t dtor)
  182 {
  183         specificdata_key_impl *newkeys;
  184         specificdata_key_t key = 0;
  185         size_t nsz;
  186 
  187         ASSERT_SLEEPABLE();
  188 
  189         if (dtor == NULL)
  190                 dtor = specificdata_noop_dtor;
  191         
  192         mutex_enter(&sd->sd_lock);
  193 
  194         if (sd->sd_keys == NULL)
  195                 goto needalloc;
  196 
  197         for (; key < sd->sd_nkey; key++) {
  198                 if (sd->sd_keys[key].ski_dtor == NULL)
  199                         goto gotit;
  200         }
  201 
  202  needalloc:
  203         nsz = (sd->sd_nkey + 1) * sizeof(*newkeys);
  204         /* XXXSMP allocating memory while holding a lock. */
  205         newkeys = kmem_zalloc(nsz, KM_SLEEP);
  206         if (sd->sd_keys != NULL) {
  207                 size_t osz = sd->sd_nkey * sizeof(*newkeys);
  208                 memcpy(newkeys, sd->sd_keys, osz);
  209                 kmem_free(sd->sd_keys, osz);
  210         }
  211         sd->sd_keys = newkeys;
  212         sd->sd_nkey++;
  213  gotit:
  214         sd->sd_keys[key].ski_dtor = dtor;
  215 
  216         mutex_exit(&sd->sd_lock);
  217 
  218         *keyp = key;
  219         return (0);
  220 }
  221 
  222 /*
  223  * specificdata_key_delete --
  224  *      Destroy a specificdata key for a domain.
  225  *
  226  *      Note: This is a rare operation.
  227  */
  228 void
  229 specificdata_key_delete(specificdata_domain_t sd, specificdata_key_t key)
  230 {
  231         specificdata_container_t sc;
  232 
  233         mutex_enter(&sd->sd_lock);
  234 
  235         if (key >= sd->sd_nkey)
  236                 goto out;
  237 
  238         /*
  239          * Traverse all of the specificdata containers in the domain
  240          * and the destroy the datum for the dying key.
  241          */
  242         LIST_FOREACH(sc, &sd->sd_list, sc_list) {
  243                 specificdata_destroy_datum(sd, sc, key);
  244         }
  245 
  246         sd->sd_keys[key].ski_dtor = NULL;
  247 
  248  out:
  249         mutex_exit(&sd->sd_lock);
  250 }
  251 
  252 /*
  253  * specificdata_init --
  254  *      Initialize a specificdata container for operation in the
  255  *      specified domain.
  256  */
  257 int
  258 specificdata_init(specificdata_domain_t sd, specificdata_reference *ref)
  259 {
  260 
  261         /*
  262          * Just NULL-out the container pointer; we'll allocate the
  263          * container the first time specificdata is put into it.
  264          */
  265         ref->specdataref_container = NULL;
  266         mutex_init(&ref->specdataref_lock, MUTEX_DEFAULT, IPL_NONE);
  267 
  268         return (0);
  269 }
  270 
  271 /*
  272  * specificdata_fini --
  273  *      Destroy a specificdata container.  We destroy all of the datums
  274  *      stuffed into the container just as if the key were destroyed.
  275  */
  276 void
  277 specificdata_fini(specificdata_domain_t sd, specificdata_reference *ref)
  278 {
  279         specificdata_container_t sc;
  280         specificdata_key_t key;
  281 
  282         ASSERT_SLEEPABLE();
  283 
  284         mutex_destroy(&ref->specdataref_lock);
  285 
  286         sc = ref->specdataref_container;
  287         if (sc == NULL)
  288                 return;
  289         ref->specdataref_container = NULL;
  290         
  291         mutex_enter(&sd->sd_lock);
  292 
  293         specificdata_container_unlink(sd, sc);
  294         for (key = 0; key < sc->sc_nkey; key++) {
  295                 specificdata_destroy_datum(sd, sc, key);
  296         }
  297 
  298         mutex_exit(&sd->sd_lock);
  299 
  300         kmem_free(sc, SPECIFICDATA_CONTAINER_BYTESIZE(sc->sc_nkey));
  301 }
  302 
  303 /*
  304  * specificdata_getspecific --
  305  *      Get a datum from a container.
  306  */
  307 void *
  308 specificdata_getspecific(specificdata_domain_t sd, specificdata_reference *ref,
  309                          specificdata_key_t key)
  310 {
  311         specificdata_container_t sc;
  312         void *data = NULL;
  313 
  314         mutex_enter(&ref->specdataref_lock);
  315 
  316         sc = ref->specdataref_container;
  317         if (sc != NULL && key < sc->sc_nkey)
  318                 data = sc->sc_data[key];
  319 
  320         mutex_exit(&ref->specdataref_lock);
  321 
  322         return (data);
  323 }
  324 
  325 /*
  326  * specificdata_getspecific_unlocked --
  327  *      Get a datum from a container in a lockless fashion.
  328  *
  329  *      Note: When using this routine, care must be taken to ensure
  330  *      that no other thread could cause the specificdata_reference
  331  *      to become invalid (i.e. point at the wrong container) by
  332  *      issuing a setspecific call or destroying the container.
  333  */
  334 void *
  335 specificdata_getspecific_unlocked(specificdata_domain_t sd,
  336                                   specificdata_reference *ref,
  337                                   specificdata_key_t key)
  338 {
  339         specificdata_container_t sc;
  340         
  341         sc = ref->specdataref_container;
  342         if (sc != NULL && key < sc->sc_nkey)
  343                 return (sc->sc_data[key]);
  344 
  345         return (NULL);
  346 }
  347 
  348 /*
  349  * specificdata_setspecific --
  350  *      Put a datum into a container.
  351  */
  352 void
  353 specificdata_setspecific(specificdata_domain_t sd,
  354                          specificdata_reference *ref,
  355                          specificdata_key_t key, void *data)
  356 {
  357         specificdata_container_t sc, newsc;
  358         size_t newnkey, sz;
  359 
  360         ASSERT_SLEEPABLE();
  361 
  362         mutex_enter(&ref->specdataref_lock);
  363 
  364         sc = ref->specdataref_container;
  365         if (__predict_true(sc != NULL && key < sc->sc_nkey)) {
  366                 sc->sc_data[key] = data;
  367                 mutex_exit(&ref->specdataref_lock);
  368                 return;
  369         }
  370 
  371         mutex_exit(&ref->specdataref_lock);
  372 
  373         /*
  374          * Slow path: need to resize.
  375          */
  376         
  377         mutex_enter(&sd->sd_lock);
  378         newnkey = sd->sd_nkey;
  379         if (key >= newnkey) {
  380                 mutex_exit(&sd->sd_lock);
  381                 panic("specificdata_setspecific");
  382         }
  383         sz = SPECIFICDATA_CONTAINER_BYTESIZE(newnkey);
  384         newsc = kmem_zalloc(sz, KM_SLEEP);
  385         newsc->sc_nkey = newnkey;
  386 
  387         mutex_enter(&ref->specdataref_lock);
  388 
  389         sc = ref->specdataref_container;
  390         if (sc != NULL) {
  391                 if (key < sc->sc_nkey) {
  392                         /*
  393                          * Someone beat us to the punch.  Unwind and put
  394                          * the object into the now large enough container.
  395                          */
  396                         sc->sc_data[key] = data;
  397                         mutex_exit(&ref->specdataref_lock);
  398                         mutex_exit(&sd->sd_lock);
  399                         kmem_free(newsc, sz);
  400                         return;
  401                 }
  402                 specificdata_container_unlink(sd, sc);
  403                 memcpy(newsc->sc_data, sc->sc_data,
  404                        sc->sc_nkey * sizeof(void *));
  405         }
  406         newsc->sc_data[key] = data;
  407         specificdata_container_link(sd, newsc);
  408         ref->specdataref_container = newsc;
  409 
  410         mutex_exit(&ref->specdataref_lock);
  411         mutex_exit(&sd->sd_lock);
  412 
  413         if (sc != NULL)
  414                 kmem_free(sc, SPECIFICDATA_CONTAINER_BYTESIZE(sc->sc_nkey));
  415 }

Cache object: b33585821d8958819d9e0bf43d612cc5


[ 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.