diff options
author | Not Zed <NotZed@Ximian.com> | 2002-12-09 08:28:06 +0800 |
---|---|---|
committer | Michael Zucci <zucchi@src.gnome.org> | 2002-12-09 08:28:06 +0800 |
commit | 24b06cb2a4030282763c8f60ba3b0b8b806d15d3 (patch) | |
tree | 44b57fbee23cb93c7b1e0d26aa2aac5eb360ee5f /camel/camel-object.c | |
parent | c43c83145ab56f5422665f8a9c8468033064ce95 (diff) | |
download | gsoc2013-evolution-24b06cb2a4030282763c8f60ba3b0b8b806d15d3.tar.gz gsoc2013-evolution-24b06cb2a4030282763c8f60ba3b0b8b806d15d3.tar.zst gsoc2013-evolution-24b06cb2a4030282763c8f60ba3b0b8b806d15d3.zip |
Use a bag instead of a hashtable to track the cache streams.
2002-12-07 Not Zed <NotZed@Ximian.com>
* camel-data-cache.c (data_cache_init): Use a bag instead of a
hashtable to track the cache streams.
(data_cache_finalise): Same.
(free_busy): No longer needed.
(data_cache_expire): use bag instead of hashtable.
(stream_finalised): No longer required.
(camel_data_cache_add): objectbagise
(camel_data_cache_get): "
(camel_data_cache_remove): "
(data_cache_path): Set the now expired date before running expiry,
so it plays better with multiple threads. Still a couple of
harmless races.
2002-12-06 Not Zed <NotZed@Ximian.com>
* providers/local/camel-spool-store.c (scan_dir): folders ->
object bag.
(get_folder_info_mbox): folders -> object bag.
* providers/local/camel-mh-store.c (folder_info_new): folders ->
object bag.
* providers/local/camel-maildir-store.c (scan_dir): folders ->
object bag.
* providers/local/camel-local-store.c (rename_folder): folders ->
object bag.
* camel-private.h (CamelStorePrivate): Remove 'cache' lock,
handled by the objectbag.
* providers/imap/camel-imap-store.c (copy_folder): Removed.
(imap_store_refresh_folders): folders -> object bag.
(get_folder_counts): folders -> object bag.
* camel-vee-store.c (vee_get_folder): changes for folders
objectbag.
(vee_get_folder_info): Change to use folders objectbag. Also,
dont refresh the base folder if we're in FAST mode.
(build_info): Removed, no longer needed.
(vee_rename_folder): Fixed for folders objectbag.
* camel-store.c (camel_store_init): init the folders objectbag.
(camel_store_finalize): Destroy the folders object bag.
(folder_matches):
(folder_finalize): Removed, now handled implicitly by the
objectbag.
(camel_store_get_folder): object bag changes.
(camel_store_delete_folder): "
(get_subfolders): Removed, now handled without a callback.
(camel_store_rename_folder): Changed to use object bag of folders.
(trash_add_folder): Removed.
(init_trash): use folders object bag.
(copy_folder_cache):
(sync_folder): Removed, no longer needed. Weird arsed code anyway.
(store_sync): Use folder object bag instead of hashtable.
(camel_store_unsubscribe_folder): "
(camel_store_init): remove cache_lock init, no longer used.
(camel_store_finalize): Same for cleanup.
2002-12-05 Not Zed <NotZed@Ximian.com>
* camel-store.h (struct _CamelStore): change folders from a
hashtable into a CamelObjectBag.
* camel-object.c (camel_object_ref): Use type_lock instead of
class lock for ref counting.
(camel_object_unref): Use type_lock instead of class lock for
unref.
(camel_object_unref): If the object is 'bagged', then also look
hooks, and remove it from any bags.
(camel_object_bag_new):
(camel_object_bag_destroy):
(camel_object_bag_add):
(camel_object_bag_get):
(camel_object_bag_remove_unlocked):
(camel_object_bag_list):
(camel_object_bag_abort):
(camel_object_bag_remove): New functions to implement a utility
object which can manage a 'bag' of weakly ref'd children in an
atomic & threadsafe way.
svn path=/trunk/; revision=19056
Diffstat (limited to 'camel/camel-object.c')
-rw-r--r-- | camel/camel-object.c | 307 |
1 files changed, 295 insertions, 12 deletions
diff --git a/camel/camel-object.c b/camel/camel-object.c index 6e3b5ef54b..7214518839 100644 --- a/camel/camel-object.c +++ b/camel/camel-object.c @@ -35,6 +35,8 @@ #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 @@ -77,9 +79,32 @@ typedef struct _CamelHookPair 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 /* ********************************************************************** */ @@ -191,6 +216,8 @@ cobject_init (CamelObject *o, CamelObjectClass *klass) 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); @@ -392,6 +419,7 @@ camel_object_new(CamelType type) return NULL; CLASS_LOCK(type); + o = e_memchunk_alloc0(type->instance_chunks); #ifdef CAMEL_OBJECT_TRACK_INSTANCES @@ -403,8 +431,11 @@ camel_object_new(CamelType type) #endif CLASS_UNLOCK(type); + camel_object_init(o, type, type); + d(printf("%p: new %s()\n", o, o->klass->name)); + return o; } @@ -415,9 +446,12 @@ camel_object_ref(void *vo) g_return_if_fail(CAMEL_IS_OBJECT(o)); - CLASS_LOCK(o->klass); + E_LOCK(type_lock); + o->ref_count++; - CLASS_UNLOCK(o->klass); + d(printf("%p: ref %s(%d)\n", o, o->klass->name, o->ref_count)); + + E_UNLOCK(type_lock); } void @@ -425,22 +459,38 @@ 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; - CLASS_LOCK(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)) { - CLASS_UNLOCK(klass); + E_UNLOCK(type_lock); + if (hooks) + camel_object_unget_hooks(o); return; } o->flags |= CAMEL_OBJECT_DESTROY; - CLASS_UNLOCK(klass); + 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); @@ -686,13 +736,6 @@ static CamelHookList *camel_object_get_hooks(CamelObject *o) return o->hooks; } -/* unlock object hooks' list */ -#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 - unsigned int camel_object_hook_event(void *vo, const char * name, CamelObjectEventHookFunc func, void *data) { @@ -1040,3 +1083,243 @@ 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); +} |