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