Home | History | Annotate | Line # | Download | only in libprop
prop_object.c revision 1.35.8.1
      1  1.35.8.1  perseant /*	$NetBSD: prop_object.c,v 1.35.8.1 2025/08/02 05:18:35 perseant Exp $	*/
      2       1.1   thorpej 
      3       1.1   thorpej /*-
      4  1.35.8.1  perseant  * Copyright (c) 2006, 2007, 2025 The NetBSD Foundation, Inc.
      5       1.1   thorpej  * All rights reserved.
      6       1.1   thorpej  *
      7       1.1   thorpej  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1   thorpej  * by Jason R. Thorpe.
      9       1.1   thorpej  *
     10       1.1   thorpej  * Redistribution and use in source and binary forms, with or without
     11       1.1   thorpej  * modification, are permitted provided that the following conditions
     12       1.1   thorpej  * are met:
     13       1.1   thorpej  * 1. Redistributions of source code must retain the above copyright
     14       1.1   thorpej  *    notice, this list of conditions and the following disclaimer.
     15       1.1   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1   thorpej  *    notice, this list of conditions and the following disclaimer in the
     17       1.1   thorpej  *    documentation and/or other materials provided with the distribution.
     18       1.1   thorpej  *
     19       1.1   thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1   thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1   thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1   thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1   thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1   thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1   thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1   thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1   thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1   thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1   thorpej  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1   thorpej  */
     31       1.1   thorpej 
     32      1.28     pooka #include "prop_object_impl.h"
     33       1.1   thorpej #include <prop/prop_object.h>
     34      1.28     pooka 
     35      1.28     pooka #ifdef _PROP_NEED_REFCNT_MTX
     36      1.28     pooka static pthread_mutex_t _prop_refcnt_mtx = PTHREAD_MUTEX_INITIALIZER;
     37      1.28     pooka #endif /* _PROP_NEED_REFCNT_MTX */
     38       1.1   thorpej 
     39       1.4   thorpej #if !defined(_KERNEL) && !defined(_STANDALONE)
     40       1.4   thorpej #include <sys/mman.h>
     41       1.4   thorpej #include <sys/stat.h>
     42       1.4   thorpej #include <errno.h>
     43       1.4   thorpej #include <fcntl.h>
     44       1.4   thorpej #include <limits.h>
     45       1.4   thorpej #include <unistd.h>
     46       1.4   thorpej #endif
     47       1.4   thorpej 
     48       1.1   thorpej #ifdef _STANDALONE
     49       1.1   thorpej void *
     50       1.1   thorpej _prop_standalone_calloc(size_t size)
     51       1.1   thorpej {
     52       1.1   thorpej 	void *rv;
     53       1.1   thorpej 
     54       1.1   thorpej 	rv = alloc(size);
     55       1.1   thorpej 	if (rv != NULL)
     56       1.1   thorpej 		memset(rv, 0, size);
     57       1.1   thorpej 
     58       1.1   thorpej 	return (rv);
     59       1.1   thorpej }
     60       1.2   thorpej 
     61       1.2   thorpej void *
     62       1.2   thorpej _prop_standalone_realloc(void *v, size_t size)
     63       1.2   thorpej {
     64       1.2   thorpej 	void *rv;
     65       1.2   thorpej 
     66       1.2   thorpej 	rv = alloc(size);
     67       1.2   thorpej 	if (rv != NULL) {
     68       1.2   thorpej 		memcpy(rv, v, size);	/* XXX */
     69       1.2   thorpej 		dealloc(v, 0);		/* XXX */
     70       1.2   thorpej 	}
     71      1.32  riastrad 
     72       1.2   thorpej 	return (rv);
     73       1.2   thorpej }
     74       1.1   thorpej #endif /* _STANDALONE */
     75       1.1   thorpej 
     76       1.1   thorpej /*
     77       1.1   thorpej  * _prop_object_init --
     78       1.1   thorpej  *	Initialize an object.  Called when sub-classes create
     79       1.1   thorpej  *	an instance.
     80       1.1   thorpej  */
     81       1.1   thorpej void
     82       1.2   thorpej _prop_object_init(struct _prop_object *po, const struct _prop_object_type *pot)
     83       1.1   thorpej {
     84       1.1   thorpej 
     85       1.2   thorpej 	po->po_type = pot;
     86       1.1   thorpej 	po->po_refcnt = 1;
     87       1.1   thorpej }
     88       1.1   thorpej 
     89       1.1   thorpej /*
     90       1.1   thorpej  * _prop_object_fini --
     91       1.1   thorpej  *	Finalize an object.  Called when sub-classes destroy
     92       1.1   thorpej  *	an instance.
     93       1.1   thorpej  */
     94       1.4   thorpej /*ARGSUSED*/
     95       1.1   thorpej void
     96       1.9   thorpej _prop_object_fini(struct _prop_object *po _PROP_ARG_UNUSED)
     97       1.1   thorpej {
     98       1.1   thorpej 	/* Nothing to do, currently. */
     99       1.1   thorpej }
    100       1.1   thorpej 
    101       1.1   thorpej /*
    102       1.1   thorpej  * prop_object_retain --
    103       1.1   thorpej  *	Increment the reference count on an object.
    104       1.1   thorpej  */
    105  1.35.8.1  perseant _PROP_EXPORT void
    106       1.1   thorpej prop_object_retain(prop_object_t obj)
    107       1.1   thorpej {
    108       1.1   thorpej 	struct _prop_object *po = obj;
    109      1.29    martin 	uint32_t ncnt __unused;
    110       1.1   thorpej 
    111      1.28     pooka 	_PROP_ATOMIC_INC32_NV(&po->po_refcnt, ncnt);
    112      1.24     pooka 	_PROP_ASSERT(ncnt != 0);
    113       1.1   thorpej }
    114       1.1   thorpej 
    115       1.1   thorpej /*
    116      1.15     joerg  * prop_object_release_emergency
    117      1.15     joerg  *	A direct free with prop_object_release failed.
    118      1.15     joerg  *	Walk down the tree until a leaf is found and
    119      1.15     joerg  *	free that. Do not recurse to avoid stack overflows.
    120      1.15     joerg  *
    121      1.15     joerg  *	This is a slow edge condition, but necessary to
    122      1.17   xtraeme  *	guarantee that an object can always be freed.
    123      1.15     joerg  */
    124      1.15     joerg static void
    125      1.15     joerg prop_object_release_emergency(prop_object_t obj)
    126      1.15     joerg {
    127      1.15     joerg 	struct _prop_object *po;
    128      1.23      haad 	void (*unlock)(void);
    129      1.15     joerg 	prop_object_t parent = NULL;
    130      1.15     joerg 	uint32_t ocnt;
    131      1.15     joerg 
    132      1.15     joerg 	for (;;) {
    133      1.15     joerg 		po = obj;
    134      1.15     joerg 		_PROP_ASSERT(obj);
    135      1.15     joerg 
    136      1.23      haad 		if (po->po_type->pot_lock != NULL)
    137      1.23      haad 		po->po_type->pot_lock();
    138      1.23      haad 
    139      1.23      haad 		/* Save pointerto unlock function */
    140      1.23      haad 		unlock = po->po_type->pot_unlock;
    141      1.32  riastrad 
    142      1.24     pooka 		/* Dance a bit to make sure we always get the non-racy ocnt */
    143      1.28     pooka 		_PROP_ATOMIC_DEC32_NV(&po->po_refcnt, ocnt);
    144      1.24     pooka 		ocnt++;
    145      1.24     pooka 		_PROP_ASSERT(ocnt != 0);
    146      1.15     joerg 
    147      1.23      haad 		if (ocnt != 1) {
    148      1.23      haad 			if (unlock != NULL)
    149      1.23      haad 				unlock();
    150      1.15     joerg 			break;
    151      1.23      haad 		}
    152      1.32  riastrad 
    153      1.32  riastrad 		_PROP_ASSERT(po->po_type);
    154      1.22   thorpej 		if ((po->po_type->pot_free)(NULL, &obj) ==
    155      1.23      haad 		    _PROP_OBJECT_FREE_DONE) {
    156      1.23      haad 			if (unlock != NULL)
    157      1.23      haad 				unlock();
    158      1.15     joerg 			break;
    159      1.23      haad 		}
    160      1.15     joerg 
    161      1.23      haad 		if (unlock != NULL)
    162      1.23      haad 			unlock();
    163      1.32  riastrad 
    164      1.15     joerg 		parent = po;
    165      1.28     pooka 		_PROP_ATOMIC_INC32(&po->po_refcnt);
    166      1.15     joerg 	}
    167      1.15     joerg 	_PROP_ASSERT(parent);
    168      1.15     joerg 	/* One object was just freed. */
    169      1.15     joerg 	po = parent;
    170      1.15     joerg 	(*po->po_type->pot_emergency_free)(parent);
    171      1.15     joerg }
    172      1.15     joerg 
    173      1.15     joerg /*
    174       1.1   thorpej  * prop_object_release --
    175       1.1   thorpej  *	Decrement the reference count on an object.
    176       1.1   thorpej  *
    177       1.1   thorpej  *	Free the object if we are releasing the final
    178       1.1   thorpej  *	reference.
    179       1.1   thorpej  */
    180  1.35.8.1  perseant _PROP_EXPORT void
    181       1.1   thorpej prop_object_release(prop_object_t obj)
    182       1.1   thorpej {
    183      1.15     joerg 	struct _prop_object *po;
    184      1.15     joerg 	struct _prop_stack stack;
    185      1.32  riastrad 	void (*unlock)(void);
    186      1.15     joerg 	int ret;
    187       1.1   thorpej 	uint32_t ocnt;
    188       1.1   thorpej 
    189      1.15     joerg 	_prop_stack_init(&stack);
    190       1.1   thorpej 
    191      1.15     joerg 	do {
    192      1.15     joerg 		do {
    193      1.15     joerg 			po = obj;
    194      1.15     joerg 			_PROP_ASSERT(obj);
    195      1.15     joerg 
    196      1.23      haad 			if (po->po_type->pot_lock != NULL)
    197      1.23      haad 				po->po_type->pot_lock();
    198      1.23      haad 
    199      1.23      haad 			/* Save pointer to object unlock function */
    200      1.23      haad 			unlock = po->po_type->pot_unlock;
    201      1.32  riastrad 
    202      1.28     pooka 			_PROP_ATOMIC_DEC32_NV(&po->po_refcnt, ocnt);
    203      1.24     pooka 			ocnt++;
    204      1.24     pooka 			_PROP_ASSERT(ocnt != 0);
    205      1.15     joerg 
    206      1.15     joerg 			if (ocnt != 1) {
    207      1.15     joerg 				ret = 0;
    208      1.23      haad 				if (unlock != NULL)
    209      1.23      haad 					unlock();
    210      1.15     joerg 				break;
    211      1.15     joerg 			}
    212      1.32  riastrad 
    213      1.23      haad 			ret = (po->po_type->pot_free)(&stack, &obj);
    214      1.15     joerg 
    215      1.23      haad 			if (unlock != NULL)
    216      1.23      haad 				unlock();
    217      1.15     joerg 
    218      1.15     joerg 			if (ret == _PROP_OBJECT_FREE_DONE)
    219      1.15     joerg 				break;
    220      1.32  riastrad 
    221      1.28     pooka 			_PROP_ATOMIC_INC32(&po->po_refcnt);
    222      1.15     joerg 		} while (ret == _PROP_OBJECT_FREE_RECURSE);
    223      1.15     joerg 		if (ret == _PROP_OBJECT_FREE_FAILED)
    224      1.15     joerg 			prop_object_release_emergency(obj);
    225      1.16     joerg 	} while (_prop_stack_pop(&stack, &obj, NULL, NULL, NULL));
    226       1.1   thorpej }
    227       1.1   thorpej 
    228       1.1   thorpej /*
    229       1.1   thorpej  * prop_object_type --
    230       1.1   thorpej  *	Return the type of an object.
    231       1.1   thorpej  */
    232  1.35.8.1  perseant _PROP_EXPORT prop_type_t
    233       1.1   thorpej prop_object_type(prop_object_t obj)
    234       1.1   thorpej {
    235       1.1   thorpej 	struct _prop_object *po = obj;
    236       1.1   thorpej 
    237       1.4   thorpej 	if (obj == NULL)
    238       1.4   thorpej 		return (PROP_TYPE_UNKNOWN);
    239       1.4   thorpej 
    240       1.2   thorpej 	return (po->po_type->pot_type);
    241       1.2   thorpej }
    242       1.2   thorpej 
    243       1.2   thorpej /*
    244       1.2   thorpej  * prop_object_equals --
    245      1.14   thorpej  *	Returns true if thw two objects are equivalent.
    246       1.2   thorpej  */
    247  1.35.8.1  perseant _PROP_EXPORT bool
    248       1.2   thorpej prop_object_equals(prop_object_t obj1, prop_object_t obj2)
    249       1.2   thorpej {
    250      1.16     joerg 	return (prop_object_equals_with_error(obj1, obj2, NULL));
    251      1.16     joerg }
    252      1.16     joerg 
    253  1.35.8.1  perseant _PROP_EXPORT bool
    254      1.16     joerg prop_object_equals_with_error(prop_object_t obj1, prop_object_t obj2,
    255      1.16     joerg     bool *error_flag)
    256      1.16     joerg {
    257      1.16     joerg 	struct _prop_object *po1;
    258      1.16     joerg 	struct _prop_object *po2;
    259      1.16     joerg 	void *stored_pointer1, *stored_pointer2;
    260      1.16     joerg 	prop_object_t next_obj1, next_obj2;
    261      1.16     joerg 	struct _prop_stack stack;
    262      1.22   thorpej 	_prop_object_equals_rv_t ret;
    263      1.16     joerg 
    264      1.16     joerg 	_prop_stack_init(&stack);
    265      1.16     joerg 	if (error_flag)
    266      1.16     joerg 		*error_flag = false;
    267      1.16     joerg 
    268      1.16     joerg  start_subtree:
    269      1.16     joerg 	stored_pointer1 = NULL;
    270      1.16     joerg 	stored_pointer2 = NULL;
    271      1.16     joerg 	po1 = obj1;
    272      1.16     joerg 	po2 = obj2;
    273       1.2   thorpej 
    274       1.2   thorpej 	if (po1->po_type != po2->po_type)
    275      1.14   thorpej 		return (false);
    276      1.32  riastrad 
    277      1.16     joerg  continue_subtree:
    278      1.22   thorpej 	ret = (*po1->po_type->pot_equals)(obj1, obj2,
    279      1.22   thorpej 					  &stored_pointer1, &stored_pointer2,
    280      1.22   thorpej 					  &next_obj1, &next_obj2);
    281      1.16     joerg 	if (ret == _PROP_OBJECT_EQUALS_FALSE)
    282      1.16     joerg 		goto finish;
    283      1.16     joerg 	if (ret == _PROP_OBJECT_EQUALS_TRUE) {
    284      1.16     joerg 		if (!_prop_stack_pop(&stack, &obj1, &obj2,
    285      1.16     joerg 				     &stored_pointer1, &stored_pointer2))
    286      1.16     joerg 			return true;
    287      1.27    martin 		po1 = obj1;
    288      1.27    martin 		po2 = obj2;
    289      1.16     joerg 		goto continue_subtree;
    290      1.16     joerg 	}
    291      1.16     joerg 	_PROP_ASSERT(ret == _PROP_OBJECT_EQUALS_RECURSE);
    292      1.16     joerg 
    293      1.16     joerg 	if (!_prop_stack_push(&stack, obj1, obj2,
    294      1.16     joerg 			      stored_pointer1, stored_pointer2)) {
    295      1.16     joerg 		if (error_flag)
    296      1.16     joerg 			*error_flag = true;
    297      1.16     joerg 		goto finish;
    298      1.16     joerg 	}
    299      1.16     joerg 	obj1 = next_obj1;
    300      1.16     joerg 	obj2 = next_obj2;
    301      1.16     joerg 	goto start_subtree;
    302      1.16     joerg 
    303      1.16     joerg finish:
    304      1.16     joerg 	while (_prop_stack_pop(&stack, &obj1, &obj2, NULL, NULL)) {
    305      1.16     joerg 		po1 = obj1;
    306      1.16     joerg 		(*po1->po_type->pot_equals_finish)(obj1, obj2);
    307      1.16     joerg 	}
    308      1.32  riastrad 	return (false);
    309       1.1   thorpej }
    310       1.1   thorpej 
    311       1.1   thorpej /*
    312       1.1   thorpej  * prop_object_iterator_next --
    313       1.1   thorpej  *	Return the next item during an iteration.
    314       1.1   thorpej  */
    315  1.35.8.1  perseant _PROP_EXPORT prop_object_t
    316       1.1   thorpej prop_object_iterator_next(prop_object_iterator_t pi)
    317       1.1   thorpej {
    318       1.1   thorpej 
    319       1.1   thorpej 	return ((*pi->pi_next_object)(pi));
    320       1.1   thorpej }
    321       1.1   thorpej 
    322       1.1   thorpej /*
    323       1.1   thorpej  * prop_object_iterator_reset --
    324       1.1   thorpej  *	Reset the iterator to the first object so as to restart
    325       1.1   thorpej  *	iteration.
    326       1.1   thorpej  */
    327  1.35.8.1  perseant _PROP_EXPORT void
    328       1.1   thorpej prop_object_iterator_reset(prop_object_iterator_t pi)
    329       1.1   thorpej {
    330       1.1   thorpej 
    331       1.1   thorpej 	(*pi->pi_reset)(pi);
    332       1.1   thorpej }
    333       1.1   thorpej 
    334       1.1   thorpej /*
    335       1.1   thorpej  * prop_object_iterator_release --
    336       1.1   thorpej  *	Release the object iterator.
    337       1.1   thorpej  */
    338  1.35.8.1  perseant _PROP_EXPORT void
    339       1.1   thorpej prop_object_iterator_release(prop_object_iterator_t pi)
    340       1.1   thorpej {
    341       1.1   thorpej 
    342       1.1   thorpej 	prop_object_release(pi->pi_obj);
    343       1.1   thorpej 	_PROP_FREE(pi, M_TEMP);
    344       1.1   thorpej }
    345