summaryrefslogtreecommitdiffstats
path: root/source/xap/xsane/xsane-0.999-signal-handling.patch
diff options
context:
space:
mode:
Diffstat (limited to 'source/xap/xsane/xsane-0.999-signal-handling.patch')
-rw-r--r--source/xap/xsane/xsane-0.999-signal-handling.patch242
1 files changed, 242 insertions, 0 deletions
diff --git a/source/xap/xsane/xsane-0.999-signal-handling.patch b/source/xap/xsane/xsane-0.999-signal-handling.patch
new file mode 100644
index 000000000..b9da71a1e
--- /dev/null
+++ b/source/xap/xsane/xsane-0.999-signal-handling.patch
@@ -0,0 +1,242 @@
+From 3b5d3b7e1f320b0bfbe48024a586c0a22375aa2d Mon Sep 17 00:00:00 2001
+From: Nils Philippsen <nils@redhat.com>
+Date: Thu, 3 Jul 2014 10:38:03 +0200
+Subject: [PATCH] patch: signal-handling
+
+Squashed commit of the following:
+
+commit 1e9e8cf5edc469114c8eadf46817cd5c1261b35c
+Author: Nils Philippsen <nils@redhat.com>
+Date: Thu Jul 3 10:14:52 2014 +0200
+
+ don't use g_unix_open_pipe(), g_unix_fd_add()
+
+ These functions have only recently been added to glib. Use pipe()/
+ fcntl() and g_io_channel_unix_new()/g_io_add_watch() instead which are
+ available in the minimum glib version needed for gtk+-2.x.
+
+commit acbdf3f693d3d2a78ee7490ca1bf76957daf00cf
+Author: Nils Philippsen <nils@redhat.com>
+Date: Thu Mar 13 13:38:12 2014 +0100
+
+ separate signal handlers in top and bottom half
+
+ This is to avoid race-conditions occurring when a signal is received
+ while the signal handler is not yet finished. It also avoids calling
+ non-reentrant functions from a signal handler. The top half (the real
+ signal handler) just writes a character into a pipe which gets picked up
+ and serviced by the bottom half from the normal event loop, this
+ serializes things and makes using non-reentrant functions safe.
+---
+ src/xsane.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 136 insertions(+), 15 deletions(-)
+
+diff --git a/src/xsane.c b/src/xsane.c
+index 2b9211b..fc2ebbe 100644
+--- a/src/xsane.c
++++ b/src/xsane.c
+@@ -47,6 +47,7 @@
+ #endif
+
+ #include <sys/wait.h>
++#include <glib-unix.h>
+
+ #include <stdarg.h>
+
+@@ -121,6 +122,7 @@ static const Preferences_medium_t pref_default_medium[]=
+
+ int DBG_LEVEL = 0;
+ static guint xsane_resolution_timer = 0;
++static int xsane_signal_pipe[2];
+
+ /* ---------------------------------------------------------------------------------------------------------------------- */
+
+@@ -161,8 +163,11 @@ void xsane_pref_save(void);
+ static int xsane_pref_restore(void);
+ static void xsane_pref_save_media(void);
+ static void xsane_pref_restore_media(void);
+-static RETSIGTYPE xsane_quit_handler(int signal);
+-static RETSIGTYPE xsane_sigchld_handler(int signal);
++static RETSIGTYPE xsane_signal_handler_top_half(int signal);
++static gboolean xsane_signal_handler_bottom_half(GIOChannel *source,
++ GIOCondition condition,
++ gpointer user_data);
++static void xsane_sigchld_handler(void);
+ static void xsane_quit(void);
+ static void xsane_exit(void);
+ static gint xsane_standard_option_win_delete(GtkWidget *widget, gpointer data);
+@@ -2296,16 +2301,119 @@ static void xsane_pref_restore_media(void)
+
+ /* ---------------------------------------------------------------------------------------------------------------------- */
+
+-static RETSIGTYPE xsane_quit_handler(int signal)
++static RETSIGTYPE xsane_signal_handler_top_half(int signal)
+ {
+- DBG(DBG_proc, "xsane_quit_handler\n");
++ const char *msg_func = "xsane_signal_handler_top_half(): ";
++ const char *msg_short_write = "Short write() while processing signal.\n";
++ const char *msg_err = "Error during write().\n";
++ char sig_char;
++ ssize_t written;
++ int errno_saved = errno;
+
+- xsane_quit();
++ switch (signal)
++ {
++ case SIGTERM:
++ sig_char = 't';
++ break;
++ case SIGINT:
++ sig_char = 'i';
++ break;
++ case SIGHUP:
++ sig_char = 'h';
++ break;
++ case SIGCHLD:
++ sig_char = 'c';
++ break;
++ default:
++ sig_char = '?';
++ break;
++ }
++
++ if ((written = write(xsane_signal_pipe[1], &sig_char, 1)) <= 0)
++ {
++ /* At this point, all bets are off. Salvage what we can. */
++
++ const char *msg = (written == 0) ? msg_short_write : msg_err;
++
++ if ((write(STDERR_FILENO, msg_func, strlen(msg_func)) < 0) ||
++ (write(STDERR_FILENO, msg, strlen(msg)) < 0))
++ {
++ /* This is really a no-op, but at this point it doesn't really matter
++ * anymore if the writes succeeded or not. */
++ goto bail_out;
++ }
++
++bail_out:
++ /* Ignore SIGCHLD errors, zombie processes don't hurt that much. */
++ if (signal != SIGCHLD)
++ {
++ struct SIGACTION act;
++ memset(&act, 0, sizeof(act));
++ act.sa_handler = SIG_DFL;
++ sigaction(signal, &act, NULL);
++ raise(signal);
++ }
++ }
++
++ errno = errno_saved;
++}
++
++static gboolean xsane_signal_handler_bottom_half(GIOChannel *source,
++ GIOCondition condition,
++ gpointer user_data)
++{
++ char sig_char;
++ ssize_t readlen;
++
++ DBG(DBG_proc, "xsane_signal_handler_bottom_half\n");
++
++ while ((readlen = read(xsane_signal_pipe[0], &sig_char, 1)) != 0)
++ {
++ if (readlen < 0)
++ {
++ if (errno == EINTR)
++ {
++ /* if interrupted by signal, just repeat reading */
++ continue;
++ }
++ else
++ {
++ break;
++ }
++ }
++
++ switch (sig_char)
++ {
++ case 't':
++ case 'i':
++ case 'h':
++ xsane_quit();
++ break;
++ case 'c':
++ xsane_sigchld_handler();
++ break;
++ default:
++ DBG(DBG_error,
++ "Don't know how to cope with character-encoded signal: '%c'\n",
++ sig_char);
++ break;
++ }
++ }
++
++ /* previous invocation might have read more than it should, so ignore
++ * EAGAIN/EWOULDBLOCK */
++ if (readlen < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
++ {
++ DBG(DBG_error, "Error while reading from pipe: %d '%s'\n", errno,
++ strerror(errno));
++ }
++
++ return TRUE;
+ }
+
+ /* ---------------------------------------------------------------------------------------------------------------------- */
+
+-static RETSIGTYPE xsane_sigchld_handler(int signal)
++static void xsane_sigchld_handler(void)
+ {
+ int status;
+ XsaneChildprocess **childprocess_listptr = &xsane.childprocess_list;
+@@ -6026,6 +6134,8 @@ void xsane_interface(int argc, char **argv)
+ {
+ struct SIGACTION act;
+
++ GIOChannel *gio_pipe_read;
++
+ DBG(DBG_proc, "xsane_interface\n");
+
+ xsane.info_label = NULL;
+@@ -6069,18 +6179,29 @@ void xsane_interface(int argc, char **argv)
+ }
+ }
+
++ if ((pipe(xsane_signal_pipe) == -1) ||
++ (fcntl(xsane_signal_pipe[0], F_SETFD, FD_CLOEXEC) == -1) ||
++ (fcntl(xsane_signal_pipe[0], F_SETFL, O_NONBLOCK) == -1) ||
++ (fcntl(xsane_signal_pipe[1], F_SETFD, FD_CLOEXEC) == -1) ||
++ (fcntl(xsane_signal_pipe[1], F_SETFL, O_NONBLOCK) == -1) ||
++ !(gio_pipe_read = g_io_channel_unix_new(xsane_signal_pipe[0])) ||
++ !g_io_add_watch(gio_pipe_read, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
++ xsane_signal_handler_bottom_half, NULL))
++ {
++ DBG(DBG_error,
++ "Couldn't create signal handling pipe, set flags on it or install\n"
++ "bottom half of handler.\n");
++ exit(1);
++ }
++
+ /* define SIGTERM, SIGINT, SIGHUP-handler to make sure that e.g. all temporary files are deleted */
+ /* when xsane gets such a signal */
+ memset(&act, 0, sizeof(act));
+- act.sa_handler = xsane_quit_handler;
+- sigaction(SIGTERM, &act, 0);
+- sigaction(SIGINT, &act, 0);
+- sigaction(SIGHUP, &act, 0);
+-
+- /* add a signal handler that cleans up zombie child processes */
+- memset(&act, 0, sizeof(act));
+- act.sa_handler = xsane_sigchld_handler;
+- sigaction(SIGCHLD, &act, 0);
++ act.sa_handler = xsane_signal_handler_top_half;
++ sigaction(SIGTERM, &act, NULL);
++ sigaction(SIGINT, &act, NULL);
++ sigaction(SIGHUP, &act, NULL);
++ sigaction(SIGCHLD, &act, NULL);
+
+ gtk_main();
+ sane_exit();
+--
+1.9.3
+