diff options
author | Søren Sandmann Pedersen <ssp@dhcp-100-2-40.bos.redhat.com> | 2009-04-12 19:54:00 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@dhcp-100-2-40.bos.redhat.com> | 2009-04-12 19:54:00 -0400 |
commit | fd7007163770f5f5bb7ef699a5c4ee153958b441 (patch) | |
tree | ade87f9fd77cec9b9b6187e785332edb4332eabb | |
parent | 85f4a3cd9d01eef1b280fc17f392612fb960fd45 (diff) |
Add signal handling
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | libnul.h | 11 | ||||
-rw-r--r-- | signal-handler.c | 219 | ||||
-rw-r--r-- | signal-handler.h | 27 |
5 files changed, 261 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index deed62c..4273d74 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,6 +8,7 @@ libnul_la_SOURCES = \ dbus.c \ array.c \ epoll.c \ + signal-handler.c \ libnul.h clean-local: @@ -1,3 +1,6 @@ +- handle the case where objects are just '/'. Currently they fail in invoke + with "failed to find object ''" + nul_dbus_service_start() should likely take a data parameter to distinguish multiple instances of the same service. Method callbacks will need to know this information. How does this work given the @@ -244,6 +244,17 @@ void nul_fd_set_poll_handler (int fd, void nul_fd_remove_watch (int fd); gboolean nul_fd_is_watched (int fd); +/* + * Unix signal handlers + */ +typedef void (* signal_func_t) (int signo, gpointer data); + +/* FIXME: error out is required */ +gboolean nul_signal_set_handler (int signo, + signal_func_t handler, + gpointer data, + GError **err); + /* Implementing a service */ typedef struct nul_dbus_service_t nul_dbus_service_t; diff --git a/signal-handler.c b/signal-handler.c new file mode 100644 index 0000000..01cf8c8 --- /dev/null +++ b/signal-handler.c @@ -0,0 +1,219 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- */ + +/* Sysprof -- Sampling, systemwide CPU profiler + * Copyright (C) 2005 Søren Sandmann (sandmann@daimi.au.dk) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <signal.h> +#include <unistd.h> +#include <string.h> +#include "libnul.h" + +typedef struct signal_watch_t signal_watch_t; +struct signal_watch_t +{ + int signo; + signal_func_t handler; + gpointer user_data; + + struct sigaction old_action; + + signal_watch_t * next; +}; + +static int read_end = -1; +static int write_end = -1; +static signal_watch_t *signal_watch_tes = NULL; + +static signal_watch_t * +lookup_signal_watch_t (int signo) +{ + signal_watch_t *w; + + for (w = signal_watch_tes; w != NULL; w = w->next) + { + if (w->signo == signo) + return w; + } + + return NULL; +} + +static void +remove_signal_watch_t (signal_watch_t *watch) +{ + signal_watch_t *prev, *w; + + g_return_if_fail (watch != NULL); + + prev = NULL; + for (w = signal_watch_tes; w != NULL; w = w->next) + { + if (w == watch) + { + if (prev) + prev->next = w->next; + else + signal_watch_tes = w->next; + + break; + } + + prev = w; + } +} + +static void +signal_handler (int signo, + siginfo_t *info, + void *data) +{ + /* FIXME: I suppose we should handle short + * and non-successful writes ... + * + * And also, there is a deadlock if so many signals arrive that + * write() blocks. Then we will be stuck right here, and the + * main loop will never run. Kinda hard to fix without dropping + * signals ... + * + */ + write (write_end, &signo, sizeof (int)); +} + +static void +on_read (gpointer data) +{ + signal_watch_t *watch; + int signo; + + /* FIXME: handle short read I suppose */ + read (read_end, &signo, sizeof (int)); + + watch = lookup_signal_watch_t (signo); + + if (watch) + watch->handler (signo, watch->user_data); +} + +static gboolean +create_pipe (int *read_end, + int *write_end, + GError **err) +{ + int p[2]; + + if (pipe (p) < 0) + { + /* FIXME - create an error */ + return FALSE; + } + + /* FIXME: We should probably make the fd's non-blocking */ + if (read_end) + *read_end = p[0]; + + if (write_end) + *write_end = p[1]; + + return TRUE; +} + +static gboolean +install_signal_handler (int signo, + struct sigaction *old_action, + GError **err) +{ + struct sigaction action; + + memset (&action, 0, sizeof (action)); + + action.sa_sigaction = signal_handler; + sigemptyset (&action.sa_mask); + action.sa_flags = SA_SIGINFO; + + if (sigaction (signo, &action, old_action) < 0) + { + /* FIXME - create an error */ + return TRUE; + } + + return TRUE; +} + +static void +signal_watch_free (signal_watch_t *watch) +{ + remove_signal_watch_t (watch); + + g_free (watch); +} + +gboolean +nul_signal_set_handler (int signo, + signal_func_t handler, + gpointer data, + GError **err) +{ + signal_watch_t *watch; + + g_return_val_if_fail (handler == NULL || + lookup_signal_watch_t (signo) == NULL, FALSE); + + if (handler == NULL) + { + watch = lookup_signal_watch_t (signo); + + if (watch) + { + /* FIXME: error */ + sigaction (signo, &watch->old_action, NULL); + + signal_watch_free (watch); + + return TRUE; + } + } + else + { + if (read_end == -1) + { + if (!create_pipe (&read_end, &write_end, err)) + return FALSE; + + nul_fd_add_watch (read_end, NULL); + nul_fd_set_read_callback (read_end, on_read); + } + + watch = g_new0 (signal_watch_t, 1); + + watch->signo = signo; + watch->handler = handler; + watch->user_data = data; + watch->next = signal_watch_tes; + signal_watch_tes = watch; + + if (!install_signal_handler (signo, &watch->old_action, err)) + { + signal_watch_free (watch); + + return FALSE; + } + + return TRUE; + } +} + diff --git a/signal-handler.h b/signal-handler.h new file mode 100644 index 0000000..44f3dde --- /dev/null +++ b/signal-handler.h @@ -0,0 +1,27 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- */ + +/* Sysprof -- Sampling, systemwide CPU profiler + * Copyright (C) 2005 Søren Sandmann (sandmann@daimi.au.dk) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +typedef void (* SignalFunc) (int signo, gpointer data); + +gboolean signal_set_handler (int signo, + SignalFunc handler, + gpointer data, + GError **err); +void signal_unset_handler (int signo); |