[telepathy-mission-control/master] McdHandlerMap: new class tracking the relationship between handlers and channels
Simon McVittie
simon.mcvittie at collabora.co.uk
Tue May 26 07:31:00 PDT 2009
---
src/Makefile.am | 2 +
src/mcd-handler-map-priv.h | 84 +++++++++++++
src/mcd-handler-map.c | 278 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 364 insertions(+), 0 deletions(-)
create mode 100644 src/mcd-handler-map-priv.h
create mode 100644 src/mcd-handler-map.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 12828cd..f8c6ae6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -125,6 +125,8 @@ libmissioncontrol_server_la_SOURCES = \
mcd-dispatch-operation-priv.h \
mcd-enum-types.c \
mcd-enum-types.h \
+ mcd-handler-map.c \
+ mcd-handler-map-priv.h \
mcd-signals-marshal.c \
mcd-misc.c \
mcd-misc.h \
diff --git a/src/mcd-handler-map-priv.h b/src/mcd-handler-map-priv.h
new file mode 100644
index 0000000..fdec51a
--- /dev/null
+++ b/src/mcd-handler-map-priv.h
@@ -0,0 +1,84 @@
+/* vi: set et sw=4 ts=8 cino=t0,(0: */
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * Keep track of which handlers own which channels.
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MCD_HANDLER_MAP_H_
+#define MCD_HANDLER_MAP_H_
+
+#include "mcd-channel.h"
+
+G_BEGIN_DECLS
+
+typedef struct _McdHandlerMap McdHandlerMap;
+typedef struct _McdHandlerMapClass McdHandlerMapClass;
+typedef struct _McdHandlerMapPrivate McdHandlerMapPrivate;
+
+GType _mcd_handler_map_get_type (void);
+
+#define MCD_TYPE_HANDLER_MAP \
+ (_mcd_handler_map_get_type ())
+#define MCD_HANDLER_MAP(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), MCD_TYPE_HANDLER_MAP, \
+ McdHandlerMap))
+#define MCD_HANDLER_MAP_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), MCD_TYPE_HANDLER_MAP, \
+ McdHandlerMapClass))
+#define MCD_IS_HANDLER_MAP(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MCD_TYPE_HANDLER_MAP))
+#define MCD_IS_HANDLER_MAP_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), MCD_TYPE_HANDLER_MAP))
+#define MCD_HANDLER_MAP_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), MCD_TYPE_HANDLER_MAP, \
+ McdHandlerMapClass))
+
+struct _McdHandlerMap
+{
+ GObject parent;
+ McdHandlerMapPrivate *priv;
+};
+
+struct _McdHandlerMapClass
+{
+ GObjectClass parent_class;
+};
+
+McdHandlerMap *_mcd_handler_map_new (void);
+
+const gchar *_mcd_handler_map_get_handler (McdHandlerMap *self,
+ const gchar *channel_path);
+
+void _mcd_handler_map_set_path_handled (McdHandlerMap *self,
+ const gchar *channel_path,
+ const gchar *unique_name);
+
+void _mcd_handler_map_set_channel_handled (McdHandlerMap *self,
+ McdChannel *channel,
+ const gchar *unique_name);
+
+void _mcd_handler_map_set_handler_crashed (McdHandlerMap *self,
+ const gchar *unique_name);
+
+G_END_DECLS
+
+#endif
diff --git a/src/mcd-handler-map.c b/src/mcd-handler-map.c
new file mode 100644
index 0000000..d251eb2
--- /dev/null
+++ b/src/mcd-handler-map.c
@@ -0,0 +1,278 @@
+/* vi: set et sw=4 ts=8 cino=t0,(0: */
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * Keep track of which handlers own which channels.
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "mcd-handler-map-priv.h"
+
+#include <telepathy-glib/util.h>
+
+G_DEFINE_TYPE (McdHandlerMap, _mcd_handler_map, G_TYPE_OBJECT);
+
+struct _McdHandlerMapPrivate
+{
+ /* The handler for each channel currently being handled
+ * owned gchar *object_path => owned gchar *unique_name */
+ GHashTable *channel_processes;
+ /* owned gchar *unique_name => malloc'd gsize, number of channels */
+ GHashTable *handler_processes;
+ /* owned gchar *object_path => ref'd TpChannel */
+ GHashTable *handled_channels;
+};
+
+static void
+slice_free_gsize (gpointer p)
+{
+ g_slice_free (gsize, p);
+}
+
+static void
+_mcd_handler_map_init (McdHandlerMap *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MCD_TYPE_HANDLER_MAP,
+ McdHandlerMapPrivate);
+
+ self->priv->channel_processes = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free, g_free);
+
+ self->priv->handler_processes = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ slice_free_gsize);
+
+ self->priv->handled_channels = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+}
+
+static void
+_mcd_handler_map_dispose (GObject *object)
+{
+ McdHandlerMap *self = MCD_HANDLER_MAP (object);
+
+ if (self->priv->handled_channels != NULL)
+ {
+ g_hash_table_destroy (self->priv->handled_channels);
+ self->priv->handled_channels = NULL;
+ }
+
+ G_OBJECT_CLASS (_mcd_handler_map_parent_class)->dispose (object);
+}
+
+static void
+_mcd_handler_map_finalize (GObject *object)
+{
+ McdHandlerMap *self = MCD_HANDLER_MAP (object);
+
+ if (self->priv->channel_processes != NULL)
+ {
+ g_hash_table_destroy (self->priv->channel_processes);
+ self->priv->channel_processes = NULL;
+ }
+
+ if (self->priv->handler_processes != NULL)
+ {
+ g_hash_table_destroy (self->priv->handler_processes);
+ self->priv->handler_processes = NULL;
+ }
+
+ G_OBJECT_CLASS (_mcd_handler_map_parent_class)->finalize (object);
+}
+
+static void
+_mcd_handler_map_class_init (McdHandlerMapClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ g_type_class_add_private (object_class, sizeof (McdHandlerMapPrivate));
+ object_class->dispose = _mcd_handler_map_dispose;
+ object_class->finalize = _mcd_handler_map_finalize;
+}
+
+McdHandlerMap *
+_mcd_handler_map_new (void)
+{
+ return g_object_new (MCD_TYPE_HANDLER_MAP,
+ NULL);
+}
+
+const gchar *
+_mcd_handler_map_get_handler (McdHandlerMap *self,
+ const gchar *channel_path)
+{
+ return g_hash_table_lookup (self->priv->channel_processes, channel_path);
+}
+
+void
+_mcd_handler_map_set_path_handled (McdHandlerMap *self,
+ const gchar *channel_path,
+ const gchar *unique_name)
+{
+ const gchar *old;
+ gsize *counter;
+
+ old = g_hash_table_lookup (self->priv->channel_processes, channel_path);
+
+ if (!tp_strdiff (old, unique_name))
+ {
+ /* no-op - the new handler is the same as the old */
+ return;
+ }
+
+ if (old != NULL)
+ {
+ counter = g_hash_table_lookup (self->priv->handler_processes,
+ old);
+
+ if (--*counter == 0)
+ {
+ g_hash_table_remove (self->priv->handler_processes, old);
+ }
+ }
+
+ g_hash_table_insert (self->priv->channel_processes,
+ g_strdup (channel_path), g_strdup (unique_name));
+
+ counter = g_hash_table_lookup (self->priv->handler_processes,
+ unique_name);
+
+ if (counter == NULL)
+ {
+ counter = g_slice_new0 (gsize);
+ }
+ else
+ {
+ /* take ownership */
+ g_hash_table_steal (self->priv->handler_processes,
+ unique_name);
+ }
+
+ ++*counter;
+
+ g_hash_table_insert (self->priv->handler_processes,
+ g_strdup (unique_name), counter);
+}
+
+static void
+handled_channel_aborted_cb (McdChannel *channel,
+ gpointer user_data)
+{
+ McdHandlerMap *self = MCD_HANDLER_MAP (user_data);
+ const gchar *path = mcd_channel_get_object_path (channel);
+ gchar *handler;
+
+ g_signal_handlers_disconnect_by_func (channel,
+ handled_channel_aborted_cb,
+ user_data);
+
+ handler = g_hash_table_lookup (self->priv->channel_processes, path);
+
+ if (handler != NULL)
+ {
+ gsize *counter = g_hash_table_lookup (self->priv->handler_processes,
+ handler);
+
+ g_assert (counter != NULL);
+
+ if (--*counter == 0)
+ {
+ g_hash_table_remove (self->priv->handler_processes, handler);
+ }
+
+ g_hash_table_remove (self->priv->channel_processes, path);
+ }
+
+ g_hash_table_remove (self->priv->handled_channels, path);
+
+ g_object_unref (self);
+}
+
+void
+_mcd_handler_map_set_channel_handled (McdHandlerMap *self,
+ McdChannel *channel,
+ const gchar *unique_name)
+{
+ const gchar *path = mcd_channel_get_object_path (channel);
+
+ g_hash_table_insert (self->priv->handled_channels,
+ g_strdup (path),
+ g_object_ref (channel));
+
+ g_signal_connect (channel, "abort",
+ G_CALLBACK (handled_channel_aborted_cb),
+ g_object_ref (self));
+
+ _mcd_handler_map_set_path_handled (self, path, unique_name);
+}
+
+void
+_mcd_handler_map_set_handler_crashed (McdHandlerMap *self,
+ const gchar *unique_name)
+{
+ gsize *counter = g_hash_table_lookup (self->priv->handler_processes,
+ unique_name);
+
+ if (counter != NULL)
+ {
+ GHashTableIter iter;
+ gpointer path_p, name_p;
+ GList *paths = NULL;
+
+ g_hash_table_remove (self->priv->handler_processes, unique_name);
+
+ /* This is O(number of channels being handled) but then again
+ * it only happens if a handler crashes */
+ g_hash_table_iter_init (&iter, self->priv->channel_processes);
+
+ while (g_hash_table_iter_next (&iter, &path_p, &name_p))
+ {
+ DEBUG ("%s lost its handler %s", (const gchar *) path_p,
+ (const gchar *) name_p);
+ paths = g_list_prepend (paths, g_strdup (path_p));
+ g_hash_table_iter_remove (&iter);
+ }
+
+ while (paths != NULL)
+ {
+ gchar *path = paths->data;
+ McdChannel *channel = g_hash_table_lookup (
+ self->priv->handled_channels, path);
+
+ if (channel != NULL)
+ {
+ DEBUG ("Aborting channel %s", path);
+ mcd_mission_abort ((McdMission *) channel);
+ }
+ else
+ {
+ DEBUG ("No McdChannel for %s, not aborting it", path);
+ }
+
+ paths = g_list_delete_link (paths, paths);
+ g_free (path);
+ }
+ }
+}
--
1.5.6.5
More information about the telepathy-commits
mailing list