Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Doc/library/signal.rst
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,13 @@ The :mod:`signal` module defines the following functions:
:func:`sigpending`.


.. function:: raise_signal(signum)

Sends a signal to the calling process. Returns nothing.

.. versionadded:: 3.8


Comment thread
asvetlov marked this conversation as resolved.
.. function:: pthread_kill(thread_id, signalnum)

Send the signal *signalnum* to the thread *thread_id*, another thread in the
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_asyncio/test_windows_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def test_ctrl_c(self):

def SIGINT_after_delay():
time.sleep(1)
_testcapi.raise_signal(signal.SIGINT)
signal.raise_signal(signal.SIGINT)

asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
l = asyncio.get_event_loop()
Expand Down
10 changes: 4 additions & 6 deletions Lib/test/test_faulthandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,29 +198,27 @@ def test_sigfpe(self):
@skip_segfault_on_android
def test_sigbus(self):
self.check_fatal_error("""
import _testcapi
import faulthandler
import signal

faulthandler.enable()
_testcapi.raise_signal(signal.SIGBUS)
signal.raise_signal(signal.SIGBUS)
""",
6,
5,
'Bus error')

@unittest.skipIf(_testcapi is None, 'need _testcapi')
@unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
@skip_segfault_on_android
def test_sigill(self):
self.check_fatal_error("""
import _testcapi
import faulthandler
import signal

faulthandler.enable()
_testcapi.raise_signal(signal.SIGILL)
signal.raise_signal(signal.SIGILL)
""",
6,
5,
'Illegal instruction')

def test_fatal_error(self):
Expand Down
8 changes: 4 additions & 4 deletions Lib/test/test_posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -1596,8 +1596,8 @@ def test_setpgroup_wrong_type(self):
'need signal.pthread_sigmask()')
def test_setsigmask(self):
code = textwrap.dedent("""\
import _testcapi, signal
_testcapi.raise_signal(signal.SIGUSR1)""")
import signal
signal.raise_signal(signal.SIGUSR1)""")

pid = posix.posix_spawn(
sys.executable,
Expand Down Expand Up @@ -1627,8 +1627,8 @@ def test_setsigmask_wrong_type(self):
def test_setsigdef(self):
original_handler = signal.signal(signal.SIGUSR1, signal.SIG_IGN)
code = textwrap.dedent("""\
import _testcapi, signal
_testcapi.raise_signal(signal.SIGUSR1)""")
import signal
signal.raise_signal(signal.SIGUSR1)""")
try:
pid = posix.posix_spawn(
sys.executable,
Expand Down
3 changes: 1 addition & 2 deletions Lib/test/test_regrtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@
ROOT_DIR = os.path.abspath(os.path.normpath(ROOT_DIR))

TEST_INTERRUPTED = textwrap.dedent("""
from signal import SIGINT
from signal import SIGINT, raise_signal
try:
from _testcapi import raise_signal
raise_signal(SIGINT)
except ImportError:
import os
Expand Down
56 changes: 44 additions & 12 deletions Lib/test/test_signal.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import errno
import os
import random
import signal
Expand Down Expand Up @@ -254,7 +255,7 @@ def handler(signum, frame):
signal.set_wakeup_fd(r)
try:
with captured_stderr() as err:
_testcapi.raise_signal(signal.SIGALRM)
signal.raise_signal(signal.SIGALRM)
except ZeroDivisionError:
# An ignored exception should have been printed out on stderr
err = err.getvalue()
Expand Down Expand Up @@ -348,10 +349,9 @@ def handler(signum, frame):

def test_signum(self):
self.check_wakeup("""def test():
import _testcapi
signal.signal(signal.SIGUSR1, handler)
_testcapi.raise_signal(signal.SIGUSR1)
_testcapi.raise_signal(signal.SIGALRM)
signal.raise_signal(signal.SIGUSR1)
signal.raise_signal(signal.SIGALRM)
""", signal.SIGUSR1, signal.SIGALRM)

@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
Expand All @@ -365,8 +365,8 @@ def test_pending(self):
signal.signal(signum2, handler)

signal.pthread_sigmask(signal.SIG_BLOCK, (signum1, signum2))
_testcapi.raise_signal(signum1)
_testcapi.raise_signal(signum2)
signal.raise_signal(signum1)
signal.raise_signal(signum2)
# Unblocking the 2 signals calls the C signal handler twice
signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2))
""", signal.SIGUSR1, signal.SIGUSR2, ordered=False)
Expand Down Expand Up @@ -396,7 +396,7 @@ def handler(signum, frame):
write.setblocking(False)
signal.set_wakeup_fd(write.fileno())

_testcapi.raise_signal(signum)
signal.raise_signal(signum)

data = read.recv(1)
if not data:
Expand Down Expand Up @@ -445,7 +445,7 @@ def handler(signum, frame):
write.close()

with captured_stderr() as err:
_testcapi.raise_signal(signum)
signal.raise_signal(signum)

err = err.getvalue()
if ('Exception ignored when trying to {action} to the signal wakeup fd'
Expand Down Expand Up @@ -519,7 +519,7 @@ def handler(signum, frame):
signal.set_wakeup_fd(write.fileno())

with captured_stderr() as err:
_testcapi.raise_signal(signum)
signal.raise_signal(signum)

err = err.getvalue()
if msg not in err:
Expand All @@ -530,7 +530,7 @@ def handler(signum, frame):
signal.set_wakeup_fd(write.fileno(), warn_on_full_buffer=True)

with captured_stderr() as err:
_testcapi.raise_signal(signum)
signal.raise_signal(signum)

err = err.getvalue()
if msg not in err:
Expand All @@ -541,7 +541,7 @@ def handler(signum, frame):
signal.set_wakeup_fd(write.fileno(), warn_on_full_buffer=False)

with captured_stderr() as err:
_testcapi.raise_signal(signum)
signal.raise_signal(signum)

err = err.getvalue()
if err != "":
Expand All @@ -553,7 +553,7 @@ def handler(signum, frame):
signal.set_wakeup_fd(write.fileno())

with captured_stderr() as err:
_testcapi.raise_signal(signum)
signal.raise_signal(signum)

err = err.getvalue()
if msg not in err:
Expand Down Expand Up @@ -1214,6 +1214,38 @@ def handler(signum, frame):
# Python handler
self.assertEqual(len(sigs), N, "Some signals were lost")

class RaiseSignalTest(unittest.TestCase):

def test_sigint(self):
try:
signal.raise_signal(signal.SIGINT)
self.fail("Expected KeyInterrupt")
except KeyboardInterrupt:
pass

@unittest.skipIf(sys.platform != "win32", "Windows specific test")
def test_invalid_argument(self):
try:
SIGHUP = 1 # not supported on win32
signal.raise_signal(SIGHUP)
self.fail("OSError (Invalid argument) expected")
except OSError as e:
if e.errno == errno.EINVAL:
pass
else:
raise

def test_handler(self):
is_ok = False
def handler(a, b):
nonlocal is_ok
is_ok = True
old_signal = signal.signal(signal.SIGINT, handler)
self.addCleanup(signal.signal, signal.SIGINT, old_signal)

signal.raise_signal(signal.SIGINT)
self.assertTrue(is_ok)


def tearDownModule():
support.reap_children()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Expose ``raise(signum)`` as `raise_signal`
21 changes: 0 additions & 21 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -3859,25 +3859,6 @@ call_in_temporary_c_thread(PyObject *self, PyObject *callback)
return res;
}

static PyObject*
test_raise_signal(PyObject* self, PyObject *args)
{
int signum, err;

if (!PyArg_ParseTuple(args, "i:raise_signal", &signum)) {
return NULL;
}

err = raise(signum);
if (err)
return PyErr_SetFromErrno(PyExc_OSError);

if (PyErr_CheckSignals() < 0)
return NULL;

Py_RETURN_NONE;
}

/* marshal */

static PyObject*
Expand Down Expand Up @@ -4908,8 +4889,6 @@ static PyMethodDef TestMethods[] = {
{"docstring_with_signature_with_defaults",
(PyCFunction)test_with_docstring, METH_NOARGS,
docstring_with_signature_with_defaults},
{"raise_signal",
(PyCFunction)test_raise_signal, METH_VARARGS},
{"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_O,
PyDoc_STR("set_error_class(error_class) -> None")},
{"pymarshal_write_long_to_file",
Expand Down
35 changes: 34 additions & 1 deletion Modules/clinic/signalmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions Modules/signalmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,31 @@ signal_pause_impl(PyObject *module)

#endif

/*[clinic input]
signal.raise_signal

signalnum: int
/

Send a signal to the executing process.
[clinic start generated code]*/

static PyObject *
signal_raise_signal_impl(PyObject *module, int signalnum)
/*[clinic end generated code: output=e2b014220aa6111d input=e90c0f9a42358de6]*/
{
int err;
Py_BEGIN_ALLOW_THREADS
Comment thread
vladima marked this conversation as resolved.
_Py_BEGIN_SUPPRESS_IPH
err = raise(signalnum);
_Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS

if (err) {
return PyErr_SetFromErrno(PyExc_OSError);
}
Py_RETURN_NONE;
}

/*[clinic input]
signal.signal
Expand Down Expand Up @@ -1208,6 +1233,7 @@ static PyMethodDef signal_methods[] = {
SIGNAL_SETITIMER_METHODDEF
SIGNAL_GETITIMER_METHODDEF
SIGNAL_SIGNAL_METHODDEF
SIGNAL_RAISE_SIGNAL_METHODDEF
SIGNAL_STRSIGNAL_METHODDEF
SIGNAL_GETSIGNAL_METHODDEF
{"set_wakeup_fd", (PyCFunction)(void(*)(void))signal_set_wakeup_fd, METH_VARARGS | METH_KEYWORDS, set_wakeup_fd_doc},
Expand Down