more use bits
This commit is contained in:
47
base/array.c
47
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -40,8 +40,9 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#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 <dispatch/dispatch.h>
|
||||
#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)
|
||||
|
253
base/heimbase.c
253
base/heimbase.c
@@ -34,27 +34,43 @@
|
||||
*/
|
||||
|
||||
#include "baselocl.h"
|
||||
#include <syslog.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
@@ -37,6 +37,9 @@
|
||||
#define HEIM_BASE_H 1
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <krb5-types.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
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 */
|
||||
|
@@ -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
|
||||
|
||||
};
|
||||
|
@@ -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
|
||||
*
|
||||
|
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user