From 1d8948e02385a6a2431b3ca782cc64eb39bc8a26 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 24 Jul 2014 22:51:05 +0200 Subject: [PATCH] Backout 42ced0d023cd: oops, i didn't want to push this changeset :-/ --- Doc/c-api/exceptions.rst | 13 +--- Doc/library/signal.rst | 5 -- Lib/test/test_signal.py | 128 +++--------------------------- Modules/signalmodule.c | 155 +++++-------------------------------- PCbuild/pythoncore.vcxproj | 16 ++-- 5 files changed, 40 insertions(+), 277 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 46033ca7389..33b44390d24 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -443,20 +443,13 @@ in various ways. There is a separate error indicator for each thread. .. c:function:: int PySignal_SetWakeupFd(int fd) - This utility function specifies a file descriptor to which the signal number - is written as a single byte whenever a signal is received. *fd* must be - non-blocking. It returns the previous such file descriptor. - - On Windows, the function only supports socket handles. - - The value ``-1`` disables the feature; this is the initial state. + This utility function specifies a file descriptor to which a ``'\0'`` byte will + be written whenever a signal is received. It returns the previous such file + descriptor. The value ``-1`` disables the feature; this is the initial state. This is equivalent to :func:`signal.set_wakeup_fd` in Python, but without any error checking. *fd* should be a valid file descriptor. The function should only be called from the main thread. - .. versionchanged:: 3.5 - On Windows, the function now only supports socket handles. - .. c:function:: PyObject* PyErr_NewException(char *name, PyObject *base, PyObject *dict) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst index cda228bdc95..a97ce66ef52 100644 --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -308,8 +308,6 @@ The :mod:`signal` module defines the following functions: a library to wakeup a poll or select call, allowing the signal to be fully processed. - On Windows, the function only supports socket handles. - 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. @@ -320,9 +318,6 @@ The :mod:`signal` module defines the following functions: attempting to call it from other threads will cause a :exc:`ValueError` exception to be raised. - .. versionchanged:: 3.5 - On Windows, the function now only supports socket handles. - .. function:: siginterrupt(signalnum, flag) diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index 28bb4d6e23f..56ab6316b61 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -6,7 +6,6 @@ import gc import pickle import select import signal -import socket import struct import subprocess import traceback @@ -252,43 +251,21 @@ class WindowsSignalTests(unittest.TestCase): class WakeupFDTests(unittest.TestCase): def test_invalid_fd(self): - if sys.platform == "win32": - sock = socket.socket() - fd = sock.fileno() - sock.close() - else: - fd = support.make_bad_fd() + fd = support.make_bad_fd() self.assertRaises((ValueError, OSError), signal.set_wakeup_fd, fd) - @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') - def test_only_socket(self): - # set_wakeup_fd() expects a socket on Windows - with open(support.TESTFN, 'wb') as fp: - self.addCleanup(support.unlink, support.TESTFN) - self.assertRaises(ValueError, - signal.set_wakeup_fd, fp.fileno()) - def test_set_wakeup_fd_result(self): - if sys.platform == 'win32': - sock1 = socket.socket() - self.addCleanup(sock1.close) - fd1 = sock1.fileno() + r1, w1 = os.pipe() + self.addCleanup(os.close, r1) + self.addCleanup(os.close, w1) + r2, w2 = os.pipe() + self.addCleanup(os.close, r2) + self.addCleanup(os.close, w2) - sock2 = socket.socket() - self.addCleanup(sock2.close) - fd2 = sock2.fileno() - else: - r1, fd1 = os.pipe() - self.addCleanup(os.close, r1) - self.addCleanup(os.close, fd1) - r2, fd2 = os.pipe() - self.addCleanup(os.close, r2) - self.addCleanup(os.close, fd2) - - signal.set_wakeup_fd(fd1) - self.assertIs(signal.set_wakeup_fd(fd2), fd1) - self.assertIs(signal.set_wakeup_fd(-1), fd2) + signal.set_wakeup_fd(w1) + self.assertIs(signal.set_wakeup_fd(w2), w1) + self.assertIs(signal.set_wakeup_fd(-1), w2) self.assertIs(signal.set_wakeup_fd(-1), -1) @@ -464,90 +441,6 @@ class WakeupSignalTests(unittest.TestCase): """, signal.SIGUSR1, signal.SIGUSR2, ordered=False) -@unittest.skipUnless(hasattr(socket, 'socketpair'), 'need socket.socketpair') -class WakeupSocketSignalTests(unittest.TestCase): - - @unittest.skipIf(_testcapi is None, 'need _testcapi') - def test_socket(self): - # use a subprocess to have only one thread - code = """if 1: - import signal - import socket - import struct - import _testcapi - - signum = signal.SIGINT - signals = (signum,) - - def handler(signum, frame): - pass - - signal.signal(signum, handler) - - read, write = socket.socketpair() - read.setblocking(False) - write.setblocking(False) - signal.set_wakeup_fd(write.fileno()) - - _testcapi.raise_signal(signum) - - data = read.recv(1) - if not data: - raise Exception("no signum written") - raised = struct.unpack('B', data) - if raised != signals: - raise Exception("%r != %r" % (raised, signals)) - - read.close() - write.close() - """ - - assert_python_ok('-c', code) - - @unittest.skipIf(_testcapi is None, 'need _testcapi') - def test_send_error(self): - # Use a subprocess to have only one thread. - if os.name == 'nt': - action = 'send' - else: - action = 'write' - code = """if 1: - import errno - import signal - import socket - import sys - import time - import _testcapi - from test.support import captured_stderr - - signum = signal.SIGINT - - def handler(signum, frame): - pass - - signal.signal(signum, handler) - - read, write = socket.socketpair() - read.setblocking(False) - write.setblocking(False) - - signal.set_wakeup_fd(write.fileno()) - - # Close sockets: send() will fail - read.close() - write.close() - - with captured_stderr() as err: - _testcapi.raise_signal(signum) - - err = err.getvalue() - if ('Exception ignored when trying to {action} to the signal wakeup fd' - not in err): - raise AssertionError(err) - """.format(action=action) - assert_python_ok('-c', code) - - @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class SiginterruptTest(unittest.TestCase): @@ -1097,7 +990,6 @@ def test_main(): try: support.run_unittest(GenericTests, PosixTests, InterProcessSignalTests, WakeupFDTests, WakeupSignalTests, - WakeupSocketSignalTests, SiginterruptTest, ItimerTest, WindowsSignalTests, PendingSignalsTests) finally: diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index a315f23a038..c4f01216444 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -4,9 +4,6 @@ /* XXX Signals should be recorded per thread, now we have thread state. */ #include "Python.h" -#ifdef MS_WINDOWS -#include "socketmodule.h" /* needed for SOCKET_T */ -#endif #ifndef MS_WINDOWS #include "posixmodule.h" #endif @@ -90,18 +87,7 @@ static volatile struct { PyObject *func; } Handlers[NSIG]; -#ifdef MS_WINDOWS -#define INVALID_SOCKET ((SOCKET_T)-1) - -static volatile struct { - SOCKET_T fd; - int send_err_set; - int send_errno; - int send_win_error; -} wakeup = {INVALID_SOCKET, 0, 0}; -#else static volatile sig_atomic_t wakeup_fd = -1; -#endif /* Speed up sigcheck() when none tripped */ static volatile sig_atomic_t is_tripped = 0; @@ -185,33 +171,6 @@ checksignals_witharg(void * unused) return PyErr_CheckSignals(); } -#ifdef MS_WINDOWS -static int -report_wakeup_error(void* Py_UNUSED(data)) -{ - PyObject *res; - - if (wakeup.send_win_error) { - /* PyErr_SetExcFromWindowsErr() invokes FormatMessage() which - recognizes the error codes used by both GetLastError() and - WSAGetLastError */ - res = PyErr_SetExcFromWindowsErr(PyExc_OSError, wakeup.send_win_error); - } - else { - errno = wakeup.send_errno; - res = PyErr_SetFromErrno(PyExc_OSError); - } - - assert(res == NULL); - wakeup.send_err_set = 0; - - PySys_WriteStderr("Exception ignored when trying to send to the " - "signal wakeup fd:\n"); - PyErr_WriteUnraisable(NULL); - - return 0; -} -#else static int report_wakeup_error(void *data) { @@ -224,51 +183,26 @@ report_wakeup_error(void *data) errno = save_errno; return 0; } -#endif static void trip_signal(int sig_num) { unsigned char byte; - Py_ssize_t rc; + int rc = 0; Handlers[sig_num].tripped = 1; - -#ifdef MS_WINDOWS - if (wakeup.fd != INVALID_SOCKET) { - byte = (unsigned char)sig_num; - do { - rc = send(wakeup.fd, &byte, 1, 0); - } while (rc < 0 && errno == EINTR); - - /* we only have a storage for one error in the wakeup structure */ - if (rc < 0 && !wakeup.send_err_set) { - wakeup.send_err_set = 1; - wakeup.send_errno = errno; - wakeup.send_win_error = GetLastError(); - Py_AddPendingCall(report_wakeup_error, NULL); - } - } -#else if (wakeup_fd != -1) { byte = (unsigned char)sig_num; - do { - rc = write(wakeup_fd, &byte, 1); - } while (rc < 0 && errno == EINTR); - - if (rc < 0) { - Py_AddPendingCall(report_wakeup_error, - (void *)(Py_intptr_t)errno); - } - } -#endif - - if (!is_tripped) { - /* Set is_tripped after setting .tripped, as it gets - cleared in PyErr_CheckSignals() before .tripped. */ - is_tripped = 1; - Py_AddPendingCall(checksignals_witharg, NULL); + while ((rc = write(wakeup_fd, &byte, 1)) == -1 && errno == EINTR); + if (rc == -1) + Py_AddPendingCall(report_wakeup_error, (void *) (Py_intptr_t) errno); } + if (is_tripped) + return; + /* Set is_tripped after setting .tripped, as it gets + cleared in PyErr_CheckSignals() before .tripped. */ + is_tripped = 1; + Py_AddPendingCall(checksignals_witharg, NULL); } static void @@ -492,28 +426,10 @@ signal_siginterrupt(PyObject *self, PyObject *args) static PyObject * signal_set_wakeup_fd(PyObject *self, PyObject *args) { -#ifdef MS_WINDOWS - PyObject *fdobj; - SOCKET_T fd, old_fd; - int res; - int res_size = sizeof res; - PyObject *mod; - struct stat st; - - if (!PyArg_ParseTuple(args, "O:set_wakeup_fd", &fdobj)) - return NULL; - - fd = PyLong_AsSocket_t(fdobj); - if (fd == (SOCKET_T)(-1) && PyErr_Occurred()) - return NULL; -#else + struct stat buf; int fd, old_fd; - struct stat st; - if (!PyArg_ParseTuple(args, "i:set_wakeup_fd", &fd)) return NULL; -#endif - #ifdef WITH_THREAD if (PyThread_get_thread_ident() != main_thread) { PyErr_SetString(PyExc_ValueError, @@ -522,54 +438,28 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args) } #endif -#ifdef MS_WINDOWS - if (fd != INVALID_SOCKET) { - /* Import the _socket module to call WSAStartup() */ - mod = PyImport_ImportModuleNoBlock("_socket"); - if (mod == NULL) - return NULL; - Py_DECREF(mod); - - /* test the socket */ - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, - (char *)&res, &res_size) != 0) { - int err = WSAGetLastError(); - if (err == WSAENOTSOCK) - PyErr_SetString(PyExc_ValueError, "fd is not a socket"); - else - PyErr_SetExcFromWindowsErr(PyExc_OSError, err); - return NULL; - } - } - - old_fd = wakeup.fd; - wakeup.fd = fd; - - if (old_fd != INVALID_SOCKET) - return PyLong_FromSocket_t(old_fd); - else - return PyLong_FromLong(-1); -#else if (fd != -1) { - if (fstat(fd, &st) != 0) { - PyErr_SetFromErrno(PyExc_OSError); + if (!_PyVerify_fd(fd)) { + PyErr_SetString(PyExc_ValueError, "invalid fd"); return NULL; } + + if (fstat(fd, &buf) != 0) + return PyErr_SetFromErrno(PyExc_OSError); } old_fd = wakeup_fd; wakeup_fd = fd; return PyLong_FromLong(old_fd); -#endif } PyDoc_STRVAR(set_wakeup_fd_doc, "set_wakeup_fd(fd) -> fd\n\ \n\ -Sets the fd to be written to (with the signal number) when a signal\n\ +Sets the fd to be written to (with '\\0') when a signal\n\ comes in. A library can use this to wakeup select or poll.\n\ -The previous fd or -1 is returned.\n\ +The previous fd is returned.\n\ \n\ The fd must be non-blocking."); @@ -577,17 +467,10 @@ The fd must be non-blocking."); int PySignal_SetWakeupFd(int fd) { - int old_fd; + int old_fd = wakeup_fd; if (fd < 0) fd = -1; - -#ifdef MS_WINDOWS - old_fd = Py_SAFE_DOWNCAST(wakeup.fd, SOCKET_T, int); - wakeup.fd = fd; -#else - old_fd = wakeup_fd; wakeup_fd = fd; -#endif return old_fd; } diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 1ad16fb8222..6021cd74cbf 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -176,7 +176,7 @@ "$(SolutionDir)make_buildinfo.exe" Release "$(IntDir)\" - $(IntDir)getbuildinfo.o;ws2_32.lib;%(AdditionalDependencies) + $(IntDir)getbuildinfo.o;%(AdditionalDependencies) $(OutDir)$(PyDllName).dll libc;%(IgnoreSpecificDefaultLibraries) 0x1e000000 @@ -212,7 +212,7 @@ IF %ERRORLEVEL% NEQ 0 ( "$(SolutionDir)make_buildinfo.exe" Release "$(IntDir)\" - $(IntDir)getbuildinfo.o;ws2_32.lib;%(AdditionalDependencies) + $(IntDir)getbuildinfo.o;%(AdditionalDependencies) libc;%(IgnoreSpecificDefaultLibraries) 0x1e000000 @@ -247,7 +247,7 @@ IF %ERRORLEVEL% NEQ 0 ( "$(SolutionDir)make_buildinfo.exe" Debug "$(IntDir)" - $(IntDir)getbuildinfo.o;ws2_32.lib;%(AdditionalDependencies) + $(IntDir)getbuildinfo.o;%(AdditionalDependencies) libc;%(IgnoreSpecificDefaultLibraries) 0x1e000000 @@ -285,7 +285,7 @@ IF %ERRORLEVEL% NEQ 0 ( "$(SolutionDir)make_buildinfo.exe" Debug "$(IntDir)" - $(IntDir)getbuildinfo.o;ws2_32.lib;%(AdditionalDependencies) + $(IntDir)getbuildinfo.o;%(AdditionalDependencies) libc;%(IgnoreSpecificDefaultLibraries) 0x1e000000 @@ -317,7 +317,7 @@ IF %ERRORLEVEL% NEQ 0 ( "$(SolutionDir)make_buildinfo.exe" Release "$(IntDir)\" - $(IntDir)getbuildinfo.o;ws2_32.lib;%(AdditionalDependencies) + $(IntDir)getbuildinfo.o;%(AdditionalDependencies) $(OutDir)$(PyDllName).dll libc;%(IgnoreSpecificDefaultLibraries) 0x1e000000 @@ -353,7 +353,7 @@ IF %ERRORLEVEL% NEQ 0 ( "$(SolutionDir)make_buildinfo.exe" Release "$(IntDir)\" - $(IntDir)getbuildinfo.o;ws2_32.lib;%(AdditionalDependencies) + $(IntDir)getbuildinfo.o;%(AdditionalDependencies) libc;%(IgnoreSpecificDefaultLibraries) 0x1e000000 MachineX64 @@ -386,7 +386,7 @@ IF %ERRORLEVEL% NEQ 0 ( "$(SolutionDir)make_buildinfo.exe" Release "$(IntDir)\" - $(IntDir)getbuildinfo.o;ws2_32.lib;%(AdditionalDependencies) + $(IntDir)getbuildinfo.o;%(AdditionalDependencies) $(OutDir)$(PyDllName).dll libc;%(IgnoreSpecificDefaultLibraries) 0x1e000000 @@ -422,7 +422,7 @@ IF %ERRORLEVEL% NEQ 0 ( "$(SolutionDir)make_buildinfo.exe" Release "$(IntDir)\" - $(IntDir)getbuildinfo.o;ws2_32.lib;%(AdditionalDependencies) + $(IntDir)getbuildinfo.o;%(AdditionalDependencies) libc;%(IgnoreSpecificDefaultLibraries) 0x1e000000 MachineX64