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/libprop/prop_array.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: prop_array.c,v 1.20 2008/08/11 05:54:21 christos 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 #include <libprop/prop_array.h>
   33 #include "prop_object_impl.h"
   34 
   35 #if !defined(_KERNEL) && !defined(_STANDALONE)
   36 #include <errno.h>
   37 #endif
   38 
   39 struct _prop_array {
   40         struct _prop_object     pa_obj;
   41         _PROP_RWLOCK_DECL(pa_rwlock)
   42         prop_object_t *         pa_array;
   43         unsigned int            pa_capacity;
   44         unsigned int            pa_count;
   45         int                     pa_flags;
   46 
   47         uint32_t                pa_version;
   48 };
   49 
   50 #define PA_F_IMMUTABLE          0x01    /* array is immutable */
   51 
   52 _PROP_POOL_INIT(_prop_array_pool, sizeof(struct _prop_array), "proparay")
   53 _PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop array",
   54                     "property array container object")
   55 
   56 static _prop_object_free_rv_t
   57                 _prop_array_free(prop_stack_t, prop_object_t *);
   58 static void     _prop_array_emergency_free(prop_object_t);
   59 static bool     _prop_array_externalize(
   60                                 struct _prop_object_externalize_context *,
   61                                 void *);
   62 static _prop_object_equals_rv_t
   63                 _prop_array_equals(prop_object_t, prop_object_t,
   64                                    void **, void **,
   65                                    prop_object_t *, prop_object_t *);
   66 static void     _prop_array_equals_finish(prop_object_t, prop_object_t);
   67 static prop_object_iterator_t
   68                 _prop_array_iterator_locked(prop_array_t);
   69 static prop_object_t
   70                 _prop_array_iterator_next_object_locked(void *);
   71 static void     _prop_array_iterator_reset_locked(void *);
   72 
   73 static const struct _prop_object_type _prop_object_type_array = {
   74         .pot_type               =       PROP_TYPE_ARRAY,
   75         .pot_free               =       _prop_array_free,
   76         .pot_emergency_free     =       _prop_array_emergency_free,
   77         .pot_extern             =       _prop_array_externalize,
   78         .pot_equals             =       _prop_array_equals,
   79         .pot_equals_finish      =       _prop_array_equals_finish,
   80 };
   81 
   82 #define prop_object_is_array(x)         \
   83         ((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array)
   84 
   85 #define prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0)
   86 
   87 struct _prop_array_iterator {
   88         struct _prop_object_iterator pai_base;
   89         unsigned int            pai_index;
   90 };
   91 
   92 #define EXPAND_STEP             16
   93 
   94 static _prop_object_free_rv_t
   95 _prop_array_free(prop_stack_t stack, prop_object_t *obj)
   96 {
   97         prop_array_t pa = *obj;
   98         prop_object_t po;
   99 
  100         _PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
  101         _PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) ||
  102                      (pa->pa_capacity != 0 && pa->pa_array != NULL));
  103 
  104         /* The easy case is an empty array, just free and return. */
  105         if (pa->pa_count == 0) {
  106                 if (pa->pa_array != NULL)
  107                         _PROP_FREE(pa->pa_array, M_PROP_ARRAY);
  108 
  109                 _PROP_RWLOCK_DESTROY(pa->pa_rwlock);
  110 
  111                 _PROP_POOL_PUT(_prop_array_pool, pa);
  112 
  113                 return (_PROP_OBJECT_FREE_DONE);
  114         }
  115 
  116         po = pa->pa_array[pa->pa_count - 1];
  117         _PROP_ASSERT(po != NULL);
  118 
  119         if (stack == NULL) {
  120                 /*
  121                  * If we are in emergency release mode,
  122                  * just let caller recurse down.
  123                  */
  124                 *obj = po;
  125                 return (_PROP_OBJECT_FREE_FAILED);
  126         }
  127 
  128         /* Otherwise, try to push the current object on the stack. */
  129         if (!_prop_stack_push(stack, pa, NULL, NULL, NULL)) {
  130                 /* Push failed, entering emergency release mode. */
  131                 return (_PROP_OBJECT_FREE_FAILED);
  132         }
  133         /* Object pushed on stack, caller will release it. */
  134         --pa->pa_count;
  135         *obj = po;
  136         return (_PROP_OBJECT_FREE_RECURSE);
  137 }
  138 
  139 static void
  140 _prop_array_emergency_free(prop_object_t obj)
  141 {
  142         prop_array_t pa = obj;
  143 
  144         _PROP_ASSERT(pa->pa_count != 0);
  145         --pa->pa_count;
  146 }
  147 
  148 static bool
  149 _prop_array_externalize(struct _prop_object_externalize_context *ctx,
  150                         void *v)
  151 {
  152         prop_array_t pa = v;
  153         struct _prop_object *po;
  154         prop_object_iterator_t pi;
  155         unsigned int i;
  156         bool rv = false;
  157 
  158         _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
  159 
  160         if (pa->pa_count == 0) {
  161                 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  162                 return (_prop_object_externalize_empty_tag(ctx, "array"));
  163         }
  164 
  165         /* XXXJRT Hint "count" for the internalize step? */
  166         if (_prop_object_externalize_start_tag(ctx, "array") == false ||
  167             _prop_object_externalize_append_char(ctx, '\n') == false)
  168                 goto out;
  169 
  170         pi = _prop_array_iterator_locked(pa);
  171         if (pi == NULL)
  172                 goto out;
  173 
  174         ctx->poec_depth++;
  175         _PROP_ASSERT(ctx->poec_depth != 0);
  176 
  177         while ((po = _prop_array_iterator_next_object_locked(pi)) != NULL) {
  178                 if ((*po->po_type->pot_extern)(ctx, po) == false) {
  179                         prop_object_iterator_release(pi);
  180                         goto out;
  181                 }
  182         }
  183 
  184         prop_object_iterator_release(pi);
  185 
  186         ctx->poec_depth--;
  187         for (i = 0; i < ctx->poec_depth; i++) {
  188                 if (_prop_object_externalize_append_char(ctx, '\t') == false)
  189                         goto out;
  190         }
  191         if (_prop_object_externalize_end_tag(ctx, "array") == false)
  192                 goto out;
  193 
  194         rv = true;
  195 
  196  out:
  197         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  198         return (rv);
  199 }
  200 
  201 /* ARGSUSED */
  202 static _prop_object_equals_rv_t
  203 _prop_array_equals(prop_object_t v1, prop_object_t v2,
  204     void **stored_pointer1, void **stored_pointer2,
  205     prop_object_t *next_obj1, prop_object_t *next_obj2)
  206 {
  207         prop_array_t array1 = v1;
  208         prop_array_t array2 = v2;
  209         uintptr_t idx;
  210         _prop_object_equals_rv_t rv = _PROP_OBJECT_EQUALS_FALSE;
  211 
  212         if (array1 == array2)
  213                 return (_PROP_OBJECT_EQUALS_TRUE);
  214 
  215         _PROP_ASSERT(*stored_pointer1 == *stored_pointer2);
  216         idx = (uintptr_t)*stored_pointer1;
  217 
  218         /* For the first iteration, lock the objects. */
  219         if (idx == 0) {
  220                 if ((uintptr_t)array1 < (uintptr_t)array2) {
  221                         _PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
  222                         _PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
  223                 } else {
  224                         _PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
  225                         _PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
  226                 }
  227         }
  228 
  229         if (array1->pa_count != array2->pa_count)
  230                 goto out;
  231         if (idx == array1->pa_count) {
  232                 rv = _PROP_OBJECT_EQUALS_TRUE;
  233                 goto out;
  234         }
  235         _PROP_ASSERT(idx < array1->pa_count);
  236 
  237         *stored_pointer1 = (void *)(idx + 1);
  238         *stored_pointer2 = (void *)(idx + 1);
  239 
  240         *next_obj1 = array1->pa_array[idx];
  241         *next_obj2 = array2->pa_array[idx];
  242 
  243         return (_PROP_OBJECT_EQUALS_RECURSE);
  244 
  245  out:
  246         _PROP_RWLOCK_UNLOCK(array1->pa_rwlock);
  247         _PROP_RWLOCK_UNLOCK(array2->pa_rwlock);
  248         return (rv);
  249 }
  250 
  251 static void
  252 _prop_array_equals_finish(prop_object_t v1, prop_object_t v2)
  253 {
  254         _PROP_RWLOCK_UNLOCK(((prop_array_t)v1)->pa_rwlock);
  255         _PROP_RWLOCK_UNLOCK(((prop_array_t)v2)->pa_rwlock);
  256 }
  257 
  258 static prop_array_t
  259 _prop_array_alloc(unsigned int capacity)
  260 {
  261         prop_array_t pa;
  262         prop_object_t *array;
  263 
  264         if (capacity != 0) {
  265                 array = _PROP_CALLOC(capacity * sizeof(prop_object_t),
  266                                      M_PROP_ARRAY);
  267                 if (array == NULL)
  268                         return (NULL);
  269         } else
  270                 array = NULL;
  271 
  272         pa = _PROP_POOL_GET(_prop_array_pool);
  273         if (pa != NULL) {
  274                 _prop_object_init(&pa->pa_obj, &_prop_object_type_array);
  275                 pa->pa_obj.po_type = &_prop_object_type_array;
  276 
  277                 _PROP_RWLOCK_INIT(pa->pa_rwlock);
  278                 pa->pa_array = array;
  279                 pa->pa_capacity = capacity;
  280                 pa->pa_count = 0;
  281                 pa->pa_flags = 0;
  282 
  283                 pa->pa_version = 0;
  284         } else if (array != NULL)
  285                 _PROP_FREE(array, M_PROP_ARRAY);
  286 
  287         return (pa);
  288 }
  289 
  290 static bool
  291 _prop_array_expand(prop_array_t pa, unsigned int capacity)
  292 {
  293         prop_object_t *array, *oarray;
  294 
  295         /*
  296          * Array must be WRITE-LOCKED.
  297          */
  298 
  299         oarray = pa->pa_array;
  300 
  301         array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY);
  302         if (array == NULL)
  303                 return (false);
  304         if (oarray != NULL)
  305                 memcpy(array, oarray, pa->pa_capacity * sizeof(*array));
  306         pa->pa_array = array;
  307         pa->pa_capacity = capacity;
  308 
  309         if (oarray != NULL)
  310                 _PROP_FREE(oarray, M_PROP_ARRAY);
  311 
  312         return (true);
  313 }
  314 
  315 static prop_object_t
  316 _prop_array_iterator_next_object_locked(void *v)
  317 {
  318         struct _prop_array_iterator *pai = v;
  319         prop_array_t pa = pai->pai_base.pi_obj;
  320         prop_object_t po = NULL;
  321 
  322         _PROP_ASSERT(prop_object_is_array(pa));
  323 
  324         if (pa->pa_version != pai->pai_base.pi_version)
  325                 goto out;       /* array changed during iteration */
  326 
  327         _PROP_ASSERT(pai->pai_index <= pa->pa_count);
  328 
  329         if (pai->pai_index == pa->pa_count)
  330                 goto out;       /* we've iterated all objects */
  331 
  332         po = pa->pa_array[pai->pai_index];
  333         pai->pai_index++;
  334 
  335  out:
  336         return (po);
  337 }
  338 
  339 static prop_object_t
  340 _prop_array_iterator_next_object(void *v)
  341 {
  342         struct _prop_array_iterator *pai = v;
  343         prop_array_t pa = pai->pai_base.pi_obj;
  344         prop_object_t po;
  345 
  346         _PROP_ASSERT(prop_object_is_array(pa));
  347 
  348         _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
  349         po = _prop_array_iterator_next_object_locked(pai);
  350         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  351         return (po);
  352 }
  353 
  354 static void
  355 _prop_array_iterator_reset_locked(void *v)
  356 {
  357         struct _prop_array_iterator *pai = v;
  358         prop_array_t pa = pai->pai_base.pi_obj;
  359 
  360         _PROP_ASSERT(prop_object_is_array(pa));
  361 
  362         pai->pai_index = 0;
  363         pai->pai_base.pi_version = pa->pa_version;
  364 }
  365 
  366 static void
  367 _prop_array_iterator_reset(void *v)
  368 {
  369         struct _prop_array_iterator *pai = v;
  370         prop_array_t pa = pai->pai_base.pi_obj;
  371 
  372         _PROP_ASSERT(prop_object_is_array(pa));
  373 
  374         _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
  375         _prop_array_iterator_reset_locked(pai);
  376         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  377 }
  378 
  379 /*
  380  * prop_array_create --
  381  *      Create an empty array.
  382  */
  383 prop_array_t
  384 prop_array_create(void)
  385 {
  386 
  387         return (_prop_array_alloc(0));
  388 }
  389 
  390 /*
  391  * prop_array_create_with_capacity --
  392  *      Create an array with the capacity to store N objects.
  393  */
  394 prop_array_t
  395 prop_array_create_with_capacity(unsigned int capacity)
  396 {
  397 
  398         return (_prop_array_alloc(capacity));
  399 }
  400 
  401 /*
  402  * prop_array_copy --
  403  *      Copy an array.  The new array has an initial capacity equal to
  404  *      the number of objects stored in the original array.  The new
  405  *      array contains references to the original array's objects, not
  406  *      copies of those objects (i.e. a shallow copy).
  407  */
  408 prop_array_t
  409 prop_array_copy(prop_array_t opa)
  410 {
  411         prop_array_t pa;
  412         prop_object_t po;
  413         unsigned int idx;
  414 
  415         if (! prop_object_is_array(opa))
  416                 return (NULL);
  417 
  418         _PROP_RWLOCK_RDLOCK(opa->pa_rwlock);
  419 
  420         pa = _prop_array_alloc(opa->pa_count);
  421         if (pa != NULL) {
  422                 for (idx = 0; idx < opa->pa_count; idx++) {
  423                         po = opa->pa_array[idx];
  424                         prop_object_retain(po);
  425                         pa->pa_array[idx] = po;
  426                 }
  427                 pa->pa_count = opa->pa_count;
  428                 pa->pa_flags = opa->pa_flags;
  429         }
  430         _PROP_RWLOCK_UNLOCK(opa->pa_rwlock);
  431         return (pa);
  432 }
  433 
  434 /*
  435  * prop_array_copy_mutable --
  436  *      Like prop_array_copy(), but the resulting array is mutable.
  437  */
  438 prop_array_t
  439 prop_array_copy_mutable(prop_array_t opa)
  440 {
  441         prop_array_t pa;
  442 
  443         pa = prop_array_copy(opa);
  444         if (pa != NULL)
  445                 pa->pa_flags &= ~PA_F_IMMUTABLE;
  446 
  447         return (pa);
  448 }
  449 
  450 /*
  451  * prop_array_capacity --
  452  *      Return the capacity of the array.
  453  */
  454 unsigned int
  455 prop_array_capacity(prop_array_t pa)
  456 {
  457         unsigned int rv;
  458 
  459         if (! prop_object_is_array(pa))
  460                 return (0);
  461 
  462         _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
  463         rv = pa->pa_capacity;
  464         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  465 
  466         return (rv);
  467 }
  468 
  469 /*
  470  * prop_array_count --
  471  *      Return the number of objects stored in the array.
  472  */
  473 unsigned int
  474 prop_array_count(prop_array_t pa)
  475 {
  476         unsigned int rv;
  477 
  478         if (! prop_object_is_array(pa))
  479                 return (0);
  480 
  481         _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
  482         rv = pa->pa_count;
  483         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  484 
  485         return (rv);
  486 }
  487 
  488 /*
  489  * prop_array_ensure_capacity --
  490  *      Ensure that the array has the capacity to store the specified
  491  *      total number of objects (inluding the objects already stored
  492  *      in the array).
  493  */
  494 bool
  495 prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity)
  496 {
  497         bool rv;
  498 
  499         if (! prop_object_is_array(pa))
  500                 return (false);
  501 
  502         _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
  503         if (capacity > pa->pa_capacity)
  504                 rv = _prop_array_expand(pa, capacity);
  505         else
  506                 rv = true;
  507         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  508 
  509         return (rv);
  510 }
  511 
  512 static prop_object_iterator_t
  513 _prop_array_iterator_locked(prop_array_t pa)
  514 {
  515         struct _prop_array_iterator *pai;
  516 
  517         if (! prop_object_is_array(pa))
  518                 return (NULL);
  519 
  520         pai = _PROP_CALLOC(sizeof(*pai), M_TEMP);
  521         if (pai == NULL)
  522                 return (NULL);
  523         pai->pai_base.pi_next_object = _prop_array_iterator_next_object;
  524         pai->pai_base.pi_reset = _prop_array_iterator_reset;
  525         prop_object_retain(pa);
  526         pai->pai_base.pi_obj = pa;
  527         _prop_array_iterator_reset_locked(pai);
  528 
  529         return (&pai->pai_base);
  530 }
  531 
  532 /*
  533  * prop_array_iterator --
  534  *      Return an iterator for the array.  The array is retained by
  535  *      the iterator.
  536  */
  537 prop_object_iterator_t
  538 prop_array_iterator(prop_array_t pa)
  539 {
  540         prop_object_iterator_t pi;
  541 
  542         _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
  543         pi = _prop_array_iterator_locked(pa);
  544         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  545         return (pi);
  546 }
  547 
  548 /*
  549  * prop_array_make_immutable --
  550  *      Make the array immutable.
  551  */
  552 void
  553 prop_array_make_immutable(prop_array_t pa)
  554 {
  555 
  556         _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
  557         if (prop_array_is_immutable(pa) == false)
  558                 pa->pa_flags |= PA_F_IMMUTABLE;
  559         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  560 }
  561 
  562 /*
  563  * prop_array_mutable --
  564  *      Returns true if the array is mutable.
  565  */
  566 bool
  567 prop_array_mutable(prop_array_t pa)
  568 {
  569         bool rv;
  570 
  571         _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
  572         rv = prop_array_is_immutable(pa) == false;
  573         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  574 
  575         return (rv);
  576 }
  577 
  578 /*
  579  * prop_array_get --
  580  *      Return the object stored at the specified array index.
  581  */
  582 prop_object_t
  583 prop_array_get(prop_array_t pa, unsigned int idx)
  584 {
  585         prop_object_t po = NULL;
  586 
  587         if (! prop_object_is_array(pa))
  588                 return (NULL);
  589 
  590         _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
  591         if (idx >= pa->pa_count)
  592                 goto out;
  593         po = pa->pa_array[idx];
  594         _PROP_ASSERT(po != NULL);
  595  out:
  596         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  597         return (po);
  598 }
  599 
  600 static bool
  601 _prop_array_add(prop_array_t pa, prop_object_t po)
  602 {
  603 
  604         /*
  605          * Array must be WRITE-LOCKED.
  606          */
  607 
  608         _PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
  609 
  610         if (prop_array_is_immutable(pa) ||
  611             (pa->pa_count == pa->pa_capacity &&
  612             _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false))
  613                 return (false);
  614 
  615         prop_object_retain(po);
  616         pa->pa_array[pa->pa_count++] = po;
  617         pa->pa_version++;
  618 
  619         return (true);
  620 }
  621 
  622 /*
  623  * prop_array_set --
  624  *      Store a reference to an object at the specified array index.
  625  *      This method is not allowed to create holes in the array; the
  626  *      caller must either be setting the object just beyond the existing
  627  *      count or replacing an already existing object reference.
  628  */
  629 bool
  630 prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po)
  631 {
  632         prop_object_t opo;
  633         bool rv = false;
  634 
  635         if (! prop_object_is_array(pa))
  636                 return (false);
  637 
  638         _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
  639 
  640         if (prop_array_is_immutable(pa))
  641                 goto out;
  642 
  643         if (idx == pa->pa_count) {
  644                 rv = _prop_array_add(pa, po);
  645                 goto out;
  646         }
  647 
  648         _PROP_ASSERT(idx < pa->pa_count);
  649 
  650         opo = pa->pa_array[idx];
  651         _PROP_ASSERT(opo != NULL);
  652 
  653         prop_object_retain(po);
  654         pa->pa_array[idx] = po;
  655         pa->pa_version++;
  656 
  657         prop_object_release(opo);
  658 
  659         rv = true;
  660 
  661  out:
  662         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  663         return (rv);
  664 }
  665 
  666 /*
  667  * prop_array_add --
  668  *      Add a reference to an object to the specified array, appending
  669  *      to the end and growing the array's capacity, if necessary.
  670  */
  671 bool
  672 prop_array_add(prop_array_t pa, prop_object_t po)
  673 {
  674         bool rv;
  675 
  676         if (! prop_object_is_array(pa))
  677                 return (false);
  678 
  679         _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
  680         rv = _prop_array_add(pa, po);
  681         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  682 
  683         return (rv);
  684 }
  685 
  686 /*
  687  * prop_array_remove --
  688  *      Remove the reference to an object from an array at the specified
  689  *      index.  The array will be compacted following the removal.
  690  */
  691 void
  692 prop_array_remove(prop_array_t pa, unsigned int idx)
  693 {
  694         prop_object_t po;
  695 
  696         if (! prop_object_is_array(pa))
  697                 return;
  698 
  699         _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
  700 
  701         _PROP_ASSERT(idx < pa->pa_count);
  702 
  703         /* XXX Should this be a _PROP_ASSERT()? */
  704         if (prop_array_is_immutable(pa)) {
  705                 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  706                 return;
  707         }
  708 
  709         po = pa->pa_array[idx];
  710         _PROP_ASSERT(po != NULL);
  711 
  712         for (++idx; idx < pa->pa_count; idx++)
  713                 pa->pa_array[idx - 1] = pa->pa_array[idx];
  714         pa->pa_count--;
  715         pa->pa_version++;
  716 
  717         _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
  718 
  719         prop_object_release(po);
  720 }
  721 
  722 /*
  723  * prop_array_equals --
  724  *      Return true if the two arrays are equivalent.  Note we do a
  725  *      by-value comparison of the objects in the array.
  726  */
  727 bool
  728 prop_array_equals(prop_array_t array1, prop_array_t array2)
  729 {
  730         if (!prop_object_is_array(array1) || !prop_object_is_array(array2))
  731                 return (false);
  732 
  733         return (prop_object_equals(array1, array2));
  734 }
  735 
  736 /*
  737  * prop_array_externalize --
  738  *      Externalize an array, return a NUL-terminated buffer
  739  *      containing the XML-style representation.  The buffer is allocated
  740  *      with the M_TEMP memory type.
  741  */
  742 char *
  743 prop_array_externalize(prop_array_t pa)
  744 {
  745         struct _prop_object_externalize_context *ctx;
  746         char *cp;
  747 
  748         ctx = _prop_object_externalize_context_alloc();
  749         if (ctx == NULL)
  750                 return (NULL);
  751 
  752         if (_prop_object_externalize_header(ctx) == false ||
  753             (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false ||
  754             _prop_object_externalize_footer(ctx) == false) {
  755                 /* We are responsible for releasing the buffer. */
  756                 _PROP_FREE(ctx->poec_buf, M_TEMP);
  757                 _prop_object_externalize_context_free(ctx);
  758                 return (NULL);
  759         }
  760 
  761         cp = ctx->poec_buf;
  762         _prop_object_externalize_context_free(ctx);
  763 
  764         return (cp);
  765 }
  766 
  767 /*
  768  * _prop_array_internalize --
  769  *      Parse an <array>...</array> and return the object created from the
  770  *      external representation.
  771  */
  772 static bool _prop_array_internalize_body(prop_stack_t, prop_object_t *,
  773     struct _prop_object_internalize_context *);
  774 
  775 bool
  776 _prop_array_internalize(prop_stack_t stack, prop_object_t *obj,
  777     struct _prop_object_internalize_context *ctx)
  778 {
  779         /* We don't currently understand any attributes. */
  780         if (ctx->poic_tagattr != NULL)
  781                 return (true);
  782 
  783         *obj = prop_array_create();
  784         /*
  785          * We are done if the create failed or no child elements exist.
  786          */
  787         if (*obj == NULL || ctx->poic_is_empty_element)
  788                 return (true);
  789 
  790         /*
  791          * Opening tag is found, now continue to the first element.
  792          */
  793         return (_prop_array_internalize_body(stack, obj, ctx));
  794 }
  795 
  796 static bool
  797 _prop_array_internalize_continue(prop_stack_t stack,
  798     prop_object_t *obj,
  799     struct _prop_object_internalize_context *ctx,
  800     void *data, prop_object_t child)
  801 {
  802         prop_array_t array;
  803 
  804         _PROP_ASSERT(data == NULL);
  805 
  806         if (child == NULL)
  807                 goto bad; /* Element could not be parsed. */
  808 
  809         array = *obj;
  810 
  811         if (prop_array_add(array, child) == false) {
  812                 prop_object_release(child);
  813                 goto bad;
  814         }
  815         prop_object_release(child);
  816 
  817         /*
  818          * Current element is processed and added, look for next.
  819          */
  820         return (_prop_array_internalize_body(stack, obj, ctx));
  821 
  822  bad:
  823         prop_object_release(*obj);
  824         *obj = NULL;
  825         return (true);
  826 }
  827 
  828 static bool
  829 _prop_array_internalize_body(prop_stack_t stack, prop_object_t *obj,
  830     struct _prop_object_internalize_context *ctx)
  831 {
  832         prop_array_t array = *obj;
  833 
  834         _PROP_ASSERT(array != NULL);
  835 
  836         /* Fetch the next tag. */
  837         if (_prop_object_internalize_find_tag(ctx, NULL,
  838                                 _PROP_TAG_TYPE_EITHER) == false)
  839                 goto bad;
  840 
  841         /* Check to see if this is the end of the array. */
  842         if (_PROP_TAG_MATCH(ctx, "array") &&
  843             ctx->poic_tag_type == _PROP_TAG_TYPE_END) {
  844                 /* It is, so don't iterate any further. */
  845                 return (true);
  846         }
  847 
  848         if (_prop_stack_push(stack, array,
  849                              _prop_array_internalize_continue, NULL, NULL))
  850                 return (false);
  851 
  852  bad:
  853         prop_object_release(array);
  854         *obj = NULL;
  855         return (true);
  856 }
  857 
  858 /*
  859  * prop_array_internalize --
  860  *      Create an array by parsing the XML-style representation.
  861  */
  862 prop_array_t
  863 prop_array_internalize(const char *xml)
  864 {
  865         return _prop_generic_internalize(xml, "array");
  866 }
  867 
  868 #if !defined(_KERNEL) && !defined(_STANDALONE)
  869 /*
  870  * prop_array_externalize_to_file --
  871  *      Externalize an array to the specified file.
  872  */
  873 bool
  874 prop_array_externalize_to_file(prop_array_t array, const char *fname)
  875 {
  876         char *xml;
  877         bool rv;
  878         int save_errno = 0;     /* XXXGCC -Wuninitialized [mips, ...] */
  879 
  880         xml = prop_array_externalize(array);
  881         if (xml == NULL)
  882                 return (false);
  883         rv = _prop_object_externalize_write_file(fname, xml, strlen(xml));
  884         if (rv == false)
  885                 save_errno = errno;
  886         _PROP_FREE(xml, M_TEMP);
  887         if (rv == false)
  888                 errno = save_errno;
  889 
  890         return (rv);
  891 }
  892 
  893 /*
  894  * prop_array_internalize_from_file --
  895  *      Internalize an array from a file.
  896  */
  897 prop_array_t
  898 prop_array_internalize_from_file(const char *fname)
  899 {
  900         struct _prop_object_internalize_mapped_file *mf;
  901         prop_array_t array;
  902 
  903         mf = _prop_object_internalize_map_file(fname);
  904         if (mf == NULL)
  905                 return (NULL);
  906         array = prop_array_internalize(mf->poimf_xml);
  907         _prop_object_internalize_unmap_file(mf);
  908 
  909         return (array);
  910 }
  911 #endif /* _KERNEL && !_STANDALONE */

Cache object: 4a69c38e9fe62d0f4b62de5e5f391c4a


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