1 From 3b5d3b7e1f320b0bfbe48024a586c0a22375aa2d Mon Sep 17 00:00:00 2001
2 From: Nils Philippsen <nils@redhat.com>
3 Date: Thu, 3 Jul 2014 10:38:03 +0200
4 Subject: [PATCH] patch: signal-handling
6 Squashed commit of the following:
8 commit 1e9e8cf5edc469114c8eadf46817cd5c1261b35c
9 Author: Nils Philippsen <nils@redhat.com>
10 Date: Thu Jul 3 10:14:52 2014 +0200
12 don't use g_unix_open_pipe(), g_unix_fd_add()
14 These functions have only recently been added to glib. Use pipe()/
15 fcntl() and g_io_channel_unix_new()/g_io_add_watch() instead which are
16 available in the minimum glib version needed for gtk+-2.x.
18 commit acbdf3f693d3d2a78ee7490ca1bf76957daf00cf
19 Author: Nils Philippsen <nils@redhat.com>
20 Date: Thu Mar 13 13:38:12 2014 +0100
22 separate signal handlers in top and bottom half
24 This is to avoid race-conditions occurring when a signal is received
25 while the signal handler is not yet finished. It also avoids calling
26 non-reentrant functions from a signal handler. The top half (the real
27 signal handler) just writes a character into a pipe which gets picked up
28 and serviced by the bottom half from the normal event loop, this
29 serializes things and makes using non-reentrant functions safe.
31 src/xsane.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------
32 1 file changed, 136 insertions(+), 15 deletions(-)
34 diff --git a/src/xsane.c b/src/xsane.c
35 index 2b9211b..fc2ebbe 100644
42 +#include <glib-unix.h>
46 @@ -121,6 +122,7 @@ static const Preferences_medium_t pref_default_medium[]=
49 static guint xsane_resolution_timer = 0;
50 +static int xsane_signal_pipe[2];
52 /* ---------------------------------------------------------------------------------------------------------------------- */
54 @@ -161,8 +163,11 @@ void xsane_pref_save(void);
55 static int xsane_pref_restore(void);
56 static void xsane_pref_save_media(void);
57 static void xsane_pref_restore_media(void);
58 -static RETSIGTYPE xsane_quit_handler(int signal);
59 -static RETSIGTYPE xsane_sigchld_handler(int signal);
60 +static RETSIGTYPE xsane_signal_handler_top_half(int signal);
61 +static gboolean xsane_signal_handler_bottom_half(GIOChannel *source,
62 + GIOCondition condition,
63 + gpointer user_data);
64 +static void xsane_sigchld_handler(void);
65 static void xsane_quit(void);
66 static void xsane_exit(void);
67 static gint xsane_standard_option_win_delete(GtkWidget *widget, gpointer data);
68 @@ -2296,16 +2301,119 @@ static void xsane_pref_restore_media(void)
70 /* ---------------------------------------------------------------------------------------------------------------------- */
72 -static RETSIGTYPE xsane_quit_handler(int signal)
73 +static RETSIGTYPE xsane_signal_handler_top_half(int signal)
75 - DBG(DBG_proc, "xsane_quit_handler\n");
76 + const char *msg_func = "xsane_signal_handler_top_half(): ";
77 + const char *msg_short_write = "Short write() while processing signal.\n";
78 + const char *msg_err = "Error during write().\n";
81 + int errno_saved = errno;
103 + if ((written = write(xsane_signal_pipe[1], &sig_char, 1)) <= 0)
105 + /* At this point, all bets are off. Salvage what we can. */
107 + const char *msg = (written == 0) ? msg_short_write : msg_err;
109 + if ((write(STDERR_FILENO, msg_func, strlen(msg_func)) < 0) ||
110 + (write(STDERR_FILENO, msg, strlen(msg)) < 0))
112 + /* This is really a no-op, but at this point it doesn't really matter
113 + * anymore if the writes succeeded or not. */
118 + /* Ignore SIGCHLD errors, zombie processes don't hurt that much. */
119 + if (signal != SIGCHLD)
121 + struct SIGACTION act;
122 + memset(&act, 0, sizeof(act));
123 + act.sa_handler = SIG_DFL;
124 + sigaction(signal, &act, NULL);
129 + errno = errno_saved;
132 +static gboolean xsane_signal_handler_bottom_half(GIOChannel *source,
133 + GIOCondition condition,
134 + gpointer user_data)
139 + DBG(DBG_proc, "xsane_signal_handler_bottom_half\n");
141 + while ((readlen = read(xsane_signal_pipe[0], &sig_char, 1)) != 0)
145 + if (errno == EINTR)
147 + /* if interrupted by signal, just repeat reading */
164 + xsane_sigchld_handler();
168 + "Don't know how to cope with character-encoded signal: '%c'\n",
174 + /* previous invocation might have read more than it should, so ignore
175 + * EAGAIN/EWOULDBLOCK */
176 + if (readlen < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
178 + DBG(DBG_error, "Error while reading from pipe: %d '%s'\n", errno,
185 /* ---------------------------------------------------------------------------------------------------------------------- */
187 -static RETSIGTYPE xsane_sigchld_handler(int signal)
188 +static void xsane_sigchld_handler(void)
191 XsaneChildprocess **childprocess_listptr = &xsane.childprocess_list;
192 @@ -6026,6 +6134,8 @@ void xsane_interface(int argc, char **argv)
194 struct SIGACTION act;
196 + GIOChannel *gio_pipe_read;
198 DBG(DBG_proc, "xsane_interface\n");
200 xsane.info_label = NULL;
201 @@ -6069,18 +6179,29 @@ void xsane_interface(int argc, char **argv)
205 + if ((pipe(xsane_signal_pipe) == -1) ||
206 + (fcntl(xsane_signal_pipe[0], F_SETFD, FD_CLOEXEC) == -1) ||
207 + (fcntl(xsane_signal_pipe[0], F_SETFL, O_NONBLOCK) == -1) ||
208 + (fcntl(xsane_signal_pipe[1], F_SETFD, FD_CLOEXEC) == -1) ||
209 + (fcntl(xsane_signal_pipe[1], F_SETFL, O_NONBLOCK) == -1) ||
210 + !(gio_pipe_read = g_io_channel_unix_new(xsane_signal_pipe[0])) ||
211 + !g_io_add_watch(gio_pipe_read, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
212 + xsane_signal_handler_bottom_half, NULL))
215 + "Couldn't create signal handling pipe, set flags on it or install\n"
216 + "bottom half of handler.\n");
220 /* define SIGTERM, SIGINT, SIGHUP-handler to make sure that e.g. all temporary files are deleted */
221 /* when xsane gets such a signal */
222 memset(&act, 0, sizeof(act));
223 - act.sa_handler = xsane_quit_handler;
224 - sigaction(SIGTERM, &act, 0);
225 - sigaction(SIGINT, &act, 0);
226 - sigaction(SIGHUP, &act, 0);
228 - /* add a signal handler that cleans up zombie child processes */
229 - memset(&act, 0, sizeof(act));
230 - act.sa_handler = xsane_sigchld_handler;
231 - sigaction(SIGCHLD, &act, 0);
232 + act.sa_handler = xsane_signal_handler_top_half;
233 + sigaction(SIGTERM, &act, NULL);
234 + sigaction(SIGINT, &act, NULL);
235 + sigaction(SIGHUP, &act, NULL);
236 + sigaction(SIGCHLD, &act, NULL);