From b0c19f1a2d54cc46ff3027ec9e51948760d9618e Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 26 Oct 2010 23:41:32 -0700 Subject: [PATCH] more use bits --- base/array.c | 47 +++++++++- base/baselocl.h | 14 ++- base/heimbase.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++-- base/heimbase.h | 30 +++++++ base/heimbasepriv.h | 1 + base/string.c | 10 ++- base/test_base.c | 36 +++++++- 7 files changed, 373 insertions(+), 18 deletions(-) diff --git a/base/array.c b/base/array.c index 0a2d8b857..3db4dc794 100644 --- a/base/array.c +++ b/base/array.c @@ -181,6 +181,51 @@ heim_object_t heim_array_copy_value(heim_array_t array, size_t idx) { if (idx >= array->len) - HEIM_BASE_ABORT("index too large"); + heim_abort("index too large"); return heim_retain(array->val[idx]); } + +/** + * Delete value at idx + * + * @param array the array to modify + * @param idx the key to delete + */ + +void +heim_array_delete_value(heim_array_t array, size_t idx) +{ + heim_object_t obj; + if (idx >= array->len) + heim_abort("index too large"); + obj = array->val[idx]; + + array->len--; + + if (idx < array->len) + memmove(&array->val[idx], &array->val[idx + 1], + (array->len - idx) * sizeof(array->val[0])); + + heim_release(obj); +} + +/** + * Get value at idx + * + * @param array the array to modify + * @param idx the key to delete + */ + +void +heim_array_filter(heim_array_t array, bool (^block)(heim_object_t)) +{ + size_t n = 0; + + while (n < array->len) { + if (block(array->val[n])) { + heim_array_delete_value(array, n); + } else { + n++; + } + } +} diff --git a/base/baselocl.h b/base/baselocl.h index dc08e58ed..3932378b2 100644 --- a/base/baselocl.h +++ b/base/baselocl.h @@ -40,8 +40,9 @@ #include #include "config.h" -#include "heim_threads.h" +#include "heimqueue.h" +#include "heim_threads.h" #include "heimbase.h" #include "heimbasepriv.h" @@ -49,8 +50,6 @@ #include #endif -#define HEIM_BASE_ABORT(x) abort() - #ifdef __GNUC__ #define heim_base_atomic_inc(x) __sync_add_and_fetch((x), 1) #define heim_base_atomic_dec(x) __sync_sub_and_fetch((x), 1) @@ -80,3 +79,12 @@ ((heim_object_t)((((uintptr_t)(x)) << 5) | ((tid) << 2) | 0x1)) #define heim_base_tagged_object_tid(x) ((((uintptr_t)(x)) & 0x1f) >> 2) #define heim_base_tagged_object_value(x) (((uintptr_t)(x)) >> 5) + +/* + * + */ + +#undef HEIMDAL_NORETURN_ATTRIBUTE +#define HEIMDAL_NORETURN_ATTRIBUTE +#undef HEIMDAL_PRINTF_ATTRIBUTE +#define HEIMDAL_PRINTF_ATTRIBUTE(x) diff --git a/base/heimbase.c b/base/heimbase.c index b63a78cd3..730af195b 100644 --- a/base/heimbase.c +++ b/base/heimbase.c @@ -34,27 +34,43 @@ */ #include "baselocl.h" +#include static heim_base_atomic_type tidglobal = HEIM_TID_USER; struct heim_base { heim_type_t isa; heim_base_atomic_type ref_cnt; - uintptr_t isaextra[3]; + HEIM_TAILQ_ENTRY(heim_base) autorel; + heim_auto_release_t autorelpool; + uintptr_t isaextra[3]; }; /* specialized version of base */ struct heim_base_mem { heim_type_t isa; heim_base_atomic_type ref_cnt; + HEIM_TAILQ_ENTRY(heim_base) autorel; + heim_auto_release_t autorelpool; const char *name; void (*dealloc)(void *); - uintptr_t isaextra[1]; + uintptr_t isaextra[1]; }; #define PTR2BASE(ptr) (((struct heim_base *)ptr) - 1) #define BASE2PTR(ptr) ((void *)(((struct heim_base *)ptr) + 1)) +/* + * Auto release structure + */ + +struct heim_auto_release { + HEIM_TAILQ_HEAD(, heim_base) pool; + HEIMDAL_MUTEX pool_mutex; + struct heim_auto_release *parent; +}; + + /** * Retain object * @@ -75,7 +91,7 @@ heim_retain(void *ptr) return ptr; if ((heim_base_atomic_inc(&p->ref_cnt) - 1) == 0) - HEIM_BASE_ABORT("resurection"); + heim_abort("resurection"); return ptr; } @@ -103,11 +119,19 @@ heim_release(void *ptr) return; if (old == 1) { + heim_auto_release_t ar = p->autorelpool; + /* remove from autorel pool list */ + if (ar) { + p->autorelpool = NULL; + HEIMDAL_MUTEX_lock(&ar->pool_mutex); + HEIM_TAILQ_REMOVE(&ar->pool, p, autorel); + HEIMDAL_MUTEX_unlock(&ar->pool_mutex); + } if (p->isa->dealloc) p->isa->dealloc(ptr); free(p); } else - HEIM_BASE_ABORT("over release"); + heim_abort("over release"); } static heim_type_t tagged_isa[9] = { @@ -133,7 +157,7 @@ _heim_get_isa(heim_object_t ptr) return tagged_isa[heim_base_tagged_object_tid(ptr)]; if (heim_base_is_tagged_string(ptr)) return &_heim_string_object; - abort(); + heim_abort("not a supported tagged type"); } p = PTR2BASE(ptr); return p->isa; @@ -186,7 +210,7 @@ heim_cmp(heim_object_t a, heim_object_t b) { heim_tid_t ta, tb; heim_type_t isa; - + ta = heim_get_tid(a); tb = heim_get_tid(b); @@ -248,8 +272,6 @@ _heim_create_type(const char *name, { heim_type_t type; - /* XXX posix_memalign */ - type = calloc(1, sizeof(*type)); if (type == NULL) return NULL; @@ -268,6 +290,7 @@ _heim_create_type(const char *name, heim_object_t _heim_alloc_object(heim_type_t type, size_t size) { + /* XXX should use posix_memalign */ struct heim_base *p = calloc(1, size + sizeof(*p)); if (p == NULL) return NULL; @@ -312,7 +335,6 @@ heim_base_once_f(heim_base_once_t *once, void *ctx, void (*func)(void *)) HEIMDAL_MUTEX_unlock(&mutex); while (1) { struct timeval tv = { 0, 1000 }; - select(0, NULL, NULL, NULL, &tv); HEIMDAL_MUTEX_lock(&mutex); if (*once == 2) break; @@ -322,3 +344,216 @@ heim_base_once_f(heim_base_once_t *once, void *ctx, void (*func)(void *)) } #endif } + +/** + * Abort and log the failure (using syslog) + */ + +void +heim_abort(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + heim_abortv(fmt, ap); + va_end(ap); +} + +/** + * Abort and log the failure (using syslog) + */ + +void +heim_abortv(const char *fmt, va_list ap) +{ + char *str = NULL; + int ret; + + ret = vasprintf(&str, fmt, ap); + if (ret > 0 && str) { + syslog(LOG_ERR, "heim_abort: %s", str); + } + abort(); +} + +/* + * + */ + +static int ar_created = 0; +static HEIMDAL_thread_key ar_key; + +struct ar_tls { + struct heim_auto_release *head; + struct heim_auto_release *current; + HEIMDAL_MUTEX tls_mutex; +}; + +static void +ar_tls_delete(void *ptr) +{ + struct ar_tls *tls = ptr; + if (tls->head) + heim_release(tls->head); + free(tls); +} + +static void +init_ar_tls(void *ptr) +{ + int ret; + HEIMDAL_key_create(&ar_key, ar_tls_delete, ret); + if (ret == 0) + ar_created = 1; +} + +static struct ar_tls * +autorel_tls(void) +{ + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; + struct ar_tls *arp; + int ret; + + heim_base_once_f(&once, NULL, init_ar_tls); + if (!ar_created) + return NULL; + + arp = HEIMDAL_getspecific(ar_key); + if (arp == NULL) { + + arp = calloc(1, sizeof(*arp)); + if (arp == NULL) + return NULL; + HEIMDAL_setspecific(ar_key, arp, ret); + if (ret) { + free(arp); + return NULL; + } + } + return arp; + +} + +static void +autorel_dealloc(void *ptr) +{ + heim_auto_release_t ar = ptr; + struct ar_tls *tls; + + tls = autorel_tls(); + if (tls == NULL) + heim_abort("autorelease pool released on thread w/o autorelease inited"); + + heim_auto_release_drain(ar); + + if (!HEIM_TAILQ_EMPTY(&ar->pool)) + heim_abort("pool not empty after draining"); + + HEIMDAL_MUTEX_lock(&tls->tls_mutex); + if (tls->current != ptr) + heim_abort("autorelease not releaseing top pool"); + + if (tls->current != tls->head) + tls->current = ar->parent; + HEIMDAL_MUTEX_unlock(&tls->tls_mutex); +} + +static int +autorel_cmp(void *a, void *b) +{ + return (a == b); +} + +static unsigned long +autorel_hash(void *ptr) +{ + return (unsigned long)ptr; +} + + +static struct heim_type_data _heim_autorel_object = { + HEIM_TID_AUTORELEASE, + "autorelease-pool", + NULL, + autorel_dealloc, + NULL, + autorel_cmp, + autorel_hash +}; + +/** + * + */ + +heim_auto_release_t +heim_auto_release_create(void) +{ + struct ar_tls *tls = autorel_tls(); + heim_auto_release_t ar; + + if (tls == NULL) + heim_abort("Failed to create/get autorelease head"); + + ar = _heim_alloc_object(&_heim_autorel_object, sizeof(struct heim_auto_release)); + if (ar) { + HEIMDAL_MUTEX_lock(&tls->tls_mutex); + if (tls->head == NULL) + tls->head = ar; + ar->parent = tls->current; + tls->current = ar; + HEIMDAL_MUTEX_unlock(&tls->tls_mutex); + } + + return ar; +} + +/** + * Mark the current object as a + */ + +void +heim_auto_release(heim_object_t ptr) +{ + struct heim_base *p = PTR2BASE(ptr); + struct ar_tls *tls = autorel_tls(); + heim_auto_release_t ar; + + if (ptr == NULL || heim_base_is_tagged(ptr)) + return; + + /* drop from old pool */ + if ((ar = p->autorelpool) != NULL) { + HEIMDAL_MUTEX_lock(&ar->pool_mutex); + HEIM_TAILQ_REMOVE(&ar->pool, p, autorel); + p->autorelpool = NULL; + HEIMDAL_MUTEX_unlock(&ar->pool_mutex); + } + + if (tls == NULL || (ar = tls->current) == NULL) + heim_abort("no auto relase pool in place, would leak"); + + HEIMDAL_MUTEX_lock(&ar->pool_mutex); + HEIM_TAILQ_INSERT_HEAD(&ar->pool, p, autorel); + p->autorelpool = ar; + HEIMDAL_MUTEX_unlock(&ar->pool_mutex); +} + +/** + * + */ + +void +heim_auto_release_drain(heim_auto_release_t autorel) +{ + heim_object_t obj; + + /* release all elements on the tail queue */ + + HEIMDAL_MUTEX_lock(&autorel->pool_mutex); + while(!HEIM_TAILQ_EMPTY(&autorel->pool)) { + obj = HEIM_TAILQ_FIRST(&autorel->pool); + HEIMDAL_MUTEX_unlock(&autorel->pool_mutex); + heim_release(BASE2PTR(obj)); + HEIMDAL_MUTEX_lock(&autorel->pool_mutex); + } + HEIMDAL_MUTEX_unlock(&autorel->pool_mutex); +} diff --git a/base/heimbase.h b/base/heimbase.h index ca1afbc24..74d2b2b55 100644 --- a/base/heimbase.h +++ b/base/heimbase.h @@ -37,6 +37,9 @@ #define HEIM_BASE_H 1 #include +#include +#include +#include typedef void * heim_object_t; typedef unsigned int heim_tid_t; @@ -61,6 +64,19 @@ heim_get_hash(heim_object_t ptr); void heim_base_once_f(heim_base_once_t *, void *, void (*)(void *)); +void +heim_abort(const char *fmt, ...) + HEIMDAL_NORETURN_ATTRIBUTE + HEIMDAL_PRINTF_ATTRIBUTE((printf, 1, 2)); + +void +heim_abortv(const char *fmt, va_list ap) + HEIMDAL_NORETURN_ATTRIBUTE + HEIMDAL_PRINTF_ATTRIBUTE((printf, 1, 0)); + +#define heim_assert(e,t) \ + (__builtin_expect(!(e), 0) ? heim_abort(t ":" #e) : (void)0) + /* * */ @@ -93,6 +109,10 @@ void heim_array_iterate(heim_array_t, void (^)(heim_object_t)); size_t heim_array_get_length(heim_array_t); heim_object_t heim_array_copy_value(heim_array_t, size_t); +void heim_array_delete_value(heim_array_t, size_t); +#ifdef __BLOCKS__ +void heim_array_filter(heim_array_t, bool (^)(heim_object_t)); +#endif /* * Dict @@ -136,4 +156,14 @@ heim_number_t heim_number_create(int); heim_tid_t heim_number_get_type_id(void); int heim_number_get_int(heim_number_t); +/* + * + */ + +typedef struct heim_auto_release * heim_auto_release_t; + +heim_auto_release_t heim_auto_release_create(void); +void heim_auto_release_drain(heim_auto_release_t); +void heim_auto_release(heim_object_t); + #endif /* HEIM_BASE_H */ diff --git a/base/heimbasepriv.h b/base/heimbasepriv.h index 7535759a6..a12773676 100644 --- a/base/heimbasepriv.h +++ b/base/heimbasepriv.h @@ -54,6 +54,7 @@ enum { HEIM_TID_ARRAY = 129, HEIM_TID_DICT = 130, HEIM_TID_STRING = 131, + HEIM_TID_AUTORELEASE = 132, HEIM_TID_USER = 255 }; diff --git a/base/string.c b/base/string.c index fa93d9216..414a9161f 100644 --- a/base/string.c +++ b/base/string.c @@ -100,7 +100,13 @@ heim_string_create(const char *string) } /** - * Create a string object from a strings allocated in the text segment + * Create a string object from a strings allocated in the text segment. + * + * Note that static string object wont be auto released with + * heim_auto_release(), the allocation policy of the string must + * be manged separately from the returned object. This make this + * function not very useful for strings in allocated from heap or + * stack. In that case you should use heim_string_create(). * * @param string the string to create, must be an utf8 string * @@ -126,7 +132,7 @@ heim_string_get_type_id(void) } /** - * Get the string value of the content + * Get the string value of the content. * * @param string the string object to get the value from * diff --git a/base/test_base.c b/base/test_base.c index ad850575d..8a2921dfd 100644 --- a/base/test_base.c +++ b/base/test_base.c @@ -91,13 +91,43 @@ test_dict(void) return 0; } +static int +test_auto_release(void) +{ + heim_auto_release_t ar1, ar2; + heim_number_t n1; + heim_string_t s1; + + ar1 = heim_auto_release_create(); + + s1 = heim_string_create("hejsan"); + heim_auto_release(s1); + + s1 = heim_string_create_with_static("hejsan"); + heim_auto_release(s1); + + n1 = heim_number_create(1); + heim_auto_release(n1); + + ar2 = heim_auto_release_create(); + + n1 = heim_number_create(1); + heim_auto_release(n1); + + heim_release(ar2); + heim_release(ar1); + + return 0; +} + int main(int argc, char **argv) { int res = 0; - res += test_memory(); - res += test_dict(); + res |= test_memory(); + res |= test_dict(); + res |= test_auto_release(); - return 0; + return res; } -- 2.11.4.GIT