1 1.42 thorpej /* $NetBSD: prop_object.c,v 1.42 2025/05/14 03:25:46 thorpej Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /*- 4 1.36 thorpej * 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.39 thorpej _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.39 thorpej _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.39 thorpej _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.39 thorpej _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.39 thorpej _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.39 thorpej _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.39 thorpej _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.39 thorpej _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