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
12 changes: 6 additions & 6 deletions Doc/c-api/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -519,13 +519,13 @@ Signal Handling
single: SIGINT
single: KeyboardInterrupt (built-in exception)

This function simulates the effect of a :const:`SIGINT` signal arriving --- the
next time :c:func:`PyErr_CheckSignals` is called, :exc:`KeyboardInterrupt` will
be raised. It may be called without holding the interpreter lock.

.. % XXX This was described as obsolete, but is used in
.. % _thread.interrupt_main() (used from IDLE), so it's still needed.
Simulate the effect of a :const:`SIGINT` signal arriving. The next time
:c:func:`PyErr_CheckSignals` is called, the Python signal handler for
:const:`SIGINT` will be called.

If :const:`SIGINT` isn't handled by Python (it was set to
:data:`signal.SIG_DFL` or :data:`signal.SIG_IGN`), this function does
nothing.

.. c:function:: int PySignal_SetWakeupFd(int fd)

Expand Down
8 changes: 6 additions & 2 deletions Doc/library/_thread.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ This module defines the following constants and functions:

.. function:: interrupt_main()

Raise a :exc:`KeyboardInterrupt` exception in the main thread. A subthread can
use this function to interrupt the main thread.
Simulate the effect of a :data:`signal.SIGINT` signal arriving in the main
thread. A thread can use this function to interrupt the main thread.

If :data:`signal.SIGINT` isn't handled by Python (it was set to
:data:`signal.SIG_DFL` or :data:`signal.SIG_IGN`), this function does
nothing.


.. function:: exit()
Expand Down
35 changes: 35 additions & 0 deletions Lib/test/test_threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import weakref
import os
import subprocess
import signal

from test import lock_tests
from test import support
Expand Down Expand Up @@ -1168,12 +1169,46 @@ class BoundedSemaphoreTests(lock_tests.BoundedSemaphoreTests):
class BarrierTests(lock_tests.BarrierTests):
barriertype = staticmethod(threading.Barrier)


class MiscTestCase(unittest.TestCase):
def test__all__(self):
extra = {"ThreadError"}
blacklist = {'currentThread', 'activeCount'}
support.check__all__(self, threading, ('threading', '_thread'),
extra=extra, blacklist=blacklist)


class InterruptMainTests(unittest.TestCase):
def test_interrupt_main_subthread(self):
# Calling start_new_thread with a function that executes interrupt_main
# should raise KeyboardInterrupt upon completion.
def call_interrupt():
_thread.interrupt_main()
t = threading.Thread(target=call_interrupt)
with self.assertRaises(KeyboardInterrupt):
t.start()
t.join()
t.join()

def test_interrupt_main_mainthread(self):
# Make sure that if interrupt_main is called in main thread that
# KeyboardInterrupt is raised instantly.
with self.assertRaises(KeyboardInterrupt):
_thread.interrupt_main()

def test_interrupt_main_noerror(self):
handler = signal.getsignal(signal.SIGINT)
try:
# No exception should arise.
signal.signal(signal.SIGINT, signal.SIG_IGN)
_thread.interrupt_main()

signal.signal(signal.SIGINT, signal.SIG_DFL)
_thread.interrupt_main()
finally:
# Restore original handler
signal.signal(signal.SIGINT, handler)


if __name__ == "__main__":
unittest.main()
2 changes: 1 addition & 1 deletion Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ Donn Cave
Charles Cazabon
Jesús Cea Avión
Per Cederqvist
Matej Cepl
Matěj Cepl
Carl Cerecke
Octavian Cerna
Michael Cetrulo
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
``_thread.interrupt_main()`` now avoids setting the Python error status
if the ``SIGINT`` signal is ignored or not handled by Python.
13 changes: 9 additions & 4 deletions Modules/signalmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1683,13 +1683,18 @@ _PyErr_CheckSignals(void)
}


/* Replacements for intrcheck.c functionality
* Declared in pyerrors.h
*/
/* Simulate the effect of a signal.SIGINT signal arriving. The next time
PyErr_CheckSignals is called, the Python SIGINT signal handler will be
raised.

Missing signal handler for the SIGINT signal is silently ignored. */
void
PyErr_SetInterrupt(void)
{
trip_signal(SIGINT);
if ((Handlers[SIGINT].func != IgnoreHandler) &&
(Handlers[SIGINT].func != DefaultHandler)) {
trip_signal(SIGINT);
}
}

void
Expand Down