1*ae771770SStanislav Sedov /* 2*ae771770SStanislav Sedov * Copyright (c) 2010 Kungliga Tekniska Högskolan 3*ae771770SStanislav Sedov * (Royal Institute of Technology, Stockholm, Sweden). 4*ae771770SStanislav Sedov * All rights reserved. 5*ae771770SStanislav Sedov * 6*ae771770SStanislav Sedov * Portions Copyright (c) 2010 Apple Inc. All rights reserved. 7*ae771770SStanislav Sedov * 8*ae771770SStanislav Sedov * Redistribution and use in source and binary forms, with or without 9*ae771770SStanislav Sedov * modification, are permitted provided that the following conditions 10*ae771770SStanislav Sedov * are met: 11*ae771770SStanislav Sedov * 12*ae771770SStanislav Sedov * 1. Redistributions of source code must retain the above copyright 13*ae771770SStanislav Sedov * notice, this list of conditions and the following disclaimer. 14*ae771770SStanislav Sedov * 15*ae771770SStanislav Sedov * 2. Redistributions in binary form must reproduce the above copyright 16*ae771770SStanislav Sedov * notice, this list of conditions and the following disclaimer in the 17*ae771770SStanislav Sedov * documentation and/or other materials provided with the distribution. 18*ae771770SStanislav Sedov * 19*ae771770SStanislav Sedov * 3. Neither the name of the Institute nor the names of its contributors 20*ae771770SStanislav Sedov * may be used to endorse or promote products derived from this software 21*ae771770SStanislav Sedov * without specific prior written permission. 22*ae771770SStanislav Sedov * 23*ae771770SStanislav Sedov * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24*ae771770SStanislav Sedov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25*ae771770SStanislav Sedov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26*ae771770SStanislav Sedov * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27*ae771770SStanislav Sedov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28*ae771770SStanislav Sedov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29*ae771770SStanislav Sedov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30*ae771770SStanislav Sedov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31*ae771770SStanislav Sedov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32*ae771770SStanislav Sedov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33*ae771770SStanislav Sedov * SUCH DAMAGE. 34*ae771770SStanislav Sedov */ 35*ae771770SStanislav Sedov 36*ae771770SStanislav Sedov #include "baselocl.h" 37*ae771770SStanislav Sedov #include <syslog.h> 38*ae771770SStanislav Sedov 39*ae771770SStanislav Sedov static heim_base_atomic_type tidglobal = HEIM_TID_USER; 40*ae771770SStanislav Sedov 41*ae771770SStanislav Sedov struct heim_base { 42*ae771770SStanislav Sedov heim_type_t isa; 43*ae771770SStanislav Sedov heim_base_atomic_type ref_cnt; 44*ae771770SStanislav Sedov HEIM_TAILQ_ENTRY(heim_base) autorel; 45*ae771770SStanislav Sedov heim_auto_release_t autorelpool; 46*ae771770SStanislav Sedov uintptr_t isaextra[3]; 47*ae771770SStanislav Sedov }; 48*ae771770SStanislav Sedov 49*ae771770SStanislav Sedov /* specialized version of base */ 50*ae771770SStanislav Sedov struct heim_base_mem { 51*ae771770SStanislav Sedov heim_type_t isa; 52*ae771770SStanislav Sedov heim_base_atomic_type ref_cnt; 53*ae771770SStanislav Sedov HEIM_TAILQ_ENTRY(heim_base) autorel; 54*ae771770SStanislav Sedov heim_auto_release_t autorelpool; 55*ae771770SStanislav Sedov const char *name; 56*ae771770SStanislav Sedov void (*dealloc)(void *); 57*ae771770SStanislav Sedov uintptr_t isaextra[1]; 58*ae771770SStanislav Sedov }; 59*ae771770SStanislav Sedov 60*ae771770SStanislav Sedov #define PTR2BASE(ptr) (((struct heim_base *)ptr) - 1) 61*ae771770SStanislav Sedov #define BASE2PTR(ptr) ((void *)(((struct heim_base *)ptr) + 1)) 62*ae771770SStanislav Sedov 63*ae771770SStanislav Sedov #ifdef HEIM_BASE_NEED_ATOMIC_MUTEX 64*ae771770SStanislav Sedov HEIMDAL_MUTEX _heim_base_mutex = HEIMDAL_MUTEX_INITIALIZER; 65*ae771770SStanislav Sedov #endif 66*ae771770SStanislav Sedov 67*ae771770SStanislav Sedov /* 68*ae771770SStanislav Sedov * Auto release structure 69*ae771770SStanislav Sedov */ 70*ae771770SStanislav Sedov 71*ae771770SStanislav Sedov struct heim_auto_release { 72*ae771770SStanislav Sedov HEIM_TAILQ_HEAD(, heim_base) pool; 73*ae771770SStanislav Sedov HEIMDAL_MUTEX pool_mutex; 74*ae771770SStanislav Sedov struct heim_auto_release *parent; 75*ae771770SStanislav Sedov }; 76*ae771770SStanislav Sedov 77*ae771770SStanislav Sedov 78*ae771770SStanislav Sedov /** 79*ae771770SStanislav Sedov * Retain object 80*ae771770SStanislav Sedov * 81*ae771770SStanislav Sedov * @param object to be released, NULL is ok 82*ae771770SStanislav Sedov * 83*ae771770SStanislav Sedov * @return the same object as passed in 84*ae771770SStanislav Sedov */ 85*ae771770SStanislav Sedov 86*ae771770SStanislav Sedov void * 87*ae771770SStanislav Sedov heim_retain(void *ptr) 88*ae771770SStanislav Sedov { 89*ae771770SStanislav Sedov struct heim_base *p = PTR2BASE(ptr); 90*ae771770SStanislav Sedov 91*ae771770SStanislav Sedov if (ptr == NULL || heim_base_is_tagged(ptr)) 92*ae771770SStanislav Sedov return ptr; 93*ae771770SStanislav Sedov 94*ae771770SStanislav Sedov if (p->ref_cnt == heim_base_atomic_max) 95*ae771770SStanislav Sedov return ptr; 96*ae771770SStanislav Sedov 97*ae771770SStanislav Sedov if ((heim_base_atomic_inc(&p->ref_cnt) - 1) == 0) 98*ae771770SStanislav Sedov heim_abort("resurection"); 99*ae771770SStanislav Sedov return ptr; 100*ae771770SStanislav Sedov } 101*ae771770SStanislav Sedov 102*ae771770SStanislav Sedov /** 103*ae771770SStanislav Sedov * Release object, free is reference count reaches zero 104*ae771770SStanislav Sedov * 105*ae771770SStanislav Sedov * @param object to be released 106*ae771770SStanislav Sedov */ 107*ae771770SStanislav Sedov 108*ae771770SStanislav Sedov void 109*ae771770SStanislav Sedov heim_release(void *ptr) 110*ae771770SStanislav Sedov { 111*ae771770SStanislav Sedov heim_base_atomic_type old; 112*ae771770SStanislav Sedov struct heim_base *p = PTR2BASE(ptr); 113*ae771770SStanislav Sedov 114*ae771770SStanislav Sedov if (ptr == NULL || heim_base_is_tagged(ptr)) 115*ae771770SStanislav Sedov return; 116*ae771770SStanislav Sedov 117*ae771770SStanislav Sedov if (p->ref_cnt == heim_base_atomic_max) 118*ae771770SStanislav Sedov return; 119*ae771770SStanislav Sedov 120*ae771770SStanislav Sedov old = heim_base_atomic_dec(&p->ref_cnt) + 1; 121*ae771770SStanislav Sedov 122*ae771770SStanislav Sedov if (old > 1) 123*ae771770SStanislav Sedov return; 124*ae771770SStanislav Sedov 125*ae771770SStanislav Sedov if (old == 1) { 126*ae771770SStanislav Sedov heim_auto_release_t ar = p->autorelpool; 127*ae771770SStanislav Sedov /* remove from autorel pool list */ 128*ae771770SStanislav Sedov if (ar) { 129*ae771770SStanislav Sedov p->autorelpool = NULL; 130*ae771770SStanislav Sedov HEIMDAL_MUTEX_lock(&ar->pool_mutex); 131*ae771770SStanislav Sedov HEIM_TAILQ_REMOVE(&ar->pool, p, autorel); 132*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&ar->pool_mutex); 133*ae771770SStanislav Sedov } 134*ae771770SStanislav Sedov if (p->isa->dealloc) 135*ae771770SStanislav Sedov p->isa->dealloc(ptr); 136*ae771770SStanislav Sedov free(p); 137*ae771770SStanislav Sedov } else 138*ae771770SStanislav Sedov heim_abort("over release"); 139*ae771770SStanislav Sedov } 140*ae771770SStanislav Sedov 141*ae771770SStanislav Sedov static heim_type_t tagged_isa[9] = { 142*ae771770SStanislav Sedov &_heim_number_object, 143*ae771770SStanislav Sedov &_heim_null_object, 144*ae771770SStanislav Sedov &_heim_bool_object, 145*ae771770SStanislav Sedov 146*ae771770SStanislav Sedov NULL, 147*ae771770SStanislav Sedov NULL, 148*ae771770SStanislav Sedov NULL, 149*ae771770SStanislav Sedov 150*ae771770SStanislav Sedov NULL, 151*ae771770SStanislav Sedov NULL, 152*ae771770SStanislav Sedov NULL 153*ae771770SStanislav Sedov }; 154*ae771770SStanislav Sedov 155*ae771770SStanislav Sedov heim_type_t 156*ae771770SStanislav Sedov _heim_get_isa(heim_object_t ptr) 157*ae771770SStanislav Sedov { 158*ae771770SStanislav Sedov struct heim_base *p; 159*ae771770SStanislav Sedov if (heim_base_is_tagged(ptr)) { 160*ae771770SStanislav Sedov if (heim_base_is_tagged_object(ptr)) 161*ae771770SStanislav Sedov return tagged_isa[heim_base_tagged_object_tid(ptr)]; 162*ae771770SStanislav Sedov heim_abort("not a supported tagged type"); 163*ae771770SStanislav Sedov } 164*ae771770SStanislav Sedov p = PTR2BASE(ptr); 165*ae771770SStanislav Sedov return p->isa; 166*ae771770SStanislav Sedov } 167*ae771770SStanislav Sedov 168*ae771770SStanislav Sedov /** 169*ae771770SStanislav Sedov * Get type ID of object 170*ae771770SStanislav Sedov * 171*ae771770SStanislav Sedov * @param object object to get type id of 172*ae771770SStanislav Sedov * 173*ae771770SStanislav Sedov * @return type id of object 174*ae771770SStanislav Sedov */ 175*ae771770SStanislav Sedov 176*ae771770SStanislav Sedov heim_tid_t 177*ae771770SStanislav Sedov heim_get_tid(heim_object_t ptr) 178*ae771770SStanislav Sedov { 179*ae771770SStanislav Sedov heim_type_t isa = _heim_get_isa(ptr); 180*ae771770SStanislav Sedov return isa->tid; 181*ae771770SStanislav Sedov } 182*ae771770SStanislav Sedov 183*ae771770SStanislav Sedov /** 184*ae771770SStanislav Sedov * Get hash value of object 185*ae771770SStanislav Sedov * 186*ae771770SStanislav Sedov * @param object object to get hash value for 187*ae771770SStanislav Sedov * 188*ae771770SStanislav Sedov * @return a hash value 189*ae771770SStanislav Sedov */ 190*ae771770SStanislav Sedov 191*ae771770SStanislav Sedov unsigned long 192*ae771770SStanislav Sedov heim_get_hash(heim_object_t ptr) 193*ae771770SStanislav Sedov { 194*ae771770SStanislav Sedov heim_type_t isa = _heim_get_isa(ptr); 195*ae771770SStanislav Sedov if (isa->hash) 196*ae771770SStanislav Sedov return isa->hash(ptr); 197*ae771770SStanislav Sedov return (unsigned long)ptr; 198*ae771770SStanislav Sedov } 199*ae771770SStanislav Sedov 200*ae771770SStanislav Sedov /** 201*ae771770SStanislav Sedov * Compare two objects, returns 0 if equal, can use used for qsort() 202*ae771770SStanislav Sedov * and friends. 203*ae771770SStanislav Sedov * 204*ae771770SStanislav Sedov * @param a first object to compare 205*ae771770SStanislav Sedov * @param b first object to compare 206*ae771770SStanislav Sedov * 207*ae771770SStanislav Sedov * @return 0 if objects are equal 208*ae771770SStanislav Sedov */ 209*ae771770SStanislav Sedov 210*ae771770SStanislav Sedov int 211*ae771770SStanislav Sedov heim_cmp(heim_object_t a, heim_object_t b) 212*ae771770SStanislav Sedov { 213*ae771770SStanislav Sedov heim_tid_t ta, tb; 214*ae771770SStanislav Sedov heim_type_t isa; 215*ae771770SStanislav Sedov 216*ae771770SStanislav Sedov ta = heim_get_tid(a); 217*ae771770SStanislav Sedov tb = heim_get_tid(b); 218*ae771770SStanislav Sedov 219*ae771770SStanislav Sedov if (ta != tb) 220*ae771770SStanislav Sedov return ta - tb; 221*ae771770SStanislav Sedov 222*ae771770SStanislav Sedov isa = _heim_get_isa(a); 223*ae771770SStanislav Sedov 224*ae771770SStanislav Sedov if (isa->cmp) 225*ae771770SStanislav Sedov return isa->cmp(a, b); 226*ae771770SStanislav Sedov 227*ae771770SStanislav Sedov return (uintptr_t)a - (uintptr_t)b; 228*ae771770SStanislav Sedov } 229*ae771770SStanislav Sedov 230*ae771770SStanislav Sedov /* 231*ae771770SStanislav Sedov * Private - allocates an memory object 232*ae771770SStanislav Sedov */ 233*ae771770SStanislav Sedov 234*ae771770SStanislav Sedov static void 235*ae771770SStanislav Sedov memory_dealloc(void *ptr) 236*ae771770SStanislav Sedov { 237*ae771770SStanislav Sedov struct heim_base_mem *p = (struct heim_base_mem *)PTR2BASE(ptr); 238*ae771770SStanislav Sedov if (p->dealloc) 239*ae771770SStanislav Sedov p->dealloc(ptr); 240*ae771770SStanislav Sedov } 241*ae771770SStanislav Sedov 242*ae771770SStanislav Sedov struct heim_type_data memory_object = { 243*ae771770SStanislav Sedov HEIM_TID_MEMORY, 244*ae771770SStanislav Sedov "memory-object", 245*ae771770SStanislav Sedov NULL, 246*ae771770SStanislav Sedov memory_dealloc, 247*ae771770SStanislav Sedov NULL, 248*ae771770SStanislav Sedov NULL, 249*ae771770SStanislav Sedov NULL 250*ae771770SStanislav Sedov }; 251*ae771770SStanislav Sedov 252*ae771770SStanislav Sedov void * 253*ae771770SStanislav Sedov heim_alloc(size_t size, const char *name, heim_type_dealloc dealloc) 254*ae771770SStanislav Sedov { 255*ae771770SStanislav Sedov /* XXX use posix_memalign */ 256*ae771770SStanislav Sedov 257*ae771770SStanislav Sedov struct heim_base_mem *p = calloc(1, size + sizeof(*p)); 258*ae771770SStanislav Sedov if (p == NULL) 259*ae771770SStanislav Sedov return NULL; 260*ae771770SStanislav Sedov p->isa = &memory_object; 261*ae771770SStanislav Sedov p->ref_cnt = 1; 262*ae771770SStanislav Sedov p->name = name; 263*ae771770SStanislav Sedov p->dealloc = dealloc; 264*ae771770SStanislav Sedov return BASE2PTR(p); 265*ae771770SStanislav Sedov } 266*ae771770SStanislav Sedov 267*ae771770SStanislav Sedov heim_type_t 268*ae771770SStanislav Sedov _heim_create_type(const char *name, 269*ae771770SStanislav Sedov heim_type_init init, 270*ae771770SStanislav Sedov heim_type_dealloc dealloc, 271*ae771770SStanislav Sedov heim_type_copy copy, 272*ae771770SStanislav Sedov heim_type_cmp cmp, 273*ae771770SStanislav Sedov heim_type_hash hash) 274*ae771770SStanislav Sedov { 275*ae771770SStanislav Sedov heim_type_t type; 276*ae771770SStanislav Sedov 277*ae771770SStanislav Sedov type = calloc(1, sizeof(*type)); 278*ae771770SStanislav Sedov if (type == NULL) 279*ae771770SStanislav Sedov return NULL; 280*ae771770SStanislav Sedov 281*ae771770SStanislav Sedov type->tid = heim_base_atomic_inc(&tidglobal); 282*ae771770SStanislav Sedov type->name = name; 283*ae771770SStanislav Sedov type->init = init; 284*ae771770SStanislav Sedov type->dealloc = dealloc; 285*ae771770SStanislav Sedov type->copy = copy; 286*ae771770SStanislav Sedov type->cmp = cmp; 287*ae771770SStanislav Sedov type->hash = hash; 288*ae771770SStanislav Sedov 289*ae771770SStanislav Sedov return type; 290*ae771770SStanislav Sedov } 291*ae771770SStanislav Sedov 292*ae771770SStanislav Sedov heim_object_t 293*ae771770SStanislav Sedov _heim_alloc_object(heim_type_t type, size_t size) 294*ae771770SStanislav Sedov { 295*ae771770SStanislav Sedov /* XXX should use posix_memalign */ 296*ae771770SStanislav Sedov struct heim_base *p = calloc(1, size + sizeof(*p)); 297*ae771770SStanislav Sedov if (p == NULL) 298*ae771770SStanislav Sedov return NULL; 299*ae771770SStanislav Sedov p->isa = type; 300*ae771770SStanislav Sedov p->ref_cnt = 1; 301*ae771770SStanislav Sedov 302*ae771770SStanislav Sedov return BASE2PTR(p); 303*ae771770SStanislav Sedov } 304*ae771770SStanislav Sedov 305*ae771770SStanislav Sedov heim_tid_t 306*ae771770SStanislav Sedov _heim_type_get_tid(heim_type_t type) 307*ae771770SStanislav Sedov { 308*ae771770SStanislav Sedov return type->tid; 309*ae771770SStanislav Sedov } 310*ae771770SStanislav Sedov 311*ae771770SStanislav Sedov /** 312*ae771770SStanislav Sedov * Call func once and only once 313*ae771770SStanislav Sedov * 314*ae771770SStanislav Sedov * @param once pointer to a heim_base_once_t 315*ae771770SStanislav Sedov * @param ctx context passed to func 316*ae771770SStanislav Sedov * @param func function to be called 317*ae771770SStanislav Sedov */ 318*ae771770SStanislav Sedov 319*ae771770SStanislav Sedov void 320*ae771770SStanislav Sedov heim_base_once_f(heim_base_once_t *once, void *ctx, void (*func)(void *)) 321*ae771770SStanislav Sedov { 322*ae771770SStanislav Sedov #ifdef HAVE_DISPATCH_DISPATCH_H 323*ae771770SStanislav Sedov dispatch_once_f(once, ctx, func); 324*ae771770SStanislav Sedov #else 325*ae771770SStanislav Sedov static HEIMDAL_MUTEX mutex = HEIMDAL_MUTEX_INITIALIZER; 326*ae771770SStanislav Sedov HEIMDAL_MUTEX_lock(&mutex); 327*ae771770SStanislav Sedov if (*once == 0) { 328*ae771770SStanislav Sedov *once = 1; 329*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&mutex); 330*ae771770SStanislav Sedov func(ctx); 331*ae771770SStanislav Sedov HEIMDAL_MUTEX_lock(&mutex); 332*ae771770SStanislav Sedov *once = 2; 333*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&mutex); 334*ae771770SStanislav Sedov } else if (*once == 2) { 335*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&mutex); 336*ae771770SStanislav Sedov } else { 337*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&mutex); 338*ae771770SStanislav Sedov while (1) { 339*ae771770SStanislav Sedov struct timeval tv = { 0, 1000 }; 340*ae771770SStanislav Sedov select(0, NULL, NULL, NULL, &tv); 341*ae771770SStanislav Sedov HEIMDAL_MUTEX_lock(&mutex); 342*ae771770SStanislav Sedov if (*once == 2) 343*ae771770SStanislav Sedov break; 344*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&mutex); 345*ae771770SStanislav Sedov } 346*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&mutex); 347*ae771770SStanislav Sedov } 348*ae771770SStanislav Sedov #endif 349*ae771770SStanislav Sedov } 350*ae771770SStanislav Sedov 351*ae771770SStanislav Sedov /** 352*ae771770SStanislav Sedov * Abort and log the failure (using syslog) 353*ae771770SStanislav Sedov */ 354*ae771770SStanislav Sedov 355*ae771770SStanislav Sedov void 356*ae771770SStanislav Sedov heim_abort(const char *fmt, ...) 357*ae771770SStanislav Sedov { 358*ae771770SStanislav Sedov va_list ap; 359*ae771770SStanislav Sedov va_start(ap, fmt); 360*ae771770SStanislav Sedov heim_abortv(fmt, ap); 361*ae771770SStanislav Sedov va_end(ap); 362*ae771770SStanislav Sedov } 363*ae771770SStanislav Sedov 364*ae771770SStanislav Sedov /** 365*ae771770SStanislav Sedov * Abort and log the failure (using syslog) 366*ae771770SStanislav Sedov */ 367*ae771770SStanislav Sedov 368*ae771770SStanislav Sedov void 369*ae771770SStanislav Sedov heim_abortv(const char *fmt, va_list ap) 370*ae771770SStanislav Sedov { 371*ae771770SStanislav Sedov static char str[1024]; 372*ae771770SStanislav Sedov 373*ae771770SStanislav Sedov vsnprintf(str, sizeof(str), fmt, ap); 374*ae771770SStanislav Sedov syslog(LOG_ERR, "heim_abort: %s", str); 375*ae771770SStanislav Sedov abort(); 376*ae771770SStanislav Sedov } 377*ae771770SStanislav Sedov 378*ae771770SStanislav Sedov /* 379*ae771770SStanislav Sedov * 380*ae771770SStanislav Sedov */ 381*ae771770SStanislav Sedov 382*ae771770SStanislav Sedov static int ar_created = 0; 383*ae771770SStanislav Sedov static HEIMDAL_thread_key ar_key; 384*ae771770SStanislav Sedov 385*ae771770SStanislav Sedov struct ar_tls { 386*ae771770SStanislav Sedov struct heim_auto_release *head; 387*ae771770SStanislav Sedov struct heim_auto_release *current; 388*ae771770SStanislav Sedov HEIMDAL_MUTEX tls_mutex; 389*ae771770SStanislav Sedov }; 390*ae771770SStanislav Sedov 391*ae771770SStanislav Sedov static void 392*ae771770SStanislav Sedov ar_tls_delete(void *ptr) 393*ae771770SStanislav Sedov { 394*ae771770SStanislav Sedov struct ar_tls *tls = ptr; 395*ae771770SStanislav Sedov if (tls->head) 396*ae771770SStanislav Sedov heim_release(tls->head); 397*ae771770SStanislav Sedov free(tls); 398*ae771770SStanislav Sedov } 399*ae771770SStanislav Sedov 400*ae771770SStanislav Sedov static void 401*ae771770SStanislav Sedov init_ar_tls(void *ptr) 402*ae771770SStanislav Sedov { 403*ae771770SStanislav Sedov int ret; 404*ae771770SStanislav Sedov HEIMDAL_key_create(&ar_key, ar_tls_delete, ret); 405*ae771770SStanislav Sedov if (ret == 0) 406*ae771770SStanislav Sedov ar_created = 1; 407*ae771770SStanislav Sedov } 408*ae771770SStanislav Sedov 409*ae771770SStanislav Sedov static struct ar_tls * 410*ae771770SStanislav Sedov autorel_tls(void) 411*ae771770SStanislav Sedov { 412*ae771770SStanislav Sedov static heim_base_once_t once = HEIM_BASE_ONCE_INIT; 413*ae771770SStanislav Sedov struct ar_tls *arp; 414*ae771770SStanislav Sedov int ret; 415*ae771770SStanislav Sedov 416*ae771770SStanislav Sedov heim_base_once_f(&once, NULL, init_ar_tls); 417*ae771770SStanislav Sedov if (!ar_created) 418*ae771770SStanislav Sedov return NULL; 419*ae771770SStanislav Sedov 420*ae771770SStanislav Sedov arp = HEIMDAL_getspecific(ar_key); 421*ae771770SStanislav Sedov if (arp == NULL) { 422*ae771770SStanislav Sedov 423*ae771770SStanislav Sedov arp = calloc(1, sizeof(*arp)); 424*ae771770SStanislav Sedov if (arp == NULL) 425*ae771770SStanislav Sedov return NULL; 426*ae771770SStanislav Sedov HEIMDAL_setspecific(ar_key, arp, ret); 427*ae771770SStanislav Sedov if (ret) { 428*ae771770SStanislav Sedov free(arp); 429*ae771770SStanislav Sedov return NULL; 430*ae771770SStanislav Sedov } 431*ae771770SStanislav Sedov } 432*ae771770SStanislav Sedov return arp; 433*ae771770SStanislav Sedov 434*ae771770SStanislav Sedov } 435*ae771770SStanislav Sedov 436*ae771770SStanislav Sedov static void 437*ae771770SStanislav Sedov autorel_dealloc(void *ptr) 438*ae771770SStanislav Sedov { 439*ae771770SStanislav Sedov heim_auto_release_t ar = ptr; 440*ae771770SStanislav Sedov struct ar_tls *tls; 441*ae771770SStanislav Sedov 442*ae771770SStanislav Sedov tls = autorel_tls(); 443*ae771770SStanislav Sedov if (tls == NULL) 444*ae771770SStanislav Sedov heim_abort("autorelease pool released on thread w/o autorelease inited"); 445*ae771770SStanislav Sedov 446*ae771770SStanislav Sedov heim_auto_release_drain(ar); 447*ae771770SStanislav Sedov 448*ae771770SStanislav Sedov if (!HEIM_TAILQ_EMPTY(&ar->pool)) 449*ae771770SStanislav Sedov heim_abort("pool not empty after draining"); 450*ae771770SStanislav Sedov 451*ae771770SStanislav Sedov HEIMDAL_MUTEX_lock(&tls->tls_mutex); 452*ae771770SStanislav Sedov if (tls->current != ptr) 453*ae771770SStanislav Sedov heim_abort("autorelease not releaseing top pool"); 454*ae771770SStanislav Sedov 455*ae771770SStanislav Sedov if (tls->current != tls->head) 456*ae771770SStanislav Sedov tls->current = ar->parent; 457*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&tls->tls_mutex); 458*ae771770SStanislav Sedov } 459*ae771770SStanislav Sedov 460*ae771770SStanislav Sedov static int 461*ae771770SStanislav Sedov autorel_cmp(void *a, void *b) 462*ae771770SStanislav Sedov { 463*ae771770SStanislav Sedov return (a == b); 464*ae771770SStanislav Sedov } 465*ae771770SStanislav Sedov 466*ae771770SStanislav Sedov static unsigned long 467*ae771770SStanislav Sedov autorel_hash(void *ptr) 468*ae771770SStanislav Sedov { 469*ae771770SStanislav Sedov return (unsigned long)ptr; 470*ae771770SStanislav Sedov } 471*ae771770SStanislav Sedov 472*ae771770SStanislav Sedov 473*ae771770SStanislav Sedov static struct heim_type_data _heim_autorel_object = { 474*ae771770SStanislav Sedov HEIM_TID_AUTORELEASE, 475*ae771770SStanislav Sedov "autorelease-pool", 476*ae771770SStanislav Sedov NULL, 477*ae771770SStanislav Sedov autorel_dealloc, 478*ae771770SStanislav Sedov NULL, 479*ae771770SStanislav Sedov autorel_cmp, 480*ae771770SStanislav Sedov autorel_hash 481*ae771770SStanislav Sedov }; 482*ae771770SStanislav Sedov 483*ae771770SStanislav Sedov /** 484*ae771770SStanislav Sedov * 485*ae771770SStanislav Sedov */ 486*ae771770SStanislav Sedov 487*ae771770SStanislav Sedov heim_auto_release_t 488*ae771770SStanislav Sedov heim_auto_release_create(void) 489*ae771770SStanislav Sedov { 490*ae771770SStanislav Sedov struct ar_tls *tls = autorel_tls(); 491*ae771770SStanislav Sedov heim_auto_release_t ar; 492*ae771770SStanislav Sedov 493*ae771770SStanislav Sedov if (tls == NULL) 494*ae771770SStanislav Sedov heim_abort("Failed to create/get autorelease head"); 495*ae771770SStanislav Sedov 496*ae771770SStanislav Sedov ar = _heim_alloc_object(&_heim_autorel_object, sizeof(struct heim_auto_release)); 497*ae771770SStanislav Sedov if (ar) { 498*ae771770SStanislav Sedov HEIMDAL_MUTEX_lock(&tls->tls_mutex); 499*ae771770SStanislav Sedov if (tls->head == NULL) 500*ae771770SStanislav Sedov tls->head = ar; 501*ae771770SStanislav Sedov ar->parent = tls->current; 502*ae771770SStanislav Sedov tls->current = ar; 503*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&tls->tls_mutex); 504*ae771770SStanislav Sedov } 505*ae771770SStanislav Sedov 506*ae771770SStanislav Sedov return ar; 507*ae771770SStanislav Sedov } 508*ae771770SStanislav Sedov 509*ae771770SStanislav Sedov /** 510*ae771770SStanislav Sedov * Mark the current object as a 511*ae771770SStanislav Sedov */ 512*ae771770SStanislav Sedov 513*ae771770SStanislav Sedov void 514*ae771770SStanislav Sedov heim_auto_release(heim_object_t ptr) 515*ae771770SStanislav Sedov { 516*ae771770SStanislav Sedov struct heim_base *p = PTR2BASE(ptr); 517*ae771770SStanislav Sedov struct ar_tls *tls = autorel_tls(); 518*ae771770SStanislav Sedov heim_auto_release_t ar; 519*ae771770SStanislav Sedov 520*ae771770SStanislav Sedov if (ptr == NULL || heim_base_is_tagged(ptr)) 521*ae771770SStanislav Sedov return; 522*ae771770SStanislav Sedov 523*ae771770SStanislav Sedov /* drop from old pool */ 524*ae771770SStanislav Sedov if ((ar = p->autorelpool) != NULL) { 525*ae771770SStanislav Sedov HEIMDAL_MUTEX_lock(&ar->pool_mutex); 526*ae771770SStanislav Sedov HEIM_TAILQ_REMOVE(&ar->pool, p, autorel); 527*ae771770SStanislav Sedov p->autorelpool = NULL; 528*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&ar->pool_mutex); 529*ae771770SStanislav Sedov } 530*ae771770SStanislav Sedov 531*ae771770SStanislav Sedov if (tls == NULL || (ar = tls->current) == NULL) 532*ae771770SStanislav Sedov heim_abort("no auto relase pool in place, would leak"); 533*ae771770SStanislav Sedov 534*ae771770SStanislav Sedov HEIMDAL_MUTEX_lock(&ar->pool_mutex); 535*ae771770SStanislav Sedov HEIM_TAILQ_INSERT_HEAD(&ar->pool, p, autorel); 536*ae771770SStanislav Sedov p->autorelpool = ar; 537*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&ar->pool_mutex); 538*ae771770SStanislav Sedov } 539*ae771770SStanislav Sedov 540*ae771770SStanislav Sedov /** 541*ae771770SStanislav Sedov * 542*ae771770SStanislav Sedov */ 543*ae771770SStanislav Sedov 544*ae771770SStanislav Sedov void 545*ae771770SStanislav Sedov heim_auto_release_drain(heim_auto_release_t autorel) 546*ae771770SStanislav Sedov { 547*ae771770SStanislav Sedov heim_object_t obj; 548*ae771770SStanislav Sedov 549*ae771770SStanislav Sedov /* release all elements on the tail queue */ 550*ae771770SStanislav Sedov 551*ae771770SStanislav Sedov HEIMDAL_MUTEX_lock(&autorel->pool_mutex); 552*ae771770SStanislav Sedov while(!HEIM_TAILQ_EMPTY(&autorel->pool)) { 553*ae771770SStanislav Sedov obj = HEIM_TAILQ_FIRST(&autorel->pool); 554*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&autorel->pool_mutex); 555*ae771770SStanislav Sedov heim_release(BASE2PTR(obj)); 556*ae771770SStanislav Sedov HEIMDAL_MUTEX_lock(&autorel->pool_mutex); 557*ae771770SStanislav Sedov } 558*ae771770SStanislav Sedov HEIMDAL_MUTEX_unlock(&autorel->pool_mutex); 559*ae771770SStanislav Sedov } 560