diff options
Diffstat (limited to 'camel/camel-object.c')
-rw-r--r-- | camel/camel-object.c | 1325 |
1 files changed, 0 insertions, 1325 deletions
diff --git a/camel/camel-object.c b/camel/camel-object.c deleted file mode 100644 index 7214518839..0000000000 --- a/camel/camel-object.c +++ /dev/null @@ -1,1325 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * - * Author: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright 2000-2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <string.h> -#include "camel-object.h" - -#include <e-util/e-memory.h> - -#ifdef ENABLE_THREADS -#include <pthread.h> -#include <e-util/e-msgport.h> -#endif - -#define d(x) - -/* I just mashed the keyboard for these... */ -#define CAMEL_OBJECT_MAGIC 0x77A344ED -#define CAMEL_OBJECT_CLASS_MAGIC 0xEE26A997 -#define CAMEL_OBJECT_FINALISED_MAGIC 0x84AC365F -#define CAMEL_OBJECT_CLASS_FINALISED_MAGIC 0x7621ABCD - -/* ** Quickie type system ************************************************* */ - -/* A 'locked' hooklist, that is only allocated on demand */ -typedef struct _CamelHookList { - EMutex *lock; - - unsigned int depth:30; /* recursive event depth */ - unsigned int flags:2; /* flags, see below */ - - unsigned int list_length; - struct _CamelHookPair *list; -} CamelHookList; - -#define CAMEL_HOOK_PAIR_REMOVED (1<<0) - -/* a 'hook pair', actually a hook tuple, we just store all hooked events in the same list, - and just comapre as we go, rather than storing separate lists for each hook type - - the name field just points directly to the key field in the class's preplist hashtable. - This way we can just use a direct pointer compare when scanning it, and also saves - copying the string */ -typedef struct _CamelHookPair -{ - struct _CamelHookPair *next; /* next MUST be the first member */ - - unsigned int id:30; - unsigned int flags:2; /* removed, etc */ - - const char *name; /* points to the key field in the classes preplist, static memory */ - union { - CamelObjectEventHookFunc event; - CamelObjectEventPrepFunc prep; - } func; - void *data; -} CamelHookPair; - -struct _CamelObjectBag { - GHashTable *object_table; /* object by key */ - GHashTable *key_table; /* key by object */ - guint32 flags; -#ifdef ENABLE_THREADS - pthread_t owner; - pthread_cond_t cond; -#endif -}; - -#define CAMEL_OBJECT_BAG_RESERVED (1) - -/* used to tag a bag hookpair */ -static const char *bag_name = "object:bag"; - -/* ********************************************************************** */ - -static CamelHookList *camel_object_get_hooks(CamelObject *o); -static void camel_object_free_hooks(CamelObject *o); -static void camel_object_bag_remove_unlocked(CamelObjectBag *inbag, CamelObject *o, CamelHookList *hooks); - -#ifdef ENABLE_THREADS -#define camel_object_unget_hooks(o) (e_mutex_unlock((CAMEL_OBJECT(o)->hooks->lock))) -#else -#define camel_object_unget_hooks(o) -#endif - -/* ********************************************************************** */ - -static pthread_mutex_t chunks_lock = PTHREAD_MUTEX_INITIALIZER; - -static EMemChunk *pair_chunks; -static EMemChunk *hook_chunks; -static unsigned int pair_id = 1; - -static EMutex *type_lock; - -static GHashTable *type_table; -static EMemChunk *type_chunks; - -CamelType camel_object_type; - -#ifdef ENABLE_THREADS -#define P_LOCK(l) (pthread_mutex_lock(&l)) -#define P_UNLOCK(l) (pthread_mutex_unlock(&l)) -#define E_LOCK(l) (e_mutex_lock(l)) -#define E_UNLOCK(l) (e_mutex_unlock(l)) -#define CLASS_LOCK(k) (g_mutex_lock((((CamelObjectClass *)k)->lock))) -#define CLASS_UNLOCK(k) (g_mutex_unlock((((CamelObjectClass *)k)->lock))) -#else -#define P_LOCK(l) -#define P_UNLOCK(l) -#define E_LOCK(l) -#define E_UNLOCK(l) -#define CLASS_LOCK(k) -#define CLASS_UNLOCK(k) -#endif - -static struct _CamelHookPair * -pair_alloc(void) -{ - CamelHookPair *pair; - - P_LOCK(chunks_lock); - pair = e_memchunk_alloc(pair_chunks); - pair->id = pair_id++; - if (pair_id == 0) - pair_id = 1; - P_UNLOCK(chunks_lock); - - return pair; -} - -static void -pair_free(CamelHookPair *pair) -{ - g_assert(pair_chunks != NULL); - - P_LOCK(chunks_lock); - e_memchunk_free(pair_chunks, pair); - P_UNLOCK(chunks_lock); -} - -static struct _CamelHookList * -hooks_alloc(void) -{ - CamelHookList *hooks; - - P_LOCK(chunks_lock); - hooks = e_memchunk_alloc(hook_chunks); - P_UNLOCK(chunks_lock); - - return hooks; -} - -static void -hooks_free(CamelHookList *hooks) -{ - g_assert(hook_chunks != NULL); - - P_LOCK(chunks_lock); - e_memchunk_free(hook_chunks, hooks); - P_UNLOCK(chunks_lock); -} - -/* not checked locked, who cares, only required for people that want to redefine root objects */ -void -camel_type_init(void) -{ - static int init = FALSE; - - if (init) - return; - - init = TRUE; - pair_chunks = e_memchunk_new(16, sizeof(CamelHookPair)); - hook_chunks = e_memchunk_new(16, sizeof(CamelHookList)); - type_lock = e_mutex_new(E_MUTEX_REC); - type_chunks = e_memchunk_new(32, sizeof(CamelType)); - type_table = g_hash_table_new(NULL, NULL); -} - -/* ************************************************************************ */ - -/* Should this return the object to the caller? */ -static void -cobject_init (CamelObject *o, CamelObjectClass *klass) -{ - o->klass = klass; - o->magic = CAMEL_OBJECT_MAGIC; - o->ref_count = 1; - o->flags = 0; -} - -static void -cobject_finalise(CamelObject *o) -{ - /*printf("%p: finalise %s\n", o, o->klass->name);*/ - - g_assert(o->ref_count == 0); - - camel_object_free_hooks(o); - - o->magic = CAMEL_OBJECT_FINALISED_MAGIC; - o->klass = NULL; -} - -static int -cobject_getv(CamelObject *o, CamelException *ex, CamelArgGetV *args) -{ - int i; - guint32 tag; - - for (i=0;i<args->argc;i++) { - CamelArgGet *arg = &args->argv[i]; - - tag = arg->tag; - - switch (tag & CAMEL_ARG_TAG) { - case CAMEL_OBJECT_ARG_DESCRIPTION: - *arg->ca_str = (char *)o->klass->name; - break; - } - } - - /* could have flags or stuff here? */ - return 0; -} - -static int -cobject_setv(CamelObject *o, CamelException *ex, CamelArgV *args) -{ - /* could have flags or stuff here? */ - return 0; -} - -static void -cobject_free(CamelObject *o, guint32 tag, void *value) -{ - /* do nothing */ -} - -static void -cobject_class_init(CamelObjectClass *klass) -{ - klass->magic = CAMEL_OBJECT_CLASS_MAGIC; - - klass->getv = cobject_getv; - klass->setv = cobject_setv; - klass->free = cobject_free; - - camel_object_class_add_event(klass, "finalize", NULL); -} - -static void -cobject_class_finalise(CamelObjectClass * klass) -{ - klass->magic = CAMEL_OBJECT_CLASS_FINALISED_MAGIC; - - g_free(klass); -} - -CamelType -camel_object_get_type (void) -{ - if (camel_object_type == CAMEL_INVALID_TYPE) { - camel_type_init(); - - camel_object_type = camel_type_register(NULL, "CamelObject", /*, 0, 0*/ - sizeof(CamelObject), sizeof(CamelObjectClass), - cobject_class_init, cobject_class_finalise, - cobject_init, cobject_finalise); - } - - return camel_object_type; -} - -static void -camel_type_class_init(CamelObjectClass *klass, CamelObjectClass *type) -{ - if (type->parent) - camel_type_class_init(klass, type->parent); - - if (type->klass_init) - type->klass_init(klass); -} - -CamelType -camel_type_register (CamelType parent, const char * name, - /*unsigned int ver, unsigned int rev,*/ - size_t object_size, size_t klass_size, - CamelObjectClassInitFunc class_init, - CamelObjectClassFinalizeFunc class_finalise, - CamelObjectInitFunc object_init, - CamelObjectFinalizeFunc object_finalise) -{ - CamelObjectClass *klass; - /*int offset; - size_t size;*/ - - if (parent != NULL && parent->magic != CAMEL_OBJECT_CLASS_MAGIC) { - g_warning("camel_type_register: invalid junk parent class for '%s'", name); - return NULL; - } - - E_LOCK(type_lock); - - /* Have to check creation, it might've happened in another thread before we got here */ - klass = g_hash_table_lookup(type_table, name); - if (klass != NULL) { - if (klass->klass_size != klass_size || klass->object_size != object_size - || klass->klass_init != class_init || klass->klass_finalise != class_finalise - || klass->init != object_init || klass->finalise != object_finalise) { - g_warning("camel_type_register: Trying to re-register class '%s'", name); - klass = NULL; - } - E_UNLOCK(type_lock); - return klass; - } - - /* this is for objects with no parent as part of their struct ('interfaces'?) */ - /*offset = parent?parent->klass_size:0; - offset = (offset + 3) & (~3); - - size = offset + klass_size; - - klass = g_malloc0(size); - - klass->klass_size = size; - klass->klass_data = offset; - - offset = parent?parent->object_size:0; - offset = (offset + 3) & (~3); - - klass->object_size = offset + object_size; - klass->object_data = offset;*/ - - if (parent - && klass_size < parent->klass_size) { - g_warning("camel_type_register: '%s' has smaller class size than parent '%s'", name, parent->name); - E_UNLOCK(type_lock); - return NULL; - } - - klass = g_malloc0(klass_size); - klass->klass_size = klass_size; - klass->object_size = object_size; -#ifdef ENABLE_THREADS - klass->lock = g_mutex_new(); -#endif - klass->instance_chunks = e_memchunk_new(8, object_size); - - klass->parent = parent; - if (parent) { - klass->next = parent->child; - parent->child = klass; - } - klass->name = name; - - /*klass->version = ver; - klass->revision = rev;*/ - - klass->klass_init = class_init; - klass->klass_finalise = class_finalise; - - klass->init = object_init; - klass->finalise = object_finalise; - - /* setup before class init, incase class init func uses the type or looks it up ? */ - g_hash_table_insert(type_table, (void *)name, klass); - - camel_type_class_init(klass, klass); - - E_UNLOCK(type_lock); - - return klass; -} - -static void -camel_object_init(CamelObject *o, CamelObjectClass *klass, CamelType type) -{ - if (type->parent) - camel_object_init(o, klass, type->parent); - - if (type->init) - type->init(o, klass); -} - -CamelObject * -camel_object_new(CamelType type) -{ - CamelObject *o; - - if (type == NULL) - return NULL; - - if (type->magic != CAMEL_OBJECT_CLASS_MAGIC) - return NULL; - - CLASS_LOCK(type); - - o = e_memchunk_alloc0(type->instance_chunks); - -#ifdef CAMEL_OBJECT_TRACK_INSTANCES - if (type->instances) - type->instances->prev = o; - o->next = type->instances; - o->prev = NULL; - type->instances = o; -#endif - - CLASS_UNLOCK(type); - - camel_object_init(o, type, type); - - d(printf("%p: new %s()\n", o, o->klass->name)); - - return o; -} - -void -camel_object_ref(void *vo) -{ - register CamelObject *o = vo; - - g_return_if_fail(CAMEL_IS_OBJECT(o)); - - E_LOCK(type_lock); - - o->ref_count++; - d(printf("%p: ref %s(%d)\n", o, o->klass->name, o->ref_count)); - - E_UNLOCK(type_lock); -} - -void -camel_object_unref(void *vo) -{ - register CamelObject *o = vo; - register CamelObjectClass *klass, *k; - CamelHookList *hooks = NULL; - - g_return_if_fail(CAMEL_IS_OBJECT(o)); - - klass = o->klass; - - if (o->hooks) - hooks = camel_object_get_hooks(o); - - E_LOCK(type_lock); - - o->ref_count--; - - d(printf("%p: unref %s(%d)\n", o, o->klass->name, o->ref_count)); - - if (o->ref_count > 0 - || (o->flags & CAMEL_OBJECT_DESTROY)) { - E_UNLOCK(type_lock); - if (hooks) - camel_object_unget_hooks(o); - return; - } - - o->flags |= CAMEL_OBJECT_DESTROY; - - if (hooks) - camel_object_bag_remove_unlocked(NULL, o, hooks); - - E_UNLOCK(type_lock); - - if (hooks) - camel_object_unget_hooks(o); - - camel_object_trigger_event(o, "finalize", NULL); - - k = klass; - while (k) { - if (k->finalise) - k->finalise(o); - k = k->parent; - } - - o->magic = CAMEL_OBJECT_FINALISED_MAGIC; - - CLASS_LOCK(klass); -#ifdef CAMEL_OBJECT_TRACK_INSTANCES - if (o->prev) - o->prev->next = o->next; - else - klass->instances = o->next; - if (o->next) - o->next->prev = o->prev; -#endif - e_memchunk_free(klass->instance_chunks, o); - CLASS_UNLOCK(klass); -} - -const char * -camel_type_to_name (CamelType type) -{ - if (type == NULL) - return "(NULL class)"; - - if (type->magic == CAMEL_OBJECT_CLASS_MAGIC) - return type->name; - - return "(Junk class)"; -} - -CamelType camel_name_to_type(const char *name) -{ - /* TODO: Load a class off disk (!) */ - - return g_hash_table_lookup(type_table, name); -} - -static char * -desc_data(CamelObject *o, int ok) -{ - char *what; - - if (o == NULL) - what = g_strdup("NULL OBJECT"); - else if (o->magic == ok) - what = NULL; - else if (o->magic == CAMEL_OBJECT_MAGIC) - what = g_strdup_printf("CLASS '%s'", ((CamelObjectClass *)o)->name); - else if (o->magic == CAMEL_OBJECT_CLASS_MAGIC) - what = g_strdup_printf("CLASS '%s'", ((CamelObjectClass *)o)->name); - else if (o->magic == CAMEL_OBJECT_FINALISED_MAGIC) - what = g_strdup_printf("finalised OBJECT"); - else if (o->magic == CAMEL_OBJECT_CLASS_FINALISED_MAGIC) - what = g_strdup_printf("finalised CLASS"); - else - what = g_strdup_printf("junk data"); - - return what; -} - -static gboolean -check_magic(void *o, CamelType ctype, int isob) -{ - char *what, *to; - - what = desc_data(o, isob?CAMEL_OBJECT_MAGIC:CAMEL_OBJECT_CLASS_MAGIC); - to = desc_data((CamelObject *)ctype, CAMEL_OBJECT_CLASS_MAGIC); - - if (what || to) { - if (what == NULL) { - if (isob) - what = g_strdup_printf("OBJECT '%s'", ((CamelObject *)o)->klass->name); - else - what = g_strdup_printf("OBJECT '%s'", ((CamelObjectClass *)o)->name); - } - if (to == NULL) - to = g_strdup_printf("OBJECT '%s'", ctype->name); - g_warning("Trying to check %s is %s", what, to); - g_free(what); - g_free(to); - - return FALSE; - } - - return TRUE; -} - -gboolean -camel_object_is (CamelObject *o, CamelType ctype) -{ - CamelObjectClass *k; - - g_return_val_if_fail(check_magic(o, ctype, TRUE), FALSE); - - k = o->klass; - while (k) { - if (k == ctype) - return TRUE; - k = k->parent; - } - - return FALSE; -} - -gboolean -camel_object_class_is (CamelObjectClass *k, CamelType ctype) -{ - g_return_val_if_fail(check_magic(k, ctype, FALSE), FALSE); - - while (k) { - if (k == ctype) - return TRUE; - k = k->parent; - } - - return FALSE; -} - -CamelObject * -camel_object_cast(CamelObject *o, CamelType ctype) -{ - CamelObjectClass *k; - - g_return_val_if_fail(check_magic(o, ctype, TRUE), NULL); - - k = o->klass; - while (k) { - if (k == ctype) - return o; - k = k->parent; - } - - g_warning("Object %p (class '%s') doesn't have '%s' in its hierarchy", o, o->klass->name, ctype->name); - - return NULL; -} - -CamelObjectClass * -camel_object_class_cast(CamelObjectClass *k, CamelType ctype) -{ - CamelObjectClass *r = k; - - g_return_val_if_fail(check_magic(k, ctype, FALSE), NULL); - - while (k) { - if (k == ctype) - return r; - k = k->parent; - } - - g_warning("Class '%s' doesn't have '%s' in its hierarchy", r->name, ctype->name); - - return NULL; -} - -void -camel_object_class_add_event(CamelObjectClass *klass, const char *name, CamelObjectEventPrepFunc prep) -{ - CamelHookPair *pair; - - g_return_if_fail (name); - - pair = klass->hooks; - while (pair) { - if (strcmp(pair->name, name) == 0) { - g_warning("camel_object_class_add_event: `%s' is already declared for '%s'\n", - name, klass->name); - return; - } - pair = pair->next; - } - - pair = pair_alloc(); - pair->name = name; - pair->func.prep = prep; - pair->flags = 0; - - pair->next = klass->hooks; - klass->hooks = pair; -} - -/* free hook data */ -static void camel_object_free_hooks(CamelObject *o) -{ - CamelHookPair *pair, *next; - - if (o->hooks) { - g_assert(o->hooks->depth == 0); - g_assert((o->hooks->flags & CAMEL_HOOK_PAIR_REMOVED) == 0); - - pair = o->hooks->list; - while (pair) { - next = pair->next; - pair_free(pair); - pair = next; - } - e_mutex_destroy(o->hooks->lock); - hooks_free(o->hooks); - o->hooks = NULL; - } -} - -/* return (allocate if required) the object's hook list, locking at the same time */ -static CamelHookList *camel_object_get_hooks(CamelObject *o) -{ -#ifdef ENABLE_THREADS - static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; -#endif - CamelHookList *hooks; - - /* if we have it, we dont have to do any other locking, - otherwise use a global lock to setup the object's hook data */ -#ifdef ENABLE_THREADS - if (o->hooks == NULL) { - pthread_mutex_lock(&lock); -#endif - if (o->hooks == NULL) { - hooks = hooks_alloc(); -#ifdef ENABLE_THREADS - hooks->lock = e_mutex_new(E_MUTEX_REC); -#endif - hooks->flags = 0; - hooks->depth = 0; - hooks->list_length = 0; - hooks->list = NULL; - o->hooks = hooks; - } -#ifdef ENABLE_THREADS - pthread_mutex_unlock(&lock); - } -#endif - -#ifdef ENABLE_THREADS - e_mutex_lock(o->hooks->lock); -#endif - return o->hooks; -} - -unsigned int -camel_object_hook_event(void *vo, const char * name, CamelObjectEventHookFunc func, void *data) -{ - CamelObject *obj = vo; - CamelHookPair *pair, *hook; - CamelHookList *hooks; - int id; - - g_return_val_if_fail(CAMEL_IS_OBJECT (obj), 0); - g_return_val_if_fail(name != NULL, 0); - g_return_val_if_fail(func != NULL, 0); - - hook = obj->klass->hooks; - while (hook) { - if (strcmp(hook->name, name) == 0) - goto setup; - hook = hook->next; - } - - g_warning("camel_object_hook_event: trying to hook event `%s' in class `%s' with no defined events.", - name, obj->klass->name); - - return 0; - -setup: - /* setup hook pair */ - pair = pair_alloc(); - pair->name = hook->name; /* effectively static! */ - pair->func.event = func; - pair->data = data; - pair->flags = 0; - id = pair->id; - - /* get the hook list object, locked, link in new event hook, unlock */ - hooks = camel_object_get_hooks(obj); - pair->next = hooks->list; - hooks->list = pair; - hooks->list_length++; - camel_object_unget_hooks(obj); - - return id; -} - -void -camel_object_remove_event(void *vo, unsigned int id) -{ - CamelObject *obj = vo; - CamelHookList *hooks; - CamelHookPair *pair, *parent; - - g_return_if_fail (CAMEL_IS_OBJECT (obj)); - g_return_if_fail (id != 0); - - if (obj->hooks == NULL) { - g_warning("camel_object_unhook_event: trying to unhook `%d` from an instance of `%s' with no hooks", - id, obj->klass->name); - return; - } - - /* scan hooks for this event, remove it, or flag it if we're busy */ - hooks = camel_object_get_hooks(obj); - parent = (CamelHookPair *)&hooks->list; - pair = parent->next; - while (pair) { - if (pair->id == id - && (pair->flags & CAMEL_HOOK_PAIR_REMOVED) == 0) { - if (hooks->depth > 0) { - pair->flags |= CAMEL_HOOK_PAIR_REMOVED; - hooks->flags |= CAMEL_HOOK_PAIR_REMOVED; - } else { - parent->next = pair->next; - pair_free(pair); - hooks->list_length--; - } - camel_object_unget_hooks(obj); - return; - } - parent = pair; - pair = pair->next; - } - camel_object_unget_hooks(obj); - - g_warning("camel_object_unhook_event: cannot find hook id %d in instance of `%s'", - id, obj->klass->name); -} - -void -camel_object_unhook_event(void *vo, const char * name, CamelObjectEventHookFunc func, void *data) -{ - CamelObject *obj = vo; - CamelHookList *hooks; - CamelHookPair *pair, *parent; - - g_return_if_fail (CAMEL_IS_OBJECT (obj)); - g_return_if_fail (name != NULL); - g_return_if_fail (func != NULL); - - if (obj->hooks == NULL) { - g_warning("camel_object_unhook_event: trying to unhook `%s` from an instance of `%s' with no hooks", - name, obj->klass->name); - return; - } - - /* scan hooks for this event, remove it, or flag it if we're busy */ - hooks = camel_object_get_hooks(obj); - parent = (CamelHookPair *)&hooks->list; - pair = parent->next; - while (pair) { - if (pair->func.event == func - && pair->data == data - && strcmp(pair->name, name) == 0 - && (pair->flags & CAMEL_HOOK_PAIR_REMOVED) == 0) { - if (hooks->depth > 0) { - pair->flags |= CAMEL_HOOK_PAIR_REMOVED; - hooks->flags |= CAMEL_HOOK_PAIR_REMOVED; - } else { - parent->next = pair->next; - pair_free(pair); - hooks->list_length--; - } - camel_object_unget_hooks(obj); - return; - } - parent = pair; - pair = pair->next; - } - camel_object_unget_hooks(obj); - - g_warning("camel_object_unhook_event: cannot find hook/data pair %p/%p in an instance of `%s' attached to `%s'", - func, data, obj->klass->name, name); -} - -void -camel_object_trigger_event(void *vo, const char * name, void *event_data) -{ - CamelObject *obj = vo; - CamelHookList *hooks; - CamelHookPair *pair, **pairs, *parent, *hook; - int i, size; - const char *prepname; - - g_return_if_fail (CAMEL_IS_OBJECT (obj)); - g_return_if_fail (name); - - hook = obj->klass->hooks; - while (hook) { - if (strcmp(hook->name, name) == 0) - goto trigger; - hook = hook->next; - } - - g_warning("camel_object_trigger_event: trying to trigger unknown event `%s' in class `%s'", - name, obj->klass->name); - - return; - -trigger: - /* try prep function, if false, then quit */ - if (hook->func.prep != NULL && !hook->func.prep(obj, event_data)) - return; - - /* also, no hooks, dont bother going further */ - if (obj->hooks == NULL) - return; - - /* lock the object for hook emission */ - camel_object_ref(obj); - hooks = camel_object_get_hooks(obj); - - if (hooks->list) { - /* first, copy the items in the list, and say we're in an event */ - hooks->depth++; - pair = hooks->list; - size = 0; - pairs = alloca(sizeof(pairs[0]) * hooks->list_length); - prepname = hook->name; - while (pair) { - if (pair->name == prepname) - pairs[size++] = pair; - pair = pair->next; - } - - /* now execute the events we have, if they haven't been removed during our calls */ - for (i=size-1;i>=0;i--) { - pair = pairs[i]; - if ((pair->flags & CAMEL_HOOK_PAIR_REMOVED) == 0) - (pair->func.event) (obj, event_data, pair->data); - } - hooks->depth--; - - /* and if we're out of any events, then clean up any pending removes */ - if (hooks->depth == 0 && (hooks->flags & CAMEL_HOOK_PAIR_REMOVED)) { - parent = (CamelHookPair *)&hooks->list; - pair = parent->next; - while (pair) { - if (pair->flags & CAMEL_HOOK_PAIR_REMOVED) { - parent->next = pair->next; - pair_free(pair); - hooks->list_length--; - } else { - parent = pair; - } - pair = parent->next; - } - hooks->flags &= ~CAMEL_HOOK_PAIR_REMOVED; - } - } - - camel_object_unget_hooks(obj); - camel_object_unref(obj); -} - -/* get/set arg methods */ -int camel_object_set(void *vo, CamelException *ex, ...) -{ - CamelArgV args; - CamelObject *o = vo; - CamelObjectClass *klass = o->klass; - int ret = 0; - - g_return_val_if_fail(CAMEL_IS_OBJECT(o), -1); - - camel_argv_start(&args, ex); - - while (camel_argv_build(&args) && ret == 0) - ret = klass->setv(o, ex, &args); - if (ret == 0) - ret = klass->setv(o, ex, &args); - - camel_argv_end(&args); - - return ret; -} - -int camel_object_setv(void *vo, CamelException *ex, CamelArgV *args) -{ - g_return_val_if_fail(CAMEL_IS_OBJECT(vo), -1); - - return ((CamelObject *)vo)->klass->setv(vo, ex, args); -} - -int camel_object_get(void *vo, CamelException *ex, ...) -{ - CamelObject *o = vo; - CamelArgGetV args; - CamelObjectClass *klass = o->klass; - int ret = 0; - - g_return_val_if_fail(CAMEL_IS_OBJECT(o), -1); - - camel_argv_start(&args, ex); - - while (camel_arggetv_build(&args) && ret == 0) - ret = klass->getv(o, ex, &args); - if (ret == 0) - ret = klass->getv(o, ex, &args); - - camel_argv_end(&args); - - return ret; -} - -int camel_object_getv(void *vo, CamelException *ex, CamelArgGetV *args) -{ - g_return_val_if_fail(CAMEL_IS_OBJECT(vo), -1); - - return ((CamelObject *)vo)->klass->getv(vo, ex, args); -} - -/* free an arg object, you can only free objects 1 at a time */ -void camel_object_free(void *vo, guint32 tag, void *value) -{ - g_return_if_fail(CAMEL_IS_OBJECT(vo)); - - /* We could also handle freeing of args differently - - Add a 'const' bit to the arg type field, - specifying that the object should not be freed. - - And, add free handlers for any pointer objects which are - not const. The free handlers would be hookpairs off of the - class. - - Then we handle the basic types OBJ,STR here, and pass PTR - types to their appropriate handler, without having to pass - through the invocation heirarchy of the free method. - - This would also let us copy and do other things with args - we can't do, but i can't see a use for that yet ... */ - - ((CamelObject *)vo)->klass->free(vo, tag, value); -} - -static void -object_class_dump_tree_rec(CamelType root, int depth) -{ - char *p; -#ifdef CAMEL_OBJECT_TRACK_INSTANCES - struct _CamelObject *o; -#endif - - p = alloca(depth*2+1); - memset(p, ' ', depth*2); - p[depth*2] = 0; - - while (root) { - CLASS_LOCK(root); - printf("%sClass: %s\n", p, root->name); - /*printf("%sVersion: %u.%u\n", p, root->version, root->revision);*/ - if (root->hooks) { - CamelHookPair *pair = root->hooks; - - while (pair) { - printf("%s event '%s' prep %p\n", p, pair->name, pair->func.prep); - pair = pair->next; - } - } -#ifdef CAMEL_OBJECT_TRACK_INSTANCES - o = root->instances; - while (o) { - printf("%s instance %p [%d]\n", p, o, o->ref_count); - /* todo: should lock hooks while it scans them */ - if (o->hooks) { - CamelHookPair *pair = o->hooks->list; - - while (pair) { - printf("%s hook '%s' func %p data %p\n", p, pair->name, pair->func.event, pair->data); - pair = pair->next; - } - } - o = o->next; - } -#endif - CLASS_UNLOCK(root); - - if (root->child) - object_class_dump_tree_rec(root->child, depth+1); - - root = root->next; - } -} - -void -camel_object_class_dump_tree(CamelType root) -{ - object_class_dump_tree_rec(root, 0); -} - -CamelObjectBag *camel_object_bag_new(GHashFunc hash, GEqualFunc equal) -{ - CamelObjectBag *bag; - - bag = g_malloc(sizeof(*bag)); - bag->object_table = g_hash_table_new(hash, equal); - bag->key_table = g_hash_table_new(NULL, NULL); - bag->flags = 0; -#ifdef ENABLE_THREADS - pthread_cond_init(&bag->cond, NULL); -#endif - return bag; -} - -static void -remove_bag(char *key, CamelObject *o, CamelObjectBag *bag) -{ - camel_object_bag_remove(bag, o); - g_free(key); -} - -void camel_object_bag_destroy(CamelObjectBag *bag) -{ - g_assert(bag->flags == 0); - - g_hash_table_foreach(bag->object_table, (GHFunc)remove_bag, bag); - g_hash_table_destroy(bag->object_table); - g_hash_table_destroy(bag->key_table); - g_free(bag); -} - -void camel_object_bag_add(CamelObjectBag *bag, const char *key, void *vo) -{ - CamelObject *o = vo; - CamelHookList *hooks; - CamelHookPair *pair; - char *k; - - hooks = camel_object_get_hooks(o); - E_LOCK(type_lock); - - pair = hooks->list; - while (pair) { - if (pair->name == bag_name && pair->data == bag) { - E_UNLOCK(type_lock); - camel_object_unget_hooks(o); - return; - } - pair = pair->next; - } - - pair = pair_alloc(); - pair->name = bag_name; - pair->data = bag; - pair->flags = 0; - - pair->next = hooks->list; - hooks->list = pair; - hooks->list_length++; - - k = g_strdup(key); - g_hash_table_insert(bag->object_table, k, vo); - g_hash_table_insert(bag->key_table, vo, k); - -#ifdef ENABLE_THREADS - if (bag->flags & CAMEL_OBJECT_BAG_RESERVED - && bag->owner == pthread_self()) { - bag->flags &= ~CAMEL_OBJECT_BAG_RESERVED; - pthread_cond_broadcast(&bag->cond); - } -#endif - - E_UNLOCK(type_lock); - camel_object_unget_hooks(o); -} - -void *camel_object_bag_get(CamelObjectBag *bag, const char *key) -{ - CamelObject *o; - int retry; - - E_LOCK(type_lock); - - do { - retry = FALSE; - o = g_hash_table_lookup(bag->object_table, key); - if (o) { - /* we use the same lock as the refcount */ - o->ref_count++; - } -#ifdef ENABLE_THREADS - else { - if (bag->flags & CAMEL_OBJECT_BAG_RESERVED) { - e_mutex_cond_wait(&bag->cond, type_lock); - retry = TRUE; - } - } -#endif - } while (retry); - - E_UNLOCK(type_lock); - - return o; -} - -/* like get, but also reserve a spot for key if it isn't there */ -/* After calling reserve, you MUST call bag_abort or bag_add */ -/* Also note that currently you can only reserve a single key - at any one time in a given thread */ -void *camel_object_bag_reserve(CamelObjectBag *bag, const char *key) -{ - CamelObject *o; - int retry; - - E_LOCK(type_lock); - - do { - retry = FALSE; - o = g_hash_table_lookup(bag->object_table, key); - if (o) { - /* we use the same lock as the refcount */ - o->ref_count++; - } -#ifdef ENABLE_THREADS - else { - /* NOTE: We dont actually reserve the key, we just reserve - the whole bag. We could do either but this is easier */ - if (bag->flags & CAMEL_OBJECT_BAG_RESERVED) { - e_mutex_cond_wait(&bag->cond, type_lock); - retry = TRUE; - } else { - bag->flags |= CAMEL_OBJECT_BAG_RESERVED; - bag->owner = pthread_self(); - } - } -#endif - } while (retry); - - E_UNLOCK(type_lock); - - return o; -} - -/* abort a reserved key */ -void camel_object_bag_abort(CamelObjectBag *bag, const char *key) -{ - CamelObject *o; - int retry; - - E_LOCK(type_lock); - - /* NOTE: We dont actually reserve the key, we just reserve - the whole bag. We could do either but this is easier */ - - g_assert(bag->owner == pthread_self()); - g_assert(bag->flags & CAMEL_OBJECT_BAG_RESERVED); - - bag->owner = 0; - bag->flags &= ~CAMEL_OBJECT_BAG_RESERVED; - - pthread_cond_broadcast(&bag->cond); - - E_UNLOCK(type_lock); -} - -static void -save_bag(char *key, CamelObject *o, GPtrArray *list) -{ - /* we have the refcount lock already */ - o->ref_count++; - g_ptr_array_add(list, o); -} - -/* get a list of all objects in the bag, ref'd */ -GPtrArray *camel_object_bag_list(CamelObjectBag *bag) -{ - GPtrArray *list; - - list = g_ptr_array_new(); - E_LOCK(type_lock); - - while (bag->flags & CAMEL_OBJECT_BAG_RESERVED) - e_mutex_cond_wait(&bag->cond, type_lock); - - g_hash_table_foreach(bag->object_table, (GHFunc)save_bag, list); - E_UNLOCK(type_lock); - - return list; -} - -/* if bag is NULL, remove all bags from object */ -static void camel_object_bag_remove_unlocked(CamelObjectBag *inbag, CamelObject *o, CamelHookList *hooks) -{ - CamelHookPair *pair, *parent; - char *oldkey; - CamelObjectBag *bag; - - parent = (CamelHookPair *)&hooks->list; - pair = parent->next; - while (pair) { - if (pair->name == bag_name - && (inbag == NULL || inbag == pair->data)) { - bag = pair->data; - /* lookup object in table? */ - oldkey = g_hash_table_lookup(bag->key_table, o); - if (oldkey) { - g_hash_table_remove(bag->key_table, o); - g_hash_table_remove(bag->object_table, oldkey); - g_free(oldkey); - } - parent->next = pair->next; - pair_free(pair); - hooks->list_length--; - } else { - parent = pair; - } - pair = parent->next; - } -} - -void camel_object_bag_remove(CamelObjectBag *inbag, void *vo) -{ - CamelObject *o = vo; - CamelHookPair *pair, *parent; - CamelHookList *hooks; - char *oldkey; - CamelObjectBag *bag; - - if (o->hooks == NULL) - return; - - hooks = camel_object_get_hooks(o); - E_LOCK(type_lock); - - camel_object_bag_remove_unlocked(inbag, o, hooks); - - E_UNLOCK(type_lock); - camel_object_unget_hooks(o); -} |