diff options
author | William Jon McCann <mccann@jhu.edu> | 2007-10-19 17:26:23 +0000 |
---|---|---|
committer | William Jon McCann <mccann@src.gnome.org> | 2007-10-19 17:26:23 +0000 |
commit | 3a8578103249134717574921c3d142bab4d6df94 (patch) | |
tree | c22f6c7a329a2230fa72deb6c12bc414a20a74ea /common | |
parent | 365092a43a92b57723297f5bdaad3375aa1efdde (diff) | |
download | gdm-3a8578103249134717574921c3d142bab4d6df94.tar.gz |
Assign ids to signal handlers. Add functions to remove handlers. Restore
2007-10-19 William Jon McCann <mccann@jhu.edu>
* common/gdm-signal-handler.c: (signal_io_watch), (catch_signal),
(uncatch_signal), (gdm_signal_handler_add), (callback_data_free),
(gdm_signal_handler_remove_and_free_data),
(gdm_signal_handler_remove), (find_callback_data_by_func),
(gdm_signal_handler_remove_func), (signal_list_free),
(gdm_signal_handler_init), (gdm_signal_handler_finalize):
* common/gdm-signal-handler.h:
* daemon/gdm-server.c: (add_ready_handler), (remove_ready_handler),
(gdm_server_spawn), (gdm_server_init), (gdm_server_finalize):
Assign ids to signal handlers. Add functions to remove handlers.
Restore sigaction when no handlers are present. Fix some
memory management bugs.
svn path=/trunk/; revision=5386
Diffstat (limited to 'common')
-rw-r--r-- | common/gdm-signal-handler.c | 178 | ||||
-rw-r--r-- | common/gdm-signal-handler.h | 9 |
2 files changed, 170 insertions, 17 deletions
diff --git a/common/gdm-signal-handler.c b/common/gdm-signal-handler.c index 151c986f..642ffa0a 100644 --- a/common/gdm-signal-handler.c +++ b/common/gdm-signal-handler.c @@ -42,14 +42,19 @@ #define GDM_SIGNAL_HANDLER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SIGNAL_HANDLER, GdmSignalHandlerPrivate)) typedef struct { + int signal_number; GdmSignalHandlerFunc func; gpointer data; + guint id; } CallbackData; struct GdmSignalHandlerPrivate { GMainLoop *main_loop; GHashTable *lookup; + GHashTable *id_lookup; + GHashTable *action_lookup; + guint next_id; }; static void gdm_signal_handler_class_init (GdmSignalHandlerClass *klass); @@ -98,6 +103,8 @@ signal_io_watch (GIOChannel *ioc, gsize bytes_read; int i; + g_debug ("SIGNAL"); + block_signals_push (); g_io_channel_read_chars (ioc, buf, sizeof (buf), &bytes_read, NULL); @@ -121,11 +128,13 @@ signal_io_watch (GIOChannel *ioc, gboolean res; CallbackData *data; - data = l->data; - g_debug ("running %d handler: %p", signum, data->func); - res = data->func (signum, data->data); - if (! res) { - is_fatal = TRUE; + data = g_hash_table_lookup (handler->priv->id_lookup, l->data); + if (data != NULL) { + g_debug ("running %d handler: %p", signum, data->func); + res = data->func (signum, data->data); + if (! res) { + is_fatal = TRUE; + } } } } @@ -253,17 +262,43 @@ static void catch_signal (GdmSignalHandler *handler, int signal_number) { - struct sigaction action; + struct sigaction action; + struct sigaction *old_action; + + g_debug ("Registering for %d signals", signal_number); action.sa_handler = signal_handler; sigemptyset (&action.sa_mask); action.sa_flags = 0; - /* FIXME: save old action? */ - sigaction (signal_number, &action, NULL); + old_action = g_new0 (struct sigaction, 1); + + sigaction (signal_number, &action, old_action); + + g_hash_table_insert (handler->priv->action_lookup, + GINT_TO_POINTER (signal_number), + old_action); } -void +static void +uncatch_signal (GdmSignalHandler *handler, + int signal_number) +{ + struct sigaction *old_action; + + g_debug ("Unregistering for %d signals", signal_number); + + old_action = g_hash_table_lookup (handler->priv->action_lookup, + GINT_TO_POINTER (signal_number)); + g_hash_table_remove (handler->priv->action_lookup, + GINT_TO_POINTER (signal_number)); + + sigaction (signal_number, old_action, NULL); + + g_free (old_action); +} + +guint gdm_signal_handler_add (GdmSignalHandler *handler, int signal_number, GdmSignalHandlerFunc callback, @@ -272,20 +307,123 @@ gdm_signal_handler_add (GdmSignalHandler *handler, CallbackData *cdata; GSList *list; - g_return_if_fail (GDM_IS_SIGNAL_HANDLER (handler)); + g_return_val_if_fail (GDM_IS_SIGNAL_HANDLER (handler), 0); cdata = g_new0 (CallbackData, 1); + cdata->signal_number = signal_number; cdata->func = callback; cdata->data = data; + cdata->id = handler->priv->next_id++; - list = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (signal_number)); - if (list == NULL) { + g_debug ("Adding handler %u: signum=%d %p", cdata->id, cdata->signal_number, cdata->func); + + if (g_hash_table_lookup (handler->priv->action_lookup, GINT_TO_POINTER (signal_number)) == NULL) { catch_signal (handler, signal_number); } - list = g_slist_prepend (list, cdata); - g_debug ("Inserting %d callback %p", signal_number, cdata->func); + /* ID lookup owns the CallbackData */ + g_hash_table_insert (handler->priv->id_lookup, GUINT_TO_POINTER (cdata->id), cdata); + + list = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (signal_number)); + list = g_slist_prepend (list, GUINT_TO_POINTER (cdata->id)); + g_hash_table_insert (handler->priv->lookup, GINT_TO_POINTER (signal_number), list); + + return cdata->id; +} + +static void +callback_data_free (CallbackData *d) +{ + g_free (d); +} + +static void +gdm_signal_handler_remove_and_free_data (GdmSignalHandler *handler, + CallbackData *cdata) +{ + GSList *list; + + g_return_if_fail (GDM_IS_SIGNAL_HANDLER (handler)); + + list = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (cdata->signal_number)); + list = g_slist_remove_all (list, GUINT_TO_POINTER (cdata->id)); + if (list == NULL) { + uncatch_signal (handler, cdata->signal_number); + } + + g_debug ("Removing handler %u: signum=%d %p", cdata->signal_number, cdata->id, cdata->func); + /* put changed list back in */ + g_hash_table_insert (handler->priv->lookup, GINT_TO_POINTER (cdata->signal_number), list); + + g_hash_table_remove (handler->priv->id_lookup, GUINT_TO_POINTER (cdata->id)); +} + +void +gdm_signal_handler_remove (GdmSignalHandler *handler, + guint id) +{ + CallbackData *found; + + g_return_if_fail (GDM_IS_SIGNAL_HANDLER (handler)); + + found = g_hash_table_lookup (handler->priv->id_lookup, GUINT_TO_POINTER (id)); + if (found != NULL) { + gdm_signal_handler_remove_and_free_data (handler, found); + found = NULL; + } +} + +static CallbackData * +find_callback_data_by_func (GdmSignalHandler *handler, + guint signal_number, + GdmSignalHandlerFunc callback, + gpointer data) +{ + GSList *list; + GSList *l; + CallbackData *found; + + found = NULL; + + list = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (signal_number)); + + for (l = list; l != NULL; l = l->next) { + guint id; + CallbackData *d; + + id = GPOINTER_TO_UINT (l->data); + + d = g_hash_table_lookup (handler->priv->id_lookup, GUINT_TO_POINTER (id)); + if (d != NULL + && d->func == callback + && d->data == data) { + found = d; + break; + } + } + + return found; +} + +void +gdm_signal_handler_remove_func (GdmSignalHandler *handler, + guint signal_number, + GdmSignalHandlerFunc callback, + gpointer data) +{ + CallbackData *found; + + g_return_if_fail (GDM_IS_SIGNAL_HANDLER (handler)); + + found = find_callback_data_by_func (handler, signal_number, callback, data); + + if (found != NULL) { + gdm_signal_handler_remove_and_free_data (handler, found); + found = NULL; + } + + /* FIXME: once all handlers are removed deregister signum handler */ } static void @@ -301,7 +439,6 @@ gdm_signal_handler_class_init (GdmSignalHandlerClass *klass) static void signal_list_free (GSList *list) { - g_slist_foreach (list, (GFunc)g_free, NULL); g_slist_free (list); } @@ -322,10 +459,18 @@ gdm_signal_handler_init (GdmSignalHandler *handler) handler->priv = GDM_SIGNAL_HANDLER_GET_PRIVATE (handler); + handler->priv->next_id = 1; + handler->priv->lookup = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)signal_list_free); + handler->priv->id_lookup = g_hash_table_new_full (NULL, + NULL, + NULL, + (GDestroyNotify)callback_data_free); + + handler->priv->action_lookup = g_hash_table_new (NULL, NULL); if (pipe (signal_pipes) == -1) { g_error ("Could not create pipe() for signal handling"); @@ -352,8 +497,9 @@ gdm_signal_handler_finalize (GObject *object) g_return_if_fail (handler->priv != NULL); - /* FIXME: free hash lists */ g_hash_table_destroy (handler->priv->lookup); + g_hash_table_destroy (handler->priv->id_lookup); + g_hash_table_destroy (handler->priv->action_lookup); G_OBJECT_CLASS (gdm_signal_handler_parent_class)->finalize (object); } diff --git a/common/gdm-signal-handler.h b/common/gdm-signal-handler.h index f29d5625..609ef17e 100644 --- a/common/gdm-signal-handler.h +++ b/common/gdm-signal-handler.h @@ -56,10 +56,17 @@ GdmSignalHandler * gdm_signal_handler_new (void); void gdm_signal_handler_set_main_loop (GdmSignalHandler *handler, GMainLoop *main_loop); -void gdm_signal_handler_add (GdmSignalHandler *handler, +guint gdm_signal_handler_add (GdmSignalHandler *handler, int signal_number, GdmSignalHandlerFunc callback, gpointer data); +void gdm_signal_handler_remove (GdmSignalHandler *handler, + guint id); +void gdm_signal_handler_remove_func (GdmSignalHandler *handler, + guint signal_number, + GdmSignalHandlerFunc callback, + gpointer data); + G_END_DECLS |