more use bits

This commit is contained in:
Love Hornquist Astrand
2010-10-26 23:41:32 -07:00
parent 82d15c0ada
commit b0c19f1a2d
7 changed files with 373 additions and 18 deletions

View File

@@ -181,6 +181,51 @@ heim_object_t
heim_array_copy_value(heim_array_t array, size_t idx) heim_array_copy_value(heim_array_t array, size_t idx)
{ {
if (idx >= array->len) if (idx >= array->len)
HEIM_BASE_ABORT("index too large"); heim_abort("index too large");
return heim_retain(array->val[idx]); 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++;
}
}
}

View File

@@ -40,8 +40,9 @@
#include <unistd.h> #include <unistd.h>
#include "config.h" #include "config.h"
#include "heim_threads.h"
#include "heimqueue.h"
#include "heim_threads.h"
#include "heimbase.h" #include "heimbase.h"
#include "heimbasepriv.h" #include "heimbasepriv.h"
@@ -49,8 +50,6 @@
#include <dispatch/dispatch.h> #include <dispatch/dispatch.h>
#endif #endif
#define HEIM_BASE_ABORT(x) abort()
#ifdef __GNUC__ #ifdef __GNUC__
#define heim_base_atomic_inc(x) __sync_add_and_fetch((x), 1) #define heim_base_atomic_inc(x) __sync_add_and_fetch((x), 1)
#define heim_base_atomic_dec(x) __sync_sub_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)) ((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_tid(x) ((((uintptr_t)(x)) & 0x1f) >> 2)
#define heim_base_tagged_object_value(x) (((uintptr_t)(x)) >> 5) #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)

View File

@@ -34,27 +34,43 @@
*/ */
#include "baselocl.h" #include "baselocl.h"
#include <syslog.h>
static heim_base_atomic_type tidglobal = HEIM_TID_USER; static heim_base_atomic_type tidglobal = HEIM_TID_USER;
struct heim_base { struct heim_base {
heim_type_t isa; heim_type_t isa;
heim_base_atomic_type ref_cnt; 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 */ /* specialized version of base */
struct heim_base_mem { struct heim_base_mem {
heim_type_t isa; heim_type_t isa;
heim_base_atomic_type ref_cnt; heim_base_atomic_type ref_cnt;
HEIM_TAILQ_ENTRY(heim_base) autorel;
heim_auto_release_t autorelpool;
const char *name; const char *name;
void (*dealloc)(void *); void (*dealloc)(void *);
uintptr_t isaextra[1]; uintptr_t isaextra[1];
}; };
#define PTR2BASE(ptr) (((struct heim_base *)ptr) - 1) #define PTR2BASE(ptr) (((struct heim_base *)ptr) - 1)
#define BASE2PTR(ptr) ((void *)(((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 * Retain object
* *
@@ -75,7 +91,7 @@ heim_retain(void *ptr)
return ptr; return ptr;
if ((heim_base_atomic_inc(&p->ref_cnt) - 1) == 0) if ((heim_base_atomic_inc(&p->ref_cnt) - 1) == 0)
HEIM_BASE_ABORT("resurection"); heim_abort("resurection");
return ptr; return ptr;
} }
@@ -103,11 +119,19 @@ heim_release(void *ptr)
return; return;
if (old == 1) { 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) if (p->isa->dealloc)
p->isa->dealloc(ptr); p->isa->dealloc(ptr);
free(p); free(p);
} else } else
HEIM_BASE_ABORT("over release"); heim_abort("over release");
} }
static heim_type_t tagged_isa[9] = { 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)]; return tagged_isa[heim_base_tagged_object_tid(ptr)];
if (heim_base_is_tagged_string(ptr)) if (heim_base_is_tagged_string(ptr))
return &_heim_string_object; return &_heim_string_object;
abort(); heim_abort("not a supported tagged type");
} }
p = PTR2BASE(ptr); p = PTR2BASE(ptr);
return p->isa; return p->isa;
@@ -186,7 +210,7 @@ heim_cmp(heim_object_t a, heim_object_t b)
{ {
heim_tid_t ta, tb; heim_tid_t ta, tb;
heim_type_t isa; heim_type_t isa;
ta = heim_get_tid(a); ta = heim_get_tid(a);
tb = heim_get_tid(b); tb = heim_get_tid(b);
@@ -248,8 +272,6 @@ _heim_create_type(const char *name,
{ {
heim_type_t type; heim_type_t type;
/* XXX posix_memalign */
type = calloc(1, sizeof(*type)); type = calloc(1, sizeof(*type));
if (type == NULL) if (type == NULL)
return NULL; return NULL;
@@ -268,6 +290,7 @@ _heim_create_type(const char *name,
heim_object_t heim_object_t
_heim_alloc_object(heim_type_t type, size_t size) _heim_alloc_object(heim_type_t type, size_t size)
{ {
/* XXX should use posix_memalign */
struct heim_base *p = calloc(1, size + sizeof(*p)); struct heim_base *p = calloc(1, size + sizeof(*p));
if (p == NULL) if (p == NULL)
return 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); HEIMDAL_MUTEX_unlock(&mutex);
while (1) { while (1) {
struct timeval tv = { 0, 1000 }; struct timeval tv = { 0, 1000 };
select(0, NULL, NULL, NULL, &tv);
HEIMDAL_MUTEX_lock(&mutex); HEIMDAL_MUTEX_lock(&mutex);
if (*once == 2) if (*once == 2)
break; break;
@@ -322,3 +344,216 @@ heim_base_once_f(heim_base_once_t *once, void *ctx, void (*func)(void *))
} }
#endif #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);
}

View File

@@ -37,6 +37,9 @@
#define HEIM_BASE_H 1 #define HEIM_BASE_H 1
#include <sys/types.h> #include <sys/types.h>
#include <krb5-types.h>
#include <stdarg.h>
#include <stdbool.h>
typedef void * heim_object_t; typedef void * heim_object_t;
typedef unsigned int heim_tid_t; typedef unsigned int heim_tid_t;
@@ -61,6 +64,19 @@ heim_get_hash(heim_object_t ptr);
void void
heim_base_once_f(heim_base_once_t *, void *, void (*)(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); size_t heim_array_get_length(heim_array_t);
heim_object_t heim_object_t
heim_array_copy_value(heim_array_t, size_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 * Dict
@@ -136,4 +156,14 @@ heim_number_t heim_number_create(int);
heim_tid_t heim_number_get_type_id(void); heim_tid_t heim_number_get_type_id(void);
int heim_number_get_int(heim_number_t); 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 */ #endif /* HEIM_BASE_H */

View File

@@ -54,6 +54,7 @@ enum {
HEIM_TID_ARRAY = 129, HEIM_TID_ARRAY = 129,
HEIM_TID_DICT = 130, HEIM_TID_DICT = 130,
HEIM_TID_STRING = 131, HEIM_TID_STRING = 131,
HEIM_TID_AUTORELEASE = 132,
HEIM_TID_USER = 255 HEIM_TID_USER = 255
}; };

View File

@@ -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 * @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 * @param string the string object to get the value from
* *

View File

@@ -91,13 +91,43 @@ test_dict(void)
return 0; 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 int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int res = 0; int res = 0;
res += test_memory(); res |= test_memory();
res += test_dict(); res |= test_dict();
res |= test_auto_release();
return 0; return res;
} }