Skip to content

Commit c24c6c2

Browse files
vladimamiss-islington
authored andcommitted
bpo-35568: add 'raise_signal' function (GH-11335)
As in title, expose C `raise` function as `raise_function` in `signal` module. Also drop existing `raise_signal` in `_testcapi` module and replace all usages with new function. https://bugs.python.org/issue35568
1 parent e61cc48 commit c24c6c2

10 files changed

Lines changed: 122 additions & 47 deletions

File tree

Doc/library/signal.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,13 @@ The :mod:`signal` module defines the following functions:
237237
:func:`sigpending`.
238238

239239

240+
.. function:: raise_signal(signum)
241+
242+
Sends a signal to the calling process. Returns nothing.
243+
244+
.. versionadded:: 3.8
245+
246+
240247
.. function:: pthread_kill(thread_id, signalnum)
241248

242249
Send the signal *signalnum* to the thread *thread_id*, another thread in the

Lib/test/test_asyncio/test_windows_events.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def test_ctrl_c(self):
4545

4646
def SIGINT_after_delay():
4747
time.sleep(1)
48-
_testcapi.raise_signal(signal.SIGINT)
48+
signal.raise_signal(signal.SIGINT)
4949

5050
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
5151
l = asyncio.get_event_loop()

Lib/test/test_faulthandler.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,29 +198,27 @@ def test_sigfpe(self):
198198
@skip_segfault_on_android
199199
def test_sigbus(self):
200200
self.check_fatal_error("""
201-
import _testcapi
202201
import faulthandler
203202
import signal
204203
205204
faulthandler.enable()
206-
_testcapi.raise_signal(signal.SIGBUS)
205+
signal.raise_signal(signal.SIGBUS)
207206
""",
208-
6,
207+
5,
209208
'Bus error')
210209

211210
@unittest.skipIf(_testcapi is None, 'need _testcapi')
212211
@unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
213212
@skip_segfault_on_android
214213
def test_sigill(self):
215214
self.check_fatal_error("""
216-
import _testcapi
217215
import faulthandler
218216
import signal
219217
220218
faulthandler.enable()
221-
_testcapi.raise_signal(signal.SIGILL)
219+
signal.raise_signal(signal.SIGILL)
222220
""",
223-
6,
221+
5,
224222
'Illegal instruction')
225223

226224
def test_fatal_error(self):

Lib/test/test_posix.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,8 +1596,8 @@ def test_setpgroup_wrong_type(self):
15961596
'need signal.pthread_sigmask()')
15971597
def test_setsigmask(self):
15981598
code = textwrap.dedent("""\
1599-
import _testcapi, signal
1600-
_testcapi.raise_signal(signal.SIGUSR1)""")
1599+
import signal
1600+
signal.raise_signal(signal.SIGUSR1)""")
16011601

16021602
pid = posix.posix_spawn(
16031603
sys.executable,
@@ -1627,8 +1627,8 @@ def test_setsigmask_wrong_type(self):
16271627
def test_setsigdef(self):
16281628
original_handler = signal.signal(signal.SIGUSR1, signal.SIG_IGN)
16291629
code = textwrap.dedent("""\
1630-
import _testcapi, signal
1631-
_testcapi.raise_signal(signal.SIGUSR1)""")
1630+
import signal
1631+
signal.raise_signal(signal.SIGUSR1)""")
16321632
try:
16331633
pid = posix.posix_spawn(
16341634
sys.executable,

Lib/test/test_regrtest.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@
2626
ROOT_DIR = os.path.abspath(os.path.normpath(ROOT_DIR))
2727

2828
TEST_INTERRUPTED = textwrap.dedent("""
29-
from signal import SIGINT
29+
from signal import SIGINT, raise_signal
3030
try:
31-
from _testcapi import raise_signal
3231
raise_signal(SIGINT)
3332
except ImportError:
3433
import os

Lib/test/test_signal.py

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import errno
12
import os
23
import random
34
import signal
@@ -254,7 +255,7 @@ def handler(signum, frame):
254255
signal.set_wakeup_fd(r)
255256
try:
256257
with captured_stderr() as err:
257-
_testcapi.raise_signal(signal.SIGALRM)
258+
signal.raise_signal(signal.SIGALRM)
258259
except ZeroDivisionError:
259260
# An ignored exception should have been printed out on stderr
260261
err = err.getvalue()
@@ -348,10 +349,9 @@ def handler(signum, frame):
348349

349350
def test_signum(self):
350351
self.check_wakeup("""def test():
351-
import _testcapi
352352
signal.signal(signal.SIGUSR1, handler)
353-
_testcapi.raise_signal(signal.SIGUSR1)
354-
_testcapi.raise_signal(signal.SIGALRM)
353+
signal.raise_signal(signal.SIGUSR1)
354+
signal.raise_signal(signal.SIGALRM)
355355
""", signal.SIGUSR1, signal.SIGALRM)
356356

357357
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
@@ -365,8 +365,8 @@ def test_pending(self):
365365
signal.signal(signum2, handler)
366366
367367
signal.pthread_sigmask(signal.SIG_BLOCK, (signum1, signum2))
368-
_testcapi.raise_signal(signum1)
369-
_testcapi.raise_signal(signum2)
368+
signal.raise_signal(signum1)
369+
signal.raise_signal(signum2)
370370
# Unblocking the 2 signals calls the C signal handler twice
371371
signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2))
372372
""", signal.SIGUSR1, signal.SIGUSR2, ordered=False)
@@ -396,7 +396,7 @@ def handler(signum, frame):
396396
write.setblocking(False)
397397
signal.set_wakeup_fd(write.fileno())
398398
399-
_testcapi.raise_signal(signum)
399+
signal.raise_signal(signum)
400400
401401
data = read.recv(1)
402402
if not data:
@@ -445,7 +445,7 @@ def handler(signum, frame):
445445
write.close()
446446
447447
with captured_stderr() as err:
448-
_testcapi.raise_signal(signum)
448+
signal.raise_signal(signum)
449449
450450
err = err.getvalue()
451451
if ('Exception ignored when trying to {action} to the signal wakeup fd'
@@ -519,7 +519,7 @@ def handler(signum, frame):
519519
signal.set_wakeup_fd(write.fileno())
520520
521521
with captured_stderr() as err:
522-
_testcapi.raise_signal(signum)
522+
signal.raise_signal(signum)
523523
524524
err = err.getvalue()
525525
if msg not in err:
@@ -530,7 +530,7 @@ def handler(signum, frame):
530530
signal.set_wakeup_fd(write.fileno(), warn_on_full_buffer=True)
531531
532532
with captured_stderr() as err:
533-
_testcapi.raise_signal(signum)
533+
signal.raise_signal(signum)
534534
535535
err = err.getvalue()
536536
if msg not in err:
@@ -541,7 +541,7 @@ def handler(signum, frame):
541541
signal.set_wakeup_fd(write.fileno(), warn_on_full_buffer=False)
542542
543543
with captured_stderr() as err:
544-
_testcapi.raise_signal(signum)
544+
signal.raise_signal(signum)
545545
546546
err = err.getvalue()
547547
if err != "":
@@ -553,7 +553,7 @@ def handler(signum, frame):
553553
signal.set_wakeup_fd(write.fileno())
554554
555555
with captured_stderr() as err:
556-
_testcapi.raise_signal(signum)
556+
signal.raise_signal(signum)
557557
558558
err = err.getvalue()
559559
if msg not in err:
@@ -1214,6 +1214,38 @@ def handler(signum, frame):
12141214
# Python handler
12151215
self.assertEqual(len(sigs), N, "Some signals were lost")
12161216

1217+
class RaiseSignalTest(unittest.TestCase):
1218+
1219+
def test_sigint(self):
1220+
try:
1221+
signal.raise_signal(signal.SIGINT)
1222+
self.fail("Expected KeyInterrupt")
1223+
except KeyboardInterrupt:
1224+
pass
1225+
1226+
@unittest.skipIf(sys.platform != "win32", "Windows specific test")
1227+
def test_invalid_argument(self):
1228+
try:
1229+
SIGHUP = 1 # not supported on win32
1230+
signal.raise_signal(SIGHUP)
1231+
self.fail("OSError (Invalid argument) expected")
1232+
except OSError as e:
1233+
if e.errno == errno.EINVAL:
1234+
pass
1235+
else:
1236+
raise
1237+
1238+
def test_handler(self):
1239+
is_ok = False
1240+
def handler(a, b):
1241+
nonlocal is_ok
1242+
is_ok = True
1243+
old_signal = signal.signal(signal.SIGINT, handler)
1244+
self.addCleanup(signal.signal, signal.SIGINT, old_signal)
1245+
1246+
signal.raise_signal(signal.SIGINT)
1247+
self.assertTrue(is_ok)
1248+
12171249

12181250
def tearDownModule():
12191251
support.reap_children()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Expose ``raise(signum)`` as `raise_signal`

Modules/_testcapimodule.c

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3859,25 +3859,6 @@ call_in_temporary_c_thread(PyObject *self, PyObject *callback)
38593859
return res;
38603860
}
38613861

3862-
static PyObject*
3863-
test_raise_signal(PyObject* self, PyObject *args)
3864-
{
3865-
int signum, err;
3866-
3867-
if (!PyArg_ParseTuple(args, "i:raise_signal", &signum)) {
3868-
return NULL;
3869-
}
3870-
3871-
err = raise(signum);
3872-
if (err)
3873-
return PyErr_SetFromErrno(PyExc_OSError);
3874-
3875-
if (PyErr_CheckSignals() < 0)
3876-
return NULL;
3877-
3878-
Py_RETURN_NONE;
3879-
}
3880-
38813862
/* marshal */
38823863

38833864
static PyObject*
@@ -4908,8 +4889,6 @@ static PyMethodDef TestMethods[] = {
49084889
{"docstring_with_signature_with_defaults",
49094890
(PyCFunction)test_with_docstring, METH_NOARGS,
49104891
docstring_with_signature_with_defaults},
4911-
{"raise_signal",
4912-
(PyCFunction)test_raise_signal, METH_VARARGS},
49134892
{"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_O,
49144893
PyDoc_STR("set_error_class(error_class) -> None")},
49154894
{"pymarshal_write_long_to_file",

Modules/clinic/signalmodule.c.h

Lines changed: 34 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/signalmodule.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,31 @@ signal_pause_impl(PyObject *module)
390390

391391
#endif
392392

393+
/*[clinic input]
394+
signal.raise_signal
395+
396+
signalnum: int
397+
/
398+
399+
Send a signal to the executing process.
400+
[clinic start generated code]*/
401+
402+
static PyObject *
403+
signal_raise_signal_impl(PyObject *module, int signalnum)
404+
/*[clinic end generated code: output=e2b014220aa6111d input=e90c0f9a42358de6]*/
405+
{
406+
int err;
407+
Py_BEGIN_ALLOW_THREADS
408+
_Py_BEGIN_SUPPRESS_IPH
409+
err = raise(signalnum);
410+
_Py_END_SUPPRESS_IPH
411+
Py_END_ALLOW_THREADS
412+
413+
if (err) {
414+
return PyErr_SetFromErrno(PyExc_OSError);
415+
}
416+
Py_RETURN_NONE;
417+
}
393418

394419
/*[clinic input]
395420
signal.signal
@@ -1208,6 +1233,7 @@ static PyMethodDef signal_methods[] = {
12081233
SIGNAL_SETITIMER_METHODDEF
12091234
SIGNAL_GETITIMER_METHODDEF
12101235
SIGNAL_SIGNAL_METHODDEF
1236+
SIGNAL_RAISE_SIGNAL_METHODDEF
12111237
SIGNAL_STRSIGNAL_METHODDEF
12121238
SIGNAL_GETSIGNAL_METHODDEF
12131239
{"set_wakeup_fd", (PyCFunction)(void(*)(void))signal_set_wakeup_fd, METH_VARARGS | METH_KEYWORDS, set_wakeup_fd_doc},

0 commit comments

Comments
 (0)