]> git.pld-linux.org Git - packages/xsane.git/blob - xsane-0.999-signal-handling.patch
b9da71a1ed164b2e4645a32dce4654283908995c
[packages/xsane.git] / xsane-0.999-signal-handling.patch
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
5
6 Squashed commit of the following:
7
8 commit 1e9e8cf5edc469114c8eadf46817cd5c1261b35c
9 Author: Nils Philippsen <nils@redhat.com>
10 Date:   Thu Jul 3 10:14:52 2014 +0200
11
12     don't use g_unix_open_pipe(), g_unix_fd_add()
13
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.
17
18 commit acbdf3f693d3d2a78ee7490ca1bf76957daf00cf
19 Author: Nils Philippsen <nils@redhat.com>
20 Date:   Thu Mar 13 13:38:12 2014 +0100
21
22     separate signal handlers in top and bottom half
23
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.
30 ---
31  src/xsane.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------
32  1 file changed, 136 insertions(+), 15 deletions(-)
33
34 diff --git a/src/xsane.c b/src/xsane.c
35 index 2b9211b..fc2ebbe 100644
36 --- a/src/xsane.c
37 +++ b/src/xsane.c
38 @@ -47,6 +47,7 @@
39  #endif
40  
41  #include <sys/wait.h>
42 +#include <glib-unix.h>
43  
44  #include <stdarg.h>
45  
46 @@ -121,6 +122,7 @@ static const Preferences_medium_t pref_default_medium[]=
47  
48  int DBG_LEVEL = 0;
49  static guint xsane_resolution_timer = 0;
50 +static int xsane_signal_pipe[2];
51  
52  /* ---------------------------------------------------------------------------------------------------------------------- */
53  
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)
69  
70  /* ---------------------------------------------------------------------------------------------------------------------- */
71  
72 -static RETSIGTYPE xsane_quit_handler(int signal)
73 +static RETSIGTYPE xsane_signal_handler_top_half(int signal)
74  {
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";
79 +  char sig_char;
80 +  ssize_t written;
81 +  int errno_saved = errno;
82  
83 -  xsane_quit();
84 +  switch (signal)
85 +  {
86 +    case SIGTERM:
87 +      sig_char = 't';
88 +      break;
89 +    case SIGINT:
90 +      sig_char = 'i';
91 +      break;
92 +    case SIGHUP:
93 +      sig_char = 'h';
94 +      break;
95 +    case SIGCHLD:
96 +      sig_char = 'c';
97 +      break;
98 +    default:
99 +      sig_char = '?';
100 +      break;
101 +  }
102 +
103 +  if ((written = write(xsane_signal_pipe[1], &sig_char, 1)) <= 0)
104 +  {
105 +    /* At this point, all bets are off. Salvage what we can. */
106 +
107 +    const char *msg = (written == 0) ? msg_short_write : msg_err;
108 +
109 +    if ((write(STDERR_FILENO, msg_func, strlen(msg_func)) < 0) ||
110 +        (write(STDERR_FILENO, msg, strlen(msg)) < 0))
111 +    {
112 +      /* This is really a no-op, but at this point it doesn't really matter
113 +       * anymore if the writes succeeded or not. */
114 +      goto bail_out;
115 +    }
116 +
117 +bail_out:
118 +    /* Ignore SIGCHLD errors, zombie processes don't hurt that much. */
119 +    if (signal != SIGCHLD)
120 +    {
121 +      struct SIGACTION act;
122 +      memset(&act, 0, sizeof(act));
123 +      act.sa_handler = SIG_DFL;
124 +      sigaction(signal, &act, NULL);
125 +      raise(signal);
126 +    }
127 +  }
128 +
129 +  errno = errno_saved;
130 +}
131 +
132 +static gboolean xsane_signal_handler_bottom_half(GIOChannel *source,
133 +                                                 GIOCondition condition,
134 +                                                 gpointer user_data)
135 +{
136 +  char sig_char;
137 +  ssize_t readlen;
138 +
139 +  DBG(DBG_proc, "xsane_signal_handler_bottom_half\n");
140 +
141 +  while ((readlen = read(xsane_signal_pipe[0], &sig_char, 1)) != 0)
142 +  {
143 +    if (readlen < 0)
144 +    {
145 +      if (errno == EINTR)
146 +      {
147 +        /* if interrupted by signal, just repeat reading */
148 +        continue;
149 +      }
150 +      else
151 +      {
152 +        break;
153 +      }
154 +    }
155 +
156 +    switch (sig_char)
157 +    {
158 +      case 't':
159 +      case 'i':
160 +      case 'h':
161 +        xsane_quit();
162 +        break;
163 +      case 'c':
164 +        xsane_sigchld_handler();
165 +        break;
166 +      default:
167 +        DBG(DBG_error,
168 +            "Don't know how to cope with character-encoded signal: '%c'\n",
169 +            sig_char);
170 +        break;
171 +    }
172 +  }
173 +
174 +  /* previous invocation might have read more than it should, so ignore
175 +   * EAGAIN/EWOULDBLOCK */
176 +  if (readlen < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
177 +  {
178 +    DBG(DBG_error, "Error while reading from pipe: %d '%s'\n", errno,
179 +        strerror(errno));
180 +  }
181 +
182 +  return TRUE;
183  }
184  
185  /* ---------------------------------------------------------------------------------------------------------------------- */
186  
187 -static RETSIGTYPE xsane_sigchld_handler(int signal)
188 +static void xsane_sigchld_handler(void)
189  {
190   int status;
191   XsaneChildprocess **childprocess_listptr = &xsane.childprocess_list;
192 @@ -6026,6 +6134,8 @@ void xsane_interface(int argc, char **argv)
193  {
194   struct SIGACTION act;
195  
196 +  GIOChannel *gio_pipe_read;
197 +
198    DBG(DBG_proc, "xsane_interface\n");
199  
200    xsane.info_label = NULL;
201 @@ -6069,18 +6179,29 @@ void xsane_interface(int argc, char **argv)
202      }
203    }
204  
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))
213 +  {
214 +    DBG(DBG_error,
215 +        "Couldn't create signal handling pipe, set flags on it or install\n"
216 +        "bottom half of handler.\n");
217 +    exit(1);
218 +  }
219 +
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);
227 -
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);
237  
238    gtk_main();
239    sane_exit();
240 -- 
241 1.9.3
242
This page took 0.162136 seconds and 2 git commands to generate.