/*-
* Copyright (c) 2006, 2007, 2025 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* prop_object_release_emergency
* A direct free with prop_object_release failed.
* Walk down the tree until a leaf is found and
* free that. Do not recurse to avoid stack overflows.
*
* This is a slow edge condition, but necessary to
* guarantee that an object can always be freed.
*/
static void
prop_object_release_emergency(prop_object_t obj)
{
struct _prop_object *po;
void (*unlock)(void);
prop_object_t parent = NULL;
uint32_t ocnt;
for (;;) {
po = obj;
_PROP_ASSERT(obj);
if (po->po_type->pot_lock != NULL)
po->po_type->pot_lock();
/* Save pointerto unlock function */
unlock = po->po_type->pot_unlock;
/* Dance a bit to make sure we always get the non-racy ocnt */
_PROP_ATOMIC_DEC32_NV(&po->po_refcnt, ocnt);
ocnt++;
_PROP_ASSERT(ocnt != 0);
if (ocnt != 1) {
if (unlock != NULL)
unlock();
break;
}
_PROP_ASSERT(po->po_type);
if ((po->po_type->pot_free)(NULL, &obj) ==
_PROP_OBJECT_FREE_DONE) {
if (unlock != NULL)
unlock();
break;
}
if (unlock != NULL)
unlock();
parent = po;
_PROP_ATOMIC_INC32(&po->po_refcnt);
}
_PROP_ASSERT(parent);
/* One object was just freed. */
po = parent;
(*po->po_type->pot_emergency_free)(parent);
}
/*
* prop_object_release --
* Decrement the reference count on an object.
*
* Free the object if we are releasing the final
* reference.
*/
_PROP_EXPORT void
prop_object_release(prop_object_t obj)
{
struct _prop_object *po;
struct _prop_stack stack;
void (*unlock)(void);
int ret;
uint32_t ocnt;
_prop_stack_init(&stack);
do {
do {
po = obj;
_PROP_ASSERT(obj);
if (po->po_type->pot_lock != NULL)
po->po_type->pot_lock();
/* Save pointer to object unlock function */
unlock = po->po_type->pot_unlock;
/*
* prop_object_iterator_next --
* Return the next item during an iteration.
*/
_PROP_EXPORT prop_object_t
prop_object_iterator_next(prop_object_iterator_t pi)
{
return ((*pi->pi_next_object)(pi));
}
/*
* prop_object_iterator_reset --
* Reset the iterator to the first object so as to restart
* iteration.
*/
_PROP_EXPORT void
prop_object_iterator_reset(prop_object_iterator_t pi)
{