[Telepathy-commits] [telepathy-glib/master] connection-handles: Don't forget handles until *all* TpConnections sharing a bucket have been invalidated
Simon McVittie
simon.mcvittie at collabora.co.uk
Tue Oct 7 08:56:09 PDT 2008
TpConnection emits invalidated when it runs out of refs, so this is
necessary for correct sharing of buckets.
---
telepathy-glib/connection-handles.c | 92 +++++++++++++++++++++++++++------
telepathy-glib/connection-internal.h | 1 +
telepathy-glib/connection.c | 2 +
3 files changed, 78 insertions(+), 17 deletions(-)
diff --git a/telepathy-glib/connection-handles.c b/telepathy-glib/connection-handles.c
index a1b9064..452275d 100644
--- a/telepathy-glib/connection-handles.c
+++ b/telepathy-glib/connection-handles.c
@@ -39,7 +39,10 @@
*/
typedef struct {
- GHashTable *refcounts[NUM_TP_HANDLE_TYPES];
+ /* number of TpConnection objects sharing this bucket */
+ gsize refcount;
+ /* guint handle => gsize refcount */
+ GHashTable *handle_refs[NUM_TP_HANDLE_TYPES];
} Bucket;
static inline void oom (void) G_GNUC_NORETURN;
@@ -57,12 +60,12 @@ bucket_free (gpointer p)
guint i;
/* [0] is never allocated (handle type NONE), so start at [1] */
- g_assert (b->refcounts[0] == NULL);
+ g_assert (b->handle_refs[0] == NULL);
for (i = 1; i < NUM_TP_HANDLE_TYPES; i++)
{
- if (b->refcounts[i] != NULL)
- g_hash_table_destroy (b->refcounts[i]);
+ if (b->handle_refs[i] != NULL)
+ g_hash_table_destroy (b->handle_refs[i]);
}
g_slice_free (Bucket, p);
@@ -71,7 +74,10 @@ bucket_free (gpointer p)
static Bucket *
bucket_new (void)
{
- return g_slice_new0 (Bucket);
+ Bucket *b = g_slice_new0 (Bucket);
+ b->refcount = 1;
+
+ return b;
}
static dbus_int32_t connection_handle_refs_slot = -1;
@@ -84,7 +90,7 @@ _tp_connection_ref_handles (TpConnection *connection,
TpProxy *as_proxy = (TpProxy *) connection;
DBusGConnection *g_connection = as_proxy->dbus_connection;
const gchar *object_path = as_proxy->object_path;
- GHashTable *table, *refcounts;
+ GHashTable *table, *handle_refs;
Bucket *bucket = NULL;
guint i;
@@ -122,18 +128,18 @@ _tp_connection_ref_handles (TpConnection *connection,
g_hash_table_insert (table, g_strdup (object_path), bucket);
}
- if (bucket->refcounts[handle_type] == NULL)
- bucket->refcounts[handle_type] = g_hash_table_new (g_direct_hash,
+ if (bucket->handle_refs[handle_type] == NULL)
+ bucket->handle_refs[handle_type] = g_hash_table_new (g_direct_hash,
g_direct_equal);
- refcounts = bucket->refcounts[handle_type];
+ handle_refs = bucket->handle_refs[handle_type];
for (i = 0; i < handles->len; i++)
{
gpointer handle = GUINT_TO_POINTER (g_array_index (handles, guint, i));
- gsize r = GPOINTER_TO_SIZE (g_hash_table_lookup (refcounts, handle));
+ gsize r = GPOINTER_TO_SIZE (g_hash_table_lookup (handle_refs, handle));
- g_hash_table_insert (refcounts, handle, GSIZE_TO_POINTER (r + 1));
+ g_hash_table_insert (handle_refs, handle, GSIZE_TO_POINTER (r + 1));
}
}
@@ -173,6 +179,52 @@ array_free_TRUE (gpointer p)
}
+void
+_tp_connection_init_handle_refs (TpConnection *self)
+{
+ TpProxy *as_proxy = (TpProxy *) self;
+ DBusGConnection *g_connection = as_proxy->dbus_connection;
+ const gchar *object_path = as_proxy->object_path;
+ GHashTable *table;
+ Bucket *bucket = NULL;
+
+ g_assert (as_proxy->invalidated == NULL);
+
+ /* MT: libdbus protects us, if so configured */
+ if (!dbus_connection_allocate_data_slot (&connection_handle_refs_slot))
+ oom ();
+
+ /* MT: if we become thread safe, the rest of this function needs a lock */
+ table = dbus_connection_get_data (dbus_g_connection_get_connection (
+ g_connection), connection_handle_refs_slot);
+
+ if (table == NULL)
+ {
+ table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+ bucket_free);
+
+ if (!dbus_connection_set_data (dbus_g_connection_get_connection (
+ g_connection), connection_handle_refs_slot, table,
+ (DBusFreeFunction) g_hash_table_destroy))
+ oom ();
+ }
+ else
+ {
+ bucket = g_hash_table_lookup (table, object_path);
+ }
+
+ if (bucket == NULL)
+ {
+ bucket = bucket_new ();
+ g_hash_table_insert (table, g_strdup (object_path), bucket);
+ }
+ else
+ {
+ bucket->refcount++;
+ }
+}
+
+
/* Clean up after the connection is invalidated */
void
_tp_connection_clean_up_handle_refs (TpConnection *self)
@@ -181,6 +233,7 @@ _tp_connection_clean_up_handle_refs (TpConnection *self)
DBusGConnection *g_connection = as_proxy->dbus_connection;
const gchar *object_path = as_proxy->object_path;
GHashTable *table;
+ Bucket *bucket;
DEBUG ("%p", self);
@@ -196,6 +249,11 @@ _tp_connection_clean_up_handle_refs (TpConnection *self)
if (table == NULL)
return;
+ bucket = g_hash_table_lookup (table, object_path);
+
+ if ((--bucket->refcount) > 0)
+ return;
+
if (g_hash_table_remove (table, object_path) &&
g_hash_table_size (table) == 0)
{
@@ -225,7 +283,7 @@ tp_connection_unref_handles (TpConnection *self,
TpProxy *as_proxy = (TpProxy *) self;
DBusGConnection *g_connection = as_proxy->dbus_connection;
const gchar *object_path = as_proxy->object_path;
- GHashTable *table, *refcounts;
+ GHashTable *table, *handle_refs;
Bucket *bucket = NULL;
guint i;
GArray *unref;
@@ -256,16 +314,16 @@ tp_connection_unref_handles (TpConnection *self,
/* if there's no bucket, then we can't have a ref to the handles -
* user error */
g_return_if_fail (bucket != NULL);
- g_return_if_fail (bucket->refcounts[handle_type] != NULL);
+ g_return_if_fail (bucket->handle_refs[handle_type] != NULL);
- refcounts = bucket->refcounts[handle_type];
+ handle_refs = bucket->handle_refs[handle_type];
unref = g_array_sized_new (FALSE, FALSE, sizeof (guint), n_handles);
for (i = 0; i < n_handles; i++)
{
gpointer handle = GUINT_TO_POINTER (handles[i]);
- gsize r = GPOINTER_TO_SIZE (g_hash_table_lookup (refcounts, handle));
+ gsize r = GPOINTER_TO_SIZE (g_hash_table_lookup (handle_refs, handle));
g_return_if_fail (handles[i] != 0);
/* if we have no refs, it's user error */
@@ -275,13 +333,13 @@ tp_connection_unref_handles (TpConnection *self,
{
DEBUG ("releasing handle %u", handles[i]);
g_array_append_val (unref, handles[i]);
- g_hash_table_remove (refcounts, handle);
+ g_hash_table_remove (handle_refs, handle);
}
else
{
DEBUG ("decrementing handle %u to %" G_GSIZE_FORMAT, handles[i],
r - 1);
- g_hash_table_insert (refcounts, handle, GSIZE_TO_POINTER (r - 1));
+ g_hash_table_insert (handle_refs, handle, GSIZE_TO_POINTER (r - 1));
}
}
diff --git a/telepathy-glib/connection-internal.h b/telepathy-glib/connection-internal.h
index 11f17cd..eb77464 100644
--- a/telepathy-glib/connection-internal.h
+++ b/telepathy-glib/connection-internal.h
@@ -29,6 +29,7 @@ G_BEGIN_DECLS
const GArray *_tp_connection_get_contact_attribute_interfaces (
TpConnection *self);
+void _tp_connection_init_handle_refs (TpConnection *self);
void _tp_connection_clean_up_handle_refs (TpConnection *self);
G_END_DECLS
diff --git a/telepathy-glib/connection.c b/telepathy-glib/connection.c
index 4f45f1c..226d643 100644
--- a/telepathy-glib/connection.c
+++ b/telepathy-glib/connection.c
@@ -460,6 +460,8 @@ tp_connection_constructor (GType type,
tp_cli_connection_call_get_status (self, -1,
tp_connection_got_status_cb, NULL, NULL, NULL);
+ _tp_connection_init_handle_refs (self);
+
g_signal_connect (self, "invalidated",
G_CALLBACK (_tp_connection_clean_up_handle_refs), NULL);
--
1.5.6.5
More information about the Telepathy-commits
mailing list