]> git.pld-linux.org Git - packages/xsane.git/blame - xsane-0.999-signal-handling.patch
keep fedora comments in .patch not .spec
[packages/xsane.git] / xsane-0.999-signal-handling.patch
CommitLineData
94120488
ER
1# from Fedora
2# fix signal handling (#1073698)
3# submitted to upstream (Oliver Rauch) via email, 2014-07-03
4
12d07cfb
AM
5From 3b5d3b7e1f320b0bfbe48024a586c0a22375aa2d Mon Sep 17 00:00:00 2001
6From: Nils Philippsen <nils@redhat.com>
7Date: Thu, 3 Jul 2014 10:38:03 +0200
8Subject: [PATCH] patch: signal-handling
9
10Squashed commit of the following:
11
12commit 1e9e8cf5edc469114c8eadf46817cd5c1261b35c
13Author: Nils Philippsen <nils@redhat.com>
14Date: Thu Jul 3 10:14:52 2014 +0200
15
16 don't use g_unix_open_pipe(), g_unix_fd_add()
17
18 These functions have only recently been added to glib. Use pipe()/
19 fcntl() and g_io_channel_unix_new()/g_io_add_watch() instead which are
20 available in the minimum glib version needed for gtk+-2.x.
21
22commit acbdf3f693d3d2a78ee7490ca1bf76957daf00cf
23Author: Nils Philippsen <nils@redhat.com>
24Date: Thu Mar 13 13:38:12 2014 +0100
25
26 separate signal handlers in top and bottom half
27
28 This is to avoid race-conditions occurring when a signal is received
29 while the signal handler is not yet finished. It also avoids calling
30 non-reentrant functions from a signal handler. The top half (the real
31 signal handler) just writes a character into a pipe which gets picked up
32 and serviced by the bottom half from the normal event loop, this
33 serializes things and makes using non-reentrant functions safe.
34---
35 src/xsane.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------
36 1 file changed, 136 insertions(+), 15 deletions(-)
37
38diff --git a/src/xsane.c b/src/xsane.c
39index 2b9211b..fc2ebbe 100644
40--- a/src/xsane.c
41+++ b/src/xsane.c
42@@ -47,6 +47,7 @@
43 #endif
44
45 #include <sys/wait.h>
46+#include <glib-unix.h>
47
48 #include <stdarg.h>
49
50@@ -121,6 +122,7 @@ static const Preferences_medium_t pref_default_medium[]=
51
52 int DBG_LEVEL = 0;
53 static guint xsane_resolution_timer = 0;
54+static int xsane_signal_pipe[2];
55
56 /* ---------------------------------------------------------------------------------------------------------------------- */
57
58@@ -161,8 +163,11 @@ void xsane_pref_save(void);
59 static int xsane_pref_restore(void);
60 static void xsane_pref_save_media(void);
61 static void xsane_pref_restore_media(void);
62-static RETSIGTYPE xsane_quit_handler(int signal);
63-static RETSIGTYPE xsane_sigchld_handler(int signal);
64+static RETSIGTYPE xsane_signal_handler_top_half(int signal);
65+static gboolean xsane_signal_handler_bottom_half(GIOChannel *source,
66+ GIOCondition condition,
67+ gpointer user_data);
68+static void xsane_sigchld_handler(void);
69 static void xsane_quit(void);
70 static void xsane_exit(void);
71 static gint xsane_standard_option_win_delete(GtkWidget *widget, gpointer data);
72@@ -2296,16 +2301,119 @@ static void xsane_pref_restore_media(void)
73
74 /* ---------------------------------------------------------------------------------------------------------------------- */
75
76-static RETSIGTYPE xsane_quit_handler(int signal)
77+static RETSIGTYPE xsane_signal_handler_top_half(int signal)
78 {
79- DBG(DBG_proc, "xsane_quit_handler\n");
80+ const char *msg_func = "xsane_signal_handler_top_half(): ";
81+ const char *msg_short_write = "Short write() while processing signal.\n";
82+ const char *msg_err = "Error during write().\n";
83+ char sig_char;
84+ ssize_t written;
85+ int errno_saved = errno;
86
87- xsane_quit();
88+ switch (signal)
89+ {
90+ case SIGTERM:
91+ sig_char = 't';
92+ break;
93+ case SIGINT:
94+ sig_char = 'i';
95+ break;
96+ case SIGHUP:
97+ sig_char = 'h';
98+ break;
99+ case SIGCHLD:
100+ sig_char = 'c';
101+ break;
102+ default:
103+ sig_char = '?';
104+ break;
105+ }
106+
107+ if ((written = write(xsane_signal_pipe[1], &sig_char, 1)) <= 0)
108+ {
109+ /* At this point, all bets are off. Salvage what we can. */
110+
111+ const char *msg = (written == 0) ? msg_short_write : msg_err;
112+
113+ if ((write(STDERR_FILENO, msg_func, strlen(msg_func)) < 0) ||
114+ (write(STDERR_FILENO, msg, strlen(msg)) < 0))
115+ {
116+ /* This is really a no-op, but at this point it doesn't really matter
117+ * anymore if the writes succeeded or not. */
118+ goto bail_out;
119+ }
120+
121+bail_out:
122+ /* Ignore SIGCHLD errors, zombie processes don't hurt that much. */
123+ if (signal != SIGCHLD)
124+ {
125+ struct SIGACTION act;
126+ memset(&act, 0, sizeof(act));
127+ act.sa_handler = SIG_DFL;
128+ sigaction(signal, &act, NULL);
129+ raise(signal);
130+ }
131+ }
132+
133+ errno = errno_saved;
134+}
135+
136+static gboolean xsane_signal_handler_bottom_half(GIOChannel *source,
137+ GIOCondition condition,
138+ gpointer user_data)
139+{
140+ char sig_char;
141+ ssize_t readlen;
142+
143+ DBG(DBG_proc, "xsane_signal_handler_bottom_half\n");
144+
145+ while ((readlen = read(xsane_signal_pipe[0], &sig_char, 1)) != 0)
146+ {
147+ if (readlen < 0)
148+ {
149+ if (errno == EINTR)
150+ {
151+ /* if interrupted by signal, just repeat reading */
152+ continue;
153+ }
154+ else
155+ {
156+ break;
157+ }
158+ }
159+
160+ switch (sig_char)
161+ {
162+ case 't':
163+ case 'i':
164+ case 'h':
165+ xsane_quit();
166+ break;
167+ case 'c':
168+ xsane_sigchld_handler();
169+ break;
170+ default:
171+ DBG(DBG_error,
172+ "Don't know how to cope with character-encoded signal: '%c'\n",
173+ sig_char);
174+ break;
175+ }
176+ }
177+
178+ /* previous invocation might have read more than it should, so ignore
179+ * EAGAIN/EWOULDBLOCK */
180+ if (readlen < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
181+ {
182+ DBG(DBG_error, "Error while reading from pipe: %d '%s'\n", errno,
183+ strerror(errno));
184+ }
185+
186+ return TRUE;
187 }
188
189 /* ---------------------------------------------------------------------------------------------------------------------- */
190
191-static RETSIGTYPE xsane_sigchld_handler(int signal)
192+static void xsane_sigchld_handler(void)
193 {
194 int status;
195 XsaneChildprocess **childprocess_listptr = &xsane.childprocess_list;
196@@ -6026,6 +6134,8 @@ void xsane_interface(int argc, char **argv)
197 {
198 struct SIGACTION act;
199
200+ GIOChannel *gio_pipe_read;
201+
202 DBG(DBG_proc, "xsane_interface\n");
203
204 xsane.info_label = NULL;
205@@ -6069,18 +6179,29 @@ void xsane_interface(int argc, char **argv)
206 }
207 }
208
209+ if ((pipe(xsane_signal_pipe) == -1) ||
210+ (fcntl(xsane_signal_pipe[0], F_SETFD, FD_CLOEXEC) == -1) ||
211+ (fcntl(xsane_signal_pipe[0], F_SETFL, O_NONBLOCK) == -1) ||
212+ (fcntl(xsane_signal_pipe[1], F_SETFD, FD_CLOEXEC) == -1) ||
213+ (fcntl(xsane_signal_pipe[1], F_SETFL, O_NONBLOCK) == -1) ||
214+ !(gio_pipe_read = g_io_channel_unix_new(xsane_signal_pipe[0])) ||
215+ !g_io_add_watch(gio_pipe_read, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
216+ xsane_signal_handler_bottom_half, NULL))
217+ {
218+ DBG(DBG_error,
219+ "Couldn't create signal handling pipe, set flags on it or install\n"
220+ "bottom half of handler.\n");
221+ exit(1);
222+ }
223+
224 /* define SIGTERM, SIGINT, SIGHUP-handler to make sure that e.g. all temporary files are deleted */
225 /* when xsane gets such a signal */
226 memset(&act, 0, sizeof(act));
227- act.sa_handler = xsane_quit_handler;
228- sigaction(SIGTERM, &act, 0);
229- sigaction(SIGINT, &act, 0);
230- sigaction(SIGHUP, &act, 0);
231-
232- /* add a signal handler that cleans up zombie child processes */
233- memset(&act, 0, sizeof(act));
234- act.sa_handler = xsane_sigchld_handler;
235- sigaction(SIGCHLD, &act, 0);
236+ act.sa_handler = xsane_signal_handler_top_half;
237+ sigaction(SIGTERM, &act, NULL);
238+ sigaction(SIGINT, &act, NULL);
239+ sigaction(SIGHUP, &act, NULL);
240+ sigaction(SIGCHLD, &act, NULL);
241
242 gtk_main();
243 sane_exit();
244--
2451.9.3
246
This page took 0.102876 seconds and 4 git commands to generate.