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.13 2008/04/28 20:24:04 martin 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.13 2008/04/28 20:24:04 martin 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         KASSERT(sd != NULL);
  157         mutex_init(&sd->sd_lock, MUTEX_DEFAULT, IPL_NONE);
  158         LIST_INIT(&sd->sd_list);
  159 
  160         return (sd);
  161 }
  162 
  163 /*
  164  * specificdata_domain_delete --
  165  *      Destroy a specificdata domain.
  166  */
  167 void
  168 specificdata_domain_delete(specificdata_domain_t sd)
  169 {
  170 
  171         panic("specificdata_domain_delete: not implemented");
  172 }
  173 
  174 /*
  175  * specificdata_key_create --
  176  *      Create a specificdata key for a domain.
  177  *
  178  *      Note: This is a rare operation.
  179  */
  180 int
  181 specificdata_key_create(specificdata_domain_t sd, specificdata_key_t *keyp,
  182                         specificdata_dtor_t dtor)
  183 {
  184         specificdata_key_impl *newkeys;
  185         specificdata_key_t key = 0;
  186         size_t nsz;
  187 
  188         ASSERT_SLEEPABLE();
  189 
  190         if (dtor == NULL)
  191                 dtor = specificdata_noop_dtor;
  192         
  193         mutex_enter(&sd->sd_lock);
  194 
  195         if (sd->sd_keys == NULL)
  196                 goto needalloc;
  197 
  198         for (; key < sd->sd_nkey; key++) {
  199                 if (sd->sd_keys[key].ski_dtor == NULL)
  200                         goto gotit;
  201         }
  202 
  203  needalloc:
  204         nsz = (sd->sd_nkey + 1) * sizeof(*newkeys);
  205         /* XXXSMP allocating memory while holding a lock. */
  206         newkeys = kmem_zalloc(nsz, KM_SLEEP);
  207         KASSERT(newkeys != NULL);
  208         if (sd->sd_keys != NULL) {
  209                 size_t osz = sd->sd_nkey * sizeof(*newkeys);
  210                 memcpy(newkeys, sd->sd_keys, osz);
  211                 kmem_free(sd->sd_keys, osz);
  212         }
  213         sd->sd_keys = newkeys;
  214         sd->sd_nkey++;
  215  gotit:
  216         sd->sd_keys[key].ski_dtor = dtor;
  217 
  218         mutex_exit(&sd->sd_lock);
  219 
  220         *keyp = key;
  221         return (0);
  222 }
  223 
  224 /*
  225  * specificdata_key_delete --
  226  *      Destroy a specificdata key for a domain.
  227  *
  228  *      Note: This is a rare operation.
  229  */
  230 void
  231 specificdata_key_delete(specificdata_domain_t sd, specificdata_key_t key)
  232 {
  233         specificdata_container_t sc;
  234 
  235         mutex_enter(&sd->sd_lock);
  236 
  237         if (key >= sd->sd_nkey)
  238                 goto out;
  239 
  240         /*
  241          * Traverse all of the specificdata containers in the domain
  242          * and the destroy the datum for the dying key.
  243          */
  244         LIST_FOREACH(sc, &sd->sd_list, sc_list) {
  245                 specificdata_destroy_datum(sd, sc, key);
  246         }
  247 
  248         sd->sd_keys[key].ski_dtor = NULL;
  249 
  250  out:
  251         mutex_exit(&sd->sd_lock);
  252 }
  253 
  254 /*
  255  * specificdata_init --
  256  *      Initialize a specificdata container for operation in the
  257  *      specified domain.
  258  */
  259 int
  260 specificdata_init(specificdata_domain_t sd, specificdata_reference *ref)
  261 {
  262 
  263         /*
  264          * Just NULL-out the container pointer; we'll allocate the
  265          * container the first time specificdata is put into it.
  266          */
  267         ref->specdataref_container = NULL;
  268         mutex_init(&ref->specdataref_lock, MUTEX_DEFAULT, IPL_NONE);
  269 
  270         return (0);
  271 }
  272 
  273 /*
  274  * specificdata_fini --
  275  *      Destroy a specificdata container.  We destroy all of the datums
  276  *      stuffed into the container just as if the key were destroyed.
  277  */
  278 void
  279 specificdata_fini(specificdata_domain_t sd, specificdata_reference *ref)
  280 {
  281         specificdata_container_t sc;
  282         specificdata_key_t key;
  283 
  284         ASSERT_SLEEPABLE();
  285 
  286         mutex_destroy(&ref->specdataref_lock);
  287 
  288         sc = ref->specdataref_container;
  289         if (sc == NULL)
  290                 return;
  291         ref->specdataref_container = NULL;
  292         
  293         mutex_enter(&sd->sd_lock);
  294 
  295         specificdata_container_unlink(sd, sc);
  296         for (key = 0; key < sc->sc_nkey; key++) {
  297                 specificdata_destroy_datum(sd, sc, key);
  298         }
  299 
  300         mutex_exit(&sd->sd_lock);
  301 
  302         kmem_free(sc, SPECIFICDATA_CONTAINER_BYTESIZE(sc->sc_nkey));
  303 }
  304 
  305 /*
  306  * specificdata_getspecific --
  307  *      Get a datum from a container.
  308  */
  309 void *
  310 specificdata_getspecific(specificdata_domain_t sd, specificdata_reference *ref,
  311                          specificdata_key_t key)
  312 {
  313         specificdata_container_t sc;
  314         void *data = NULL;
  315 
  316         mutex_enter(&ref->specdataref_lock);
  317 
  318         sc = ref->specdataref_container;
  319         if (sc != NULL && key < sc->sc_nkey)
  320                 data = sc->sc_data[key];
  321 
  322         mutex_exit(&ref->specdataref_lock);
  323 
  324         return (data);
  325 }
  326 
  327 /*
  328  * specificdata_getspecific_unlocked --
  329  *      Get a datum from a container in a lockless fashion.
  330  *
  331  *      Note: When using this routine, care must be taken to ensure
  332  *      that no other thread could cause the specificdata_reference
  333  *      to become invalid (i.e. point at the wrong container) by
  334  *      issuing a setspecific call or destroying the container.
  335  */
  336 void *
  337 specificdata_getspecific_unlocked(specificdata_domain_t sd,
  338                                   specificdata_reference *ref,
  339                                   specificdata_key_t key)
  340 {
  341         specificdata_container_t sc;
  342         
  343         sc = ref->specdataref_container;
  344         if (sc != NULL && key < sc->sc_nkey)
  345                 return (sc->sc_data[key]);
  346 
  347         return (NULL);
  348 }
  349 
  350 /*
  351  * specificdata_setspecific --
  352  *      Put a datum into a container.
  353  */
  354 void
  355 specificdata_setspecific(specificdata_domain_t sd,
  356                          specificdata_reference *ref,
  357                          specificdata_key_t key, void *data)
  358 {
  359         specificdata_container_t sc, newsc;
  360         size_t newnkey, sz;
  361 
  362         ASSERT_SLEEPABLE();
  363 
  364         mutex_enter(&ref->specdataref_lock);
  365 
  366         sc = ref->specdataref_container;
  367         if (__predict_true(sc != NULL && key < sc->sc_nkey)) {
  368                 sc->sc_data[key] = data;
  369                 mutex_exit(&ref->specdataref_lock);
  370                 return;
  371         }
  372 
  373         mutex_exit(&ref->specdataref_lock);
  374 
  375         /*
  376          * Slow path: need to resize.
  377          */
  378         
  379         mutex_enter(&sd->sd_lock);
  380         newnkey = sd->sd_nkey;
  381         if (key >= newnkey) {
  382                 mutex_exit(&sd->sd_lock);
  383                 panic("specificdata_setspecific");
  384         }
  385         sz = SPECIFICDATA_CONTAINER_BYTESIZE(newnkey);
  386         newsc = kmem_zalloc(sz, KM_SLEEP);
  387         KASSERT(newsc != NULL);
  388         newsc->sc_nkey = newnkey;
  389 
  390         mutex_enter(&ref->specdataref_lock);
  391 
  392         sc = ref->specdataref_container;
  393         if (sc != NULL) {
  394                 if (key < sc->sc_nkey) {
  395                         /*
  396                          * Someone beat us to the punch.  Unwind and put
  397                          * the object into the now large enough container.
  398                          */
  399                         sc->sc_data[key] = data;
  400                         mutex_exit(&ref->specdataref_lock);
  401                         mutex_exit(&sd->sd_lock);
  402                         kmem_free(newsc, sz);
  403                         return;
  404                 }
  405                 specificdata_container_unlink(sd, sc);
  406                 memcpy(newsc->sc_data, sc->sc_data,
  407                        sc->sc_nkey * sizeof(void *));
  408         }
  409         newsc->sc_data[key] = data;
  410         specificdata_container_link(sd, newsc);
  411         ref->specdataref_container = newsc;
  412 
  413         mutex_exit(&ref->specdataref_lock);
  414         mutex_exit(&sd->sd_lock);
  415 
  416         if (sc != NULL)
  417                 kmem_free(sc, SPECIFICDATA_CONTAINER_BYTESIZE(sc->sc_nkey));
  418 }

Cache object: f07bf2cc8be543430ee6cfdb23586d2a


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