chiark / gitweb /
Use the self-pipe trick to fix the signal handling bug.
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 4 Jan 2017 00:44:45 +0000 (00:44 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 4 Jan 2017 01:05:59 +0000 (01:05 +0000)
Closes:#850079.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
debian/changelog
events.c
events.h
twm.c

index a41b5002a133dfc38fa076906e5ac563abc5cc44..f404585e031e05c26c565eb5920cf10a2780df7e 100644 (file)
@@ -1,6 +1,8 @@
 vtwm (5.4.7-5~) unstable; urgency=medium
 
-  * 
+  Bugfix:
+  * Use the self-pipe trick to fix the signal handling bug, instead
+    of sigprocmask.  Closes:#850079.
 
  -- Ian Jackson <ijackson@chiark.greenend.org.uk>  Tue, 03 Jan 2017 23:19:00 +0000
 
index 28e1e29b7f4925e1f1d9f1946f0abfa2163ce980..beeb2e84ed951a78684338e21b9e5d6d8424d6fd 100644 (file)
--- a/events.c
+++ b/events.c
@@ -38,6 +38,9 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <signal.h>
+#include <poll.h>
+#include <errno.h>
 #include "twm.h"
 #include <X11/Xatom.h>
 #include "add_window.h"
@@ -63,6 +66,9 @@
 #include <sys/types.h> /* RAISEDELAY */
 #include <unistd.h>
 #endif
+#include <unistd.h>
+#include <assert.h>
+#include <sys/fcntl.h>
 
 extern void IconDown();
 /* djhjr - 4/26/99 */
@@ -360,6 +366,68 @@ Bool DispatchEvent ()
 
 \f
 
+/***********************************************************************
+ *
+ *  Procedures:
+ *      HandleSignal   use instead of signal
+ *
+ ***********************************************************************
+ */
+
+#define HANDLE_SIG_MAX 256 /* increase means changing type written to pipe */
+
+static SigProc signaltable[HANDLE_SIG_MAX];
+static int sigselfpipe[2] = { -1, -1 };
+
+static void
+SelfPipeHandler(sig)
+       int sig;
+{
+       unsigned char sigchar = sig;
+       int esave;
+
+       esave = errno;
+       write(sigselfpipe[1], &sigchar, 1);
+       errno = esave;
+}
+
+void
+HandleSignal(sig, func)
+       int sig;
+       SigProc func;
+{
+       struct sigaction sa;
+       int r, i;
+
+       if (sigselfpipe[0] == -1) {
+               r = pipe(sigselfpipe);
+               if (r) { perror("pipe for signals"); exit(-1); }
+               for (i = 0; i < 2; i++) {
+                       r = fcntl(sigselfpipe[i], F_GETFL);
+                       if (r<0) { perror("fcntl get for pipe"); exit(-1); }
+                       r |= O_NONBLOCK;
+                       r = fcntl(sigselfpipe[i], F_SETFL, r);
+                       if (r<0) { perror("fcntl get for pipe"); exit(-1); }
+               }
+       }
+
+       assert(sig < HANDLE_SIG_MAX);
+
+       r = sigaction(sig, NULL, &sa);
+       if (r) { perror("sigaction get"); exit(-1); }
+
+       if (sa.sa_handler != SIG_DFL)
+               return;
+
+       signaltable[sig] = func;
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = SelfPipeHandler;
+       sigemptyset(&sa.sa_mask);
+       sa.sa_flags = SA_RESTART;
+       r = sigaction(sig, &sa, NULL);
+       if (r) { perror("sigaction set"); exit(-1); }
+}
+
 /***********************************************************************
  *
  *  Procedure:
@@ -371,6 +439,14 @@ Bool DispatchEvent ()
 void
 HandleEvents()
 {
+       struct pollfd pfds[2];
+       pfds[0].fd = ConnectionNumber(dpy);
+       pfds[0].events = POLLIN|POLLPRI;
+       pfds[1].fd = sigselfpipe[0];
+       pfds[1].events = POLLIN|POLLPRI;
+       sigset_t emptyset;
+       sigemptyset(&emptyset);
+
        while (TRUE)
        {
        if (enter_flag && !QLength(dpy)) {
@@ -384,7 +460,32 @@ HandleEvents()
            InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
        }
        WindowMoved = FALSE;
-       XNextEvent(dpy, &Event);
+       while (!XCheckMaskEvent(dpy, -1 /* wot no AllEventMask */, &Event)) {
+               int r;
+               unsigned char signum;
+               r = poll(pfds, 2, -1);
+               if (r<0 && errno!=EINTR) {
+                       perror("vtwm: poll failed");
+                       exit(-1);
+               }
+               for (;;) {
+                       r = read(sigselfpipe[0], &signum, 1);
+                       if (r < 0) {
+                               if (errno == EINTR) continue;
+                               if (errno == EAGAIN) break;
+                               if (errno == EWOULDBLOCK) break;
+                               perror("vtwm: read signal self-pipe");
+                               exit(-1);
+                       }
+                       if (!r) {
+                               fputs("signal self-pipe read EOF!",stderr);
+                               exit(-1);
+                       }
+                       assert(signum < HANDLE_SIG_MAX);
+                       assert(signaltable[signum]);
+                       signaltable[signum](signum);
+               }
+       }
        (void) DispatchEvent ();
        }
 }
index 8d4230455681d57de0cdf9cad089aaa1403a5cfb..498ef1e4cd32d93a05078f503629edc331427cc6 100644 (file)
--- a/events.h
+++ b/events.h
@@ -77,6 +77,8 @@ extern void InstallWindowColormaps();
 extern void RedoDoorName(); /* djhjr - 2/28/99 */
 extern void RedoListWindow(); /* djhjr - 3/1/99 */
 
+extern void HandleSignal();
+
 extern event_proc EventHandler[];
 extern Window DragWindow;
 extern int origDragX;
diff --git a/twm.c b/twm.c
index 1402eee38f3716b2bfc6449a9310f06fa9760657..54b895719aa5cddd3cd5627bd551abdeeb123b84 100644 (file)
--- a/twm.c
+++ b/twm.c
@@ -258,13 +258,13 @@ main(argc, argv, environ)
 /* djhjr - 6/22/01 */
 #ifndef NO_SOUND_SUPPORT
 #define sounddonehandler(sig) \
-    if (signal (sig, SIG_IGN) != SIG_IGN) (void) signal (sig, PlaySoundDone)
+    HandleSignal (sig, PlaySoundDone)
 #else
 #define sounddonehandler(sig) \
-    if (signal (sig, SIG_IGN) != SIG_IGN) (void) signal (sig, Done)
+    HandleSignal (sig, Done)
 #endif
 #define donehandler(sig) \
-    if (signal (sig, SIG_IGN) != SIG_IGN) (void) signal (sig, Done)
+    HandleSignal (sig, Done)
 
     sounddonehandler (SIGINT);
     sounddonehandler (SIGHUP);
@@ -282,7 +282,7 @@ main(argc, argv, environ)
 #undef donehandler
 
     /* djhjr - 7/31/98 */
-    signal (SIGUSR1, QueueRestartVtwm);
+    HandleSignal (SIGUSR1, QueueRestartVtwm);
 
     Home = getenv("HOME");
     if (Home == NULL)