/** * camel_object_bag_add: * @bag: a #CamelObjectBag * @key: a reserved key * @object: a #GObject * * Adds @object to @bag. The @key MUST have been previously reserved using * camel_object_bag_reserve(). **/ void camel_object_bag_add (CamelObjectBag *bag, gconstpointer key, gpointer object) { g_return_if_fail (bag != NULL); g_return_if_fail (key != NULL); g_return_if_fail (G_IS_OBJECT (object)); g_mutex_lock (&bag->mutex); /* Check it's the *same* object, not an old one at the same address */ if (!object_in_bag (bag, object)) { ObjRef *ref; gpointer copied_key; ref = g_slice_new (ObjRef); ref->bag = bag; /* We need to stash a 'raw' pointer since that's the key we use * in the key_table */ ref->obj = object; g_weak_ref_init (&ref->ref, object); copied_key = bag->key_copy_func (key); g_hash_table_insert (bag->key_table, object, copied_key); g_hash_table_insert (bag->object_table, copied_key, ref); object_bag_unreserve (bag, key); g_object_weak_ref ( G_OBJECT (object), (GWeakNotify) object_bag_notify, bag); } g_mutex_unlock (&bag->mutex); }
/** * camel_object_bag_get: * @bag: a #CamelObjectBag * @key: a key * * Lookup an object by @key. If the key is currently reserved, the function * will block until another thread commits or aborts the reservation. The * caller owns the reference to the returned object. Use g_object_unref () * to unreference it. * * Returns: the object corresponding to @key, or %NULL if not found **/ gpointer camel_object_bag_get (CamelObjectBag *bag, gconstpointer key) { KeyReservation *reservation; ObjRef *ref; gpointer object = NULL; g_return_val_if_fail (bag != NULL, NULL); g_return_val_if_fail (key != NULL, NULL); g_mutex_lock (&bag->mutex); /* Look for the key in the bag. */ ref = g_hash_table_lookup (bag->object_table, key); if (ref != NULL) { object = g_weak_ref_get (&ref->ref); if (object != NULL) { g_mutex_unlock (&bag->mutex); return object; } /* Remove stale reference to dead object. */ g_hash_table_remove (bag->key_table, ref->obj); g_hash_table_remove (bag->object_table, key); } /* Check if the key has been reserved. */ reservation = key_reservation_lookup (bag, key); if (reservation == NULL) { /* No such key, so return NULL. */ g_mutex_unlock (&bag->mutex); return NULL; } /* Wait for the key to be unreserved. */ reservation->waiters++; while (reservation->owner != NULL) g_cond_wait (&reservation->cond, &bag->mutex); reservation->waiters--; /* Check if an object was added by another thread. */ ref = g_hash_table_lookup (bag->object_table, key); if (ref != NULL) { object = g_weak_ref_get (&ref->ref); if (object == NULL) { /* Remove stale reference to dead object. */ g_hash_table_remove (bag->key_table, ref->obj); g_hash_table_remove (bag->object_table, key); } } /* We're not reserving it. */ reservation->owner = g_thread_self (); object_bag_unreserve (bag, key); g_mutex_unlock (&bag->mutex); return object; }
/** * camel_object_bag_reserve: * @bag: a #CamelObjectBag * @key: the key to reserve * * Reserves @key in @bag. If @key is already reserved in another thread, * then wait until the reservation has been committed. * * After reserving @key, you either get a reference to the object * corresponding to @key (similar to camel_object_bag_get()) or you get * %NULL, signifying that you MUST call either camel_object_bag_add() or * camel_object_bag_abort(). * * Returns: the object for @key, or %NULL if @key is not found **/ gpointer camel_object_bag_reserve (CamelObjectBag *bag, gconstpointer key) { KeyReservation *reservation; ObjRef *ref; gpointer object = NULL; g_return_val_if_fail (bag != NULL, NULL); g_return_val_if_fail (key != NULL, NULL); g_mutex_lock (&bag->mutex); /* If object for key already exists, return it immediately. */ ref = g_hash_table_lookup (bag->object_table, key); if (ref != NULL) { object = g_weak_ref_get (&ref->ref); if (object != NULL) { g_mutex_unlock (&bag->mutex); return object; } /* Remove stale reference to dead object. */ g_hash_table_remove (bag->key_table, ref->obj); g_hash_table_remove (bag->object_table, key); } /* If no such key exists in the bag, create a reservation. */ reservation = key_reservation_lookup (bag, key); if (reservation == NULL) { key_reservation_new (bag, key); g_mutex_unlock (&bag->mutex); return NULL; } /* Wait for the reservation to be committed or aborted. */ reservation->waiters++; while (reservation->owner != NULL) g_cond_wait (&reservation->cond, &bag->mutex); reservation->owner = g_thread_self (); reservation->waiters--; /* Check if the object was added by another thread. */ ref = g_hash_table_lookup (bag->object_table, key); if (ref != NULL) { object = g_weak_ref_get (&ref->ref); if (object != NULL) { /* We have an object; no need to reserve the key. */ object_bag_unreserve (bag, key); } else { /* Remove stale reference to dead object. */ g_hash_table_remove (bag->key_table, ref->obj); g_hash_table_remove (bag->object_table, key); } } g_mutex_unlock (&bag->mutex); return object; }
/** * camel_object_bag_add: * @bag: a #CamelObjectBag * @key: a reserved key * @object: a #GObject * * Adds @object to @bag. The @key MUST have been previously reserved using * camel_object_bag_reserve(). **/ void camel_object_bag_add (CamelObjectBag *bag, gconstpointer key, gpointer object) { g_return_if_fail (bag != NULL); g_return_if_fail (key != NULL); g_return_if_fail (G_IS_OBJECT (object)); g_mutex_lock (bag->mutex); if (g_hash_table_lookup (bag->key_table, object) == NULL) { gpointer copied_key; copied_key = bag->key_copy_func (key); g_hash_table_insert (bag->key_table, object, copied_key); g_hash_table_insert (bag->object_table, copied_key, object); object_bag_unreserve (bag, key); g_object_weak_ref ( G_OBJECT (object), (GWeakNotify) object_bag_notify, bag); } g_mutex_unlock (bag->mutex); }
/** * camel_object_bag_abort: * @bag: a #CamelObjectBag * @key: a reserved key * * Aborts a key reservation. **/ void camel_object_bag_abort (CamelObjectBag *bag, gconstpointer key) { g_return_if_fail (bag != NULL); g_return_if_fail (key != NULL); g_mutex_lock (&bag->mutex); object_bag_unreserve (bag, key); g_mutex_unlock (&bag->mutex); }