]> granicus.if.org Git - python/commitdiff
Issue #8407: The signal handler writes the signal number as a single byte
authorVictor Stinner <victor.stinner@haypocalc.com>
Sun, 8 May 2011 00:03:15 +0000 (02:03 +0200)
committerVictor Stinner <victor.stinner@haypocalc.com>
Sun, 8 May 2011 00:03:15 +0000 (02:03 +0200)
instead of a nul byte into the wakeup file descriptor. So it is possible to
wait more than one signal and know which signals were raised.

Doc/library/signal.rst
Doc/whatsnew/3.3.rst
Lib/test/test_signal.py
Misc/NEWS
Modules/signalmodule.c

index 473eda280761df2ffabeb247de7ba1ff2b51168e..68a5d2c0149c3417c51b0af21bf288a4a4b4cd63 100644 (file)
@@ -262,13 +262,17 @@ The :mod:`signal` module defines the following functions:
 
 .. function:: set_wakeup_fd(fd)
 
-   Set the wakeup fd to *fd*.  When a signal is received, a ``'\0'`` byte is
-   written to the fd.  This can be used by a library to wakeup a poll or select
-   call, allowing the signal to be fully processed.
+   Set the wakeup file descriptor to *fd*.  When a signal is received, the
+   signal number is written as a single byte into the fd.  This can be used by
+   a library to wakeup a poll or select call, allowing the signal to be fully
+   processed.
 
    The old wakeup fd is returned.  *fd* must be non-blocking.  It is up to the
    library to remove any bytes before calling poll or select again.
 
+   Use for example ``struct.unpack('%uB' % len(data), data)`` to decode the
+   signal numbers list.
+
    When threads are enabled, this function can only be called from the main thread;
    attempting to call it from other threads will cause a :exc:`ValueError`
    exception to be raised.
index 14f06af802c70ee227088adbbb2c14b5e174803c..37f96ce948daba24de741bc52f13c0a92f4e2c67 100644 (file)
@@ -131,6 +131,10 @@ signal
   * :func:`~signal.sigpending`: examine pending functions ;
   * :func:`~signal.sigwait`: wait a signal.
 
+* The signal handler writes the signal number as a single byte instead of
+  a nul byte into the wakeup file descriptor. So it is possible to wait more
+  than one signal and know which signals were raised.
+
 
 Optimizations
 =============
index c1054ed834bf317361d7fe7ed17f3c5506b16e6f..80b9744dea09ce7812e35dea8fa2f50002bd93d0 100644 (file)
@@ -5,6 +5,7 @@ import gc
 import pickle
 import select
 import signal
+import struct
 import subprocess
 import traceback
 import sys, os, time, errno
@@ -236,6 +237,11 @@ class WakeupSignalTests(unittest.TestCase):
     TIMEOUT_FULL = 10
     TIMEOUT_HALF = 5
 
+    def check_signum(self, *signals):
+        data = os.read(self.read, len(signals)+1)
+        raised = struct.unpack('%uB' % len(data), data)
+        self.assertSequenceEqual(raised, signals)
+
     def test_wakeup_fd_early(self):
         import select
 
@@ -249,6 +255,7 @@ class WakeupSignalTests(unittest.TestCase):
         select.select([self.read], [], [], self.TIMEOUT_FULL)
         after_time = time.time()
         self.assertTrue(after_time - mid_time < self.TIMEOUT_HALF)
+        self.check_signum(signal.SIGALRM)
 
     def test_wakeup_fd_during(self):
         import select
@@ -260,6 +267,14 @@ class WakeupSignalTests(unittest.TestCase):
             [self.read], [], [], self.TIMEOUT_FULL)
         after_time = time.time()
         self.assertTrue(after_time - before_time < self.TIMEOUT_HALF)
+        self.check_signum(signal.SIGALRM)
+
+    def test_signum(self):
+        old_handler = signal.signal(signal.SIGUSR1, lambda x,y:None)
+        self.addCleanup(signal.signal, signal.SIGUSR1, old_handler)
+        os.kill(os.getpid(), signal.SIGUSR1)
+        os.kill(os.getpid(), signal.SIGALRM)
+        self.check_signum(signal.SIGUSR1, signal.SIGALRM)
 
     def setUp(self):
         import fcntl
index 274931cc6d1d84f965a7039da3251403ff261439..ef78ab7cf95598d1b1594eacd479127617358550 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -140,6 +140,10 @@ Core and Builtins
 Library
 -------
 
+- Issue #8407: The signal handler writes the signal number as a single byte
+  instead of a nul byte into the wakeup file descriptor. So it is possible to
+  wait more than one signal and know which signals were raised.
+
 - Issue #8407: Add pthread_kill(), sigpending() and sigwait() functions to the
   signal module.
 
index 72850799b5b7c98eb42de18f4bfc26a9545094f4..7e07b3eb0c12fa0985c3325ab5d6e3b962b4da51 100644 (file)
@@ -176,6 +176,7 @@ checksignals_witharg(void * unused)
 static void
 trip_signal(int sig_num)
 {
+    unsigned char byte;
     Handlers[sig_num].tripped = 1;
     if (is_tripped)
         return;
@@ -183,8 +184,10 @@ trip_signal(int sig_num)
        cleared in PyErr_CheckSignals() before .tripped. */
     is_tripped = 1;
     Py_AddPendingCall(checksignals_witharg, NULL);
-    if (wakeup_fd != -1)
-        write(wakeup_fd, "\0", 1);
+    if (wakeup_fd != -1) {
+        byte = (unsigned char)sig_num;
+        write(wakeup_fd, &byte, 1);
+    }
 }
 
 static void