mirror of https://github.com/python/cpython
Issue #8407: Add pthread_kill(), sigpending() and sigwait() functions to the
signal module.
This commit is contained in:
parent
2c736bb38e
commit
b3e7219abf
|
@ -2284,6 +2284,8 @@ written in Python, such as a mail server's external command delivery program.
|
||||||
will be set to *sig*. The Windows version of :func:`kill` additionally takes
|
will be set to *sig*. The Windows version of :func:`kill` additionally takes
|
||||||
process handles to be killed.
|
process handles to be killed.
|
||||||
|
|
||||||
|
See also :func:`signal.pthread_kill`.
|
||||||
|
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
Windows support.
|
Windows support.
|
||||||
|
|
||||||
|
|
|
@ -179,6 +179,29 @@ The :mod:`signal` module defines the following functions:
|
||||||
will then be called. Returns nothing. Not on Windows. (See the Unix man page
|
will then be called. Returns nothing. Not on Windows. (See the Unix man page
|
||||||
:manpage:`signal(2)`.)
|
:manpage:`signal(2)`.)
|
||||||
|
|
||||||
|
See also :func:`sigwait` and :func:`sigpending`.
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: pthread_kill(thread_id, signum)
|
||||||
|
|
||||||
|
Send the signal *signum* to the thread *thread_id*, another thread in the same
|
||||||
|
process as the caller. The signal is asynchronously directed to thread.
|
||||||
|
|
||||||
|
*thread_id* can be read from the :attr:`~threading.Thread.ident` attribute
|
||||||
|
of :attr:`threading.Thread`. For example,
|
||||||
|
``threading.current_thread().ident`` gives the identifier of the current
|
||||||
|
thread.
|
||||||
|
|
||||||
|
If *signum* is 0, then no signal is sent, but error checking is still
|
||||||
|
performed; this can be used to check if a thread is still running.
|
||||||
|
|
||||||
|
Availability: Unix (see the man page :manpage:`pthread_kill(3)` for further
|
||||||
|
information).
|
||||||
|
|
||||||
|
See also :func:`os.kill`.
|
||||||
|
|
||||||
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
||||||
.. function:: pthread_sigmask(how, mask)
|
.. function:: pthread_sigmask(how, mask)
|
||||||
|
|
||||||
|
@ -206,6 +229,8 @@ The :mod:`signal` module defines the following functions:
|
||||||
Availability: Unix. See the man page :manpage:`sigprocmask(3)` and
|
Availability: Unix. See the man page :manpage:`sigprocmask(3)` and
|
||||||
:manpage:`pthread_sigmask(3)` for further information.
|
:manpage:`pthread_sigmask(3)` for further information.
|
||||||
|
|
||||||
|
See also :func:`pause`, :func:`sigpending` and :func:`sigwait`.
|
||||||
|
|
||||||
.. versionadded:: 3.3
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
||||||
|
@ -283,6 +308,34 @@ The :mod:`signal` module defines the following functions:
|
||||||
:const:`SIGTERM`. A :exc:`ValueError` will be raised in any other case.
|
:const:`SIGTERM`. A :exc:`ValueError` will be raised in any other case.
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: sigpending()
|
||||||
|
|
||||||
|
Examine the set of signals that are pending for delivery to the calling
|
||||||
|
thread (i.e., the signals which have been raised while blocked). Return the
|
||||||
|
set of the pending signals.
|
||||||
|
|
||||||
|
Availability: Unix (see the man page :manpage:`sigpending(2)` for further
|
||||||
|
information).
|
||||||
|
|
||||||
|
See also :func:`pause`, :func:`pthread_sigmask` and :func:`sigwait`.
|
||||||
|
|
||||||
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: sigwait(sigset)
|
||||||
|
|
||||||
|
Suspend execution of the calling thread until the delivery of one of the
|
||||||
|
signals specified in the signal set *sigset*. The function accepts the signal
|
||||||
|
(removes it from the pending list of signals), and returns the signal number.
|
||||||
|
|
||||||
|
Availability: Unix (see the man page :manpage:`sigwait(3)` for further
|
||||||
|
information).
|
||||||
|
|
||||||
|
See also :func:`pause`, :func:`pthread_sigmask` and :func:`sigpending`.
|
||||||
|
|
||||||
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
||||||
.. _signal-example:
|
.. _signal-example:
|
||||||
|
|
||||||
Example
|
Example
|
||||||
|
|
|
@ -123,10 +123,13 @@ sys
|
||||||
signal
|
signal
|
||||||
------
|
------
|
||||||
|
|
||||||
* The :mod:`signal` module has a new :func:`~signal.pthread_sigmask` function
|
* The :mod:`signal` module has a new functions:
|
||||||
to fetch and/or change the signal mask of the calling thread.
|
|
||||||
|
|
||||||
(Contributed by Jean-Paul Calderone in :issue:`8407`)
|
* :func:`~signal.pthread_sigmask`: fetch and/or change the signal mask of the
|
||||||
|
calling thread (Contributed by Jean-Paul Calderone in :issue:`8407`) ;
|
||||||
|
* :func:`~signal.pthread_kill`: send a signal to a thread ;
|
||||||
|
* :func:`~signal.sigpending`: examine pending functions ;
|
||||||
|
* :func:`~signal.sigwait`: wait a signal.
|
||||||
|
|
||||||
|
|
||||||
Optimizations
|
Optimizations
|
||||||
|
|
|
@ -8,6 +8,10 @@ import signal
|
||||||
import subprocess
|
import subprocess
|
||||||
import traceback
|
import traceback
|
||||||
import sys, os, time, errno
|
import sys, os, time, errno
|
||||||
|
try:
|
||||||
|
import threading
|
||||||
|
except ImportError:
|
||||||
|
threading = None
|
||||||
|
|
||||||
if sys.platform in ('os2', 'riscos'):
|
if sys.platform in ('os2', 'riscos'):
|
||||||
raise unittest.SkipTest("Can't test signal on %s" % sys.platform)
|
raise unittest.SkipTest("Can't test signal on %s" % sys.platform)
|
||||||
|
@ -187,7 +191,7 @@ class InterProcessSignalTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
|
@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
|
||||||
class BasicSignalTests(unittest.TestCase):
|
class PosixTests(unittest.TestCase):
|
||||||
def trivial_signal_handler(self, *args):
|
def trivial_signal_handler(self, *args):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -484,50 +488,121 @@ class ItimerTest(unittest.TestCase):
|
||||||
self.assertEqual(self.hndl_called, True)
|
self.assertEqual(self.hndl_called, True)
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
|
|
||||||
'need signal.pthread_sigmask()')
|
|
||||||
class PendingSignalsTests(unittest.TestCase):
|
class PendingSignalsTests(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
Tests for the pthread_sigmask() function.
|
Test pthread_sigmask(), pthread_kill(), sigpending() and sigwait()
|
||||||
|
functions.
|
||||||
"""
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
self.has_pthread_kill = hasattr(signal, 'pthread_kill')
|
||||||
|
|
||||||
def handler(self, signum, frame):
|
def handler(self, signum, frame):
|
||||||
1/0
|
1/0
|
||||||
|
|
||||||
def read_sigmask(self):
|
def read_sigmask(self):
|
||||||
return signal.pthread_sigmask(signal.SIG_BLOCK, [])
|
return signal.pthread_sigmask(signal.SIG_BLOCK, [])
|
||||||
|
|
||||||
def test_pthread_sigmask_arguments(self):
|
def can_test_blocked_signals(self, skip):
|
||||||
self.assertRaises(TypeError, signal.pthread_sigmask)
|
"""
|
||||||
self.assertRaises(TypeError, signal.pthread_sigmask, 1)
|
Check if a blocked signal can be raised to the main thread without
|
||||||
self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3)
|
calling its signal handler. We need pthread_kill() or exactly one
|
||||||
self.assertRaises(RuntimeError, signal.pthread_sigmask, 1700, [])
|
thread (the main thread).
|
||||||
|
|
||||||
def test_pthread_sigmask(self):
|
Return True if it's possible. Otherwise, return False and print a
|
||||||
import faulthandler
|
warning if skip is False, or raise a SkipTest exception if skip is
|
||||||
pid = os.getpid()
|
True.
|
||||||
signum = signal.SIGUSR1
|
"""
|
||||||
|
if self.has_pthread_kill:
|
||||||
|
return True
|
||||||
|
|
||||||
# The fault handler timeout thread masks all signals. If the main
|
# The fault handler timeout thread masks all signals. If the main
|
||||||
# thread masks also SIGUSR1, all threads mask this signal. In this
|
# thread masks also SIGUSR1, all threads mask this signal. In this
|
||||||
# case, if we send SIGUSR1 to the process, the signal is pending in the
|
# case, if we send SIGUSR1 to the process, the signal is pending in the
|
||||||
# main or the faulthandler timeout thread. Unblock SIGUSR1 in the main
|
# main or the faulthandler timeout thread. Unblock SIGUSR1 in the main
|
||||||
# thread calls the signal handler only if the signal is pending for the
|
# thread calls the signal handler only if the signal is pending for the
|
||||||
# main thread.
|
# main thread. Stop the faulthandler timeout thread to workaround this
|
||||||
#
|
# problem.
|
||||||
# Stop the faulthandler timeout thread to workaround this problem.
|
import faulthandler
|
||||||
# Another solution would be to send the signal directly to the main
|
|
||||||
# thread using pthread_kill(), but Python doesn't expose this
|
|
||||||
# function.
|
|
||||||
faulthandler.cancel_dump_tracebacks_later()
|
faulthandler.cancel_dump_tracebacks_later()
|
||||||
|
|
||||||
# Issue #11998: The _tkinter module loads the Tcl library which creates
|
# Issue #11998: The _tkinter module loads the Tcl library which
|
||||||
# a thread waiting events in select(). This thread receives signals
|
# creates a thread waiting events in select(). This thread receives
|
||||||
# blocked by all other threads. We cannot test blocked signals if the
|
# signals blocked by all other threads. We cannot test blocked
|
||||||
# _tkinter module is loaded.
|
# signals
|
||||||
can_test_blocked_signals = ('_tkinter' not in sys.modules)
|
if '_tkinter' in sys.modules:
|
||||||
if not can_test_blocked_signals:
|
message = ("_tkinter is loaded and pthread_kill() is missing, "
|
||||||
print("WARNING: _tkinter is loaded, cannot test signals "
|
"cannot test blocked signals (issue #11998)")
|
||||||
"blocked by pthread_sigmask() (issue #11998)")
|
if skip:
|
||||||
|
self.skipTest(message)
|
||||||
|
else:
|
||||||
|
print("WARNING: %s" % message)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def kill(self, signum):
|
||||||
|
if self.has_pthread_kill:
|
||||||
|
tid = threading.current_thread().ident
|
||||||
|
signal.pthread_kill(tid, signum)
|
||||||
|
else:
|
||||||
|
pid = os.getpid()
|
||||||
|
os.kill(pid, signum)
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(signal, 'sigpending'),
|
||||||
|
'need signal.sigpending()')
|
||||||
|
def test_sigpending_empty(self):
|
||||||
|
self.assertEqual(signal.sigpending(), set())
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
|
||||||
|
'need signal.pthread_sigmask()')
|
||||||
|
@unittest.skipUnless(hasattr(signal, 'sigpending'),
|
||||||
|
'need signal.sigpending()')
|
||||||
|
def test_sigpending(self):
|
||||||
|
self.can_test_blocked_signals(True)
|
||||||
|
|
||||||
|
signum = signal.SIGUSR1
|
||||||
|
old_handler = signal.signal(signum, self.handler)
|
||||||
|
self.addCleanup(signal.signal, signum, old_handler)
|
||||||
|
|
||||||
|
signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
|
||||||
|
self.kill(signum)
|
||||||
|
self.assertEqual(signal.sigpending(), {signum})
|
||||||
|
with self.assertRaises(ZeroDivisionError):
|
||||||
|
signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(signal, 'pthread_kill'),
|
||||||
|
'need signal.pthread_kill()')
|
||||||
|
def test_pthread_kill(self):
|
||||||
|
signum = signal.SIGUSR1
|
||||||
|
current = threading.current_thread().ident
|
||||||
|
|
||||||
|
old_handler = signal.signal(signum, self.handler)
|
||||||
|
self.addCleanup(signal.signal, signum, old_handler)
|
||||||
|
|
||||||
|
with self.assertRaises(ZeroDivisionError):
|
||||||
|
signal.pthread_kill(current, signum)
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(signal, 'sigwait'),
|
||||||
|
'need signal.sigwait()')
|
||||||
|
def test_sigwait(self):
|
||||||
|
old_handler = signal.signal(signal.SIGALRM, self.handler)
|
||||||
|
self.addCleanup(signal.signal, signal.SIGALRM, old_handler)
|
||||||
|
|
||||||
|
signal.alarm(1)
|
||||||
|
self.assertEqual(signal.sigwait([signal.SIGALRM]), signal.SIGALRM)
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
|
||||||
|
'need signal.pthread_sigmask()')
|
||||||
|
def test_pthread_sigmask_arguments(self):
|
||||||
|
self.assertRaises(TypeError, signal.pthread_sigmask)
|
||||||
|
self.assertRaises(TypeError, signal.pthread_sigmask, 1)
|
||||||
|
self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3)
|
||||||
|
self.assertRaises(OSError, signal.pthread_sigmask, 1700, [])
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
|
||||||
|
'need signal.pthread_sigmask()')
|
||||||
|
def test_pthread_sigmask(self):
|
||||||
|
test_blocked_signals = self.can_test_blocked_signals(False)
|
||||||
|
signum = signal.SIGUSR1
|
||||||
|
|
||||||
# Install our signal handler
|
# Install our signal handler
|
||||||
old_handler = signal.signal(signum, self.handler)
|
old_handler = signal.signal(signum, self.handler)
|
||||||
|
@ -537,13 +612,13 @@ class PendingSignalsTests(unittest.TestCase):
|
||||||
old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
|
old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
|
||||||
self.addCleanup(signal.pthread_sigmask, signal.SIG_SETMASK, old_mask)
|
self.addCleanup(signal.pthread_sigmask, signal.SIG_SETMASK, old_mask)
|
||||||
with self.assertRaises(ZeroDivisionError):
|
with self.assertRaises(ZeroDivisionError):
|
||||||
os.kill(pid, signum)
|
self.kill(signum)
|
||||||
|
|
||||||
# Block and then raise SIGUSR1. The signal is blocked: the signal
|
# Block and then raise SIGUSR1. The signal is blocked: the signal
|
||||||
# handler is not called, and the signal is now pending
|
# handler is not called, and the signal is now pending
|
||||||
signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
|
signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
|
||||||
if can_test_blocked_signals:
|
if test_blocked_signals:
|
||||||
os.kill(pid, signum)
|
self.kill(signum)
|
||||||
|
|
||||||
# Check the new mask
|
# Check the new mask
|
||||||
blocked = self.read_sigmask()
|
blocked = self.read_sigmask()
|
||||||
|
@ -551,14 +626,14 @@ class PendingSignalsTests(unittest.TestCase):
|
||||||
self.assertEqual(old_mask ^ blocked, {signum})
|
self.assertEqual(old_mask ^ blocked, {signum})
|
||||||
|
|
||||||
# Unblock SIGUSR1
|
# Unblock SIGUSR1
|
||||||
if can_test_blocked_signals:
|
if test_blocked_signals:
|
||||||
with self.assertRaises(ZeroDivisionError):
|
with self.assertRaises(ZeroDivisionError):
|
||||||
# unblock the pending signal calls immediatly the signal handler
|
# unblock the pending signal calls immediatly the signal handler
|
||||||
signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
|
signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
|
||||||
else:
|
else:
|
||||||
signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
|
signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
|
||||||
with self.assertRaises(ZeroDivisionError):
|
with self.assertRaises(ZeroDivisionError):
|
||||||
os.kill(pid, signum)
|
self.kill(signum)
|
||||||
|
|
||||||
# Check the new mask
|
# Check the new mask
|
||||||
unblocked = self.read_sigmask()
|
unblocked = self.read_sigmask()
|
||||||
|
@ -570,7 +645,7 @@ class PendingSignalsTests(unittest.TestCase):
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
try:
|
try:
|
||||||
support.run_unittest(BasicSignalTests, InterProcessSignalTests,
|
support.run_unittest(PosixTests, InterProcessSignalTests,
|
||||||
WakeupSignalTests, SiginterruptTest,
|
WakeupSignalTests, SiginterruptTest,
|
||||||
ItimerTest, WindowsSignalTests,
|
ItimerTest, WindowsSignalTests,
|
||||||
PendingSignalsTests)
|
PendingSignalsTests)
|
||||||
|
|
|
@ -140,6 +140,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #8407: Add pthread_kill(), sigpending() and sigwait() functions to the
|
||||||
|
signal module.
|
||||||
|
|
||||||
- Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch
|
- Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch
|
||||||
by Kasun Herath.
|
by Kasun Herath.
|
||||||
|
|
||||||
|
|
|
@ -503,7 +503,7 @@ PyDoc_STRVAR(getitimer_doc,
|
||||||
Returns current value of given itimer.");
|
Returns current value of given itimer.");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PYPTHREAD_SIGMASK
|
#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGWAIT)
|
||||||
/* Convert an iterable to a sigset.
|
/* Convert an iterable to a sigset.
|
||||||
Return 0 on success, return -1 and raise an exception on error. */
|
Return 0 on success, return -1 and raise an exception on error. */
|
||||||
|
|
||||||
|
@ -551,7 +551,9 @@ error:
|
||||||
Py_XDECREF(iterator);
|
Py_XDECREF(iterator);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGPENDING)
|
||||||
static PyObject*
|
static PyObject*
|
||||||
sigset_to_set(sigset_t mask)
|
sigset_to_set(sigset_t mask)
|
||||||
{
|
{
|
||||||
|
@ -585,7 +587,9 @@ sigset_to_set(sigset_t mask)
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PYPTHREAD_SIGMASK
|
||||||
static PyObject *
|
static PyObject *
|
||||||
signal_pthread_sigmask(PyObject *self, PyObject *args)
|
signal_pthread_sigmask(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
@ -603,7 +607,7 @@ signal_pthread_sigmask(PyObject *self, PyObject *args)
|
||||||
err = pthread_sigmask(how, &mask, &previous);
|
err = pthread_sigmask(how, &mask, &previous);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
errno = err;
|
errno = err;
|
||||||
PyErr_SetFromErrno(PyExc_RuntimeError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,6 +625,88 @@ Fetch and/or change the signal mask of the calling thread.");
|
||||||
#endif /* #ifdef PYPTHREAD_SIGMASK */
|
#endif /* #ifdef PYPTHREAD_SIGMASK */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_SIGPENDING
|
||||||
|
static PyObject *
|
||||||
|
signal_sigpending(PyObject *self)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
sigset_t mask;
|
||||||
|
err = sigpending(&mask);
|
||||||
|
if (err)
|
||||||
|
return PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return sigset_to_set(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(signal_sigpending_doc,
|
||||||
|
"sigpending() -> list\n\
|
||||||
|
\n\
|
||||||
|
Examine pending signals.");
|
||||||
|
#endif /* #ifdef HAVE_SIGPENDING */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_SIGWAIT
|
||||||
|
static PyObject *
|
||||||
|
signal_sigwait(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *signals;
|
||||||
|
sigset_t set;
|
||||||
|
int err, signum;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O:sigwait", &signals))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (iterable_to_sigset(signals, &set))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
err = sigwait(&set, &signum);
|
||||||
|
if (err) {
|
||||||
|
errno = err;
|
||||||
|
return PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyLong_FromLong(signum);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(signal_sigwait_doc,
|
||||||
|
"sigwait(sigset) -> signum\n\
|
||||||
|
\n\
|
||||||
|
Wait a signal.");
|
||||||
|
#endif /* #ifdef HAVE_SIGPENDING */
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(HAVE_PTHREAD_KILL) && defined(WITH_THREAD)
|
||||||
|
static PyObject *
|
||||||
|
signal_pthread_kill(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
long tid;
|
||||||
|
int signum;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "li:pthread_kill", &tid, &signum))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
err = pthread_kill(tid, signum);
|
||||||
|
if (err != 0) {
|
||||||
|
errno = err;
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the signal may have been send to the current thread */
|
||||||
|
if (PyErr_CheckSignals())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(signal_pthread_kill_doc,
|
||||||
|
"pthread_kill(thread_id, signum)\n\
|
||||||
|
\n\
|
||||||
|
Send a signal to a thread.");
|
||||||
|
#endif /* #if defined(HAVE_PTHREAD_KILL) && defined(WITH_THREAD) */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* List of functions defined in the module */
|
/* List of functions defined in the module */
|
||||||
static PyMethodDef signal_methods[] = {
|
static PyMethodDef signal_methods[] = {
|
||||||
#ifdef HAVE_ALARM
|
#ifdef HAVE_ALARM
|
||||||
|
@ -644,9 +730,21 @@ static PyMethodDef signal_methods[] = {
|
||||||
#endif
|
#endif
|
||||||
{"default_int_handler", signal_default_int_handler,
|
{"default_int_handler", signal_default_int_handler,
|
||||||
METH_VARARGS, default_int_handler_doc},
|
METH_VARARGS, default_int_handler_doc},
|
||||||
|
#if defined(HAVE_PTHREAD_KILL) && defined(WITH_THREAD)
|
||||||
|
{"pthread_kill", (PyCFunction)signal_pthread_kill,
|
||||||
|
METH_VARARGS, signal_pthread_kill_doc},
|
||||||
|
#endif
|
||||||
#ifdef PYPTHREAD_SIGMASK
|
#ifdef PYPTHREAD_SIGMASK
|
||||||
{"pthread_sigmask", (PyCFunction)signal_pthread_sigmask,
|
{"pthread_sigmask", (PyCFunction)signal_pthread_sigmask,
|
||||||
METH_VARARGS, signal_pthread_sigmask_doc},
|
METH_VARARGS, signal_pthread_sigmask_doc},
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SIGPENDING
|
||||||
|
{"sigpending", (PyCFunction)signal_sigpending,
|
||||||
|
METH_NOARGS, signal_sigpending_doc},
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SIGWAIT
|
||||||
|
{"sigwait", (PyCFunction)signal_sigwait,
|
||||||
|
METH_VARARGS, signal_sigwait_doc},
|
||||||
#endif
|
#endif
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
|
@ -9258,11 +9258,12 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
|
||||||
initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \
|
initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \
|
||||||
mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \
|
mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \
|
||||||
posix_fallocate posix_fadvise pread \
|
posix_fallocate posix_fadvise pread \
|
||||||
pthread_init putenv pwrite readlink readlinkat readv realpath renameat \
|
pthread_init pthread_kill putenv pwrite readlink readlinkat readv realpath renameat \
|
||||||
select sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
|
select sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
|
||||||
setgid sethostname \
|
setgid sethostname \
|
||||||
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
|
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
|
||||||
sigaction sigaltstack siginterrupt sigrelse snprintf strftime strlcpy symlinkat sync \
|
sigaction sigaltstack siginterrupt sigpending \
|
||||||
|
sigrelse sigwait snprintf strftime strlcpy symlinkat sync \
|
||||||
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
|
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
|
||||||
truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \
|
truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \
|
||||||
wcscoll wcsftime wcsxfrm writev _getpty
|
wcscoll wcsftime wcsxfrm writev _getpty
|
||||||
|
|
|
@ -2503,11 +2503,12 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
|
||||||
initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \
|
initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \
|
||||||
mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \
|
mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \
|
||||||
posix_fallocate posix_fadvise pread \
|
posix_fallocate posix_fadvise pread \
|
||||||
pthread_init putenv pwrite readlink readlinkat readv realpath renameat \
|
pthread_init pthread_kill putenv pwrite readlink readlinkat readv realpath renameat \
|
||||||
select sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
|
select sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
|
||||||
setgid sethostname \
|
setgid sethostname \
|
||||||
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
|
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
|
||||||
sigaction sigaltstack siginterrupt sigrelse snprintf strftime strlcpy symlinkat sync \
|
sigaction sigaltstack siginterrupt sigpending \
|
||||||
|
sigrelse sigwait snprintf strftime strlcpy symlinkat sync \
|
||||||
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
|
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
|
||||||
truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \
|
truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \
|
||||||
wcscoll wcsftime wcsxfrm writev _getpty)
|
wcscoll wcsftime wcsxfrm writev _getpty)
|
||||||
|
|
|
@ -590,6 +590,9 @@
|
||||||
/* Define to 1 if you have the `pthread_sigmask' function. */
|
/* Define to 1 if you have the `pthread_sigmask' function. */
|
||||||
#undef HAVE_PTHREAD_SIGMASK
|
#undef HAVE_PTHREAD_SIGMASK
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `pthread_kill' function. */
|
||||||
|
#undef HAVE_PTHREAD_KILL
|
||||||
|
|
||||||
/* Define to 1 if you have the <pty.h> header file. */
|
/* Define to 1 if you have the <pty.h> header file. */
|
||||||
#undef HAVE_PTY_H
|
#undef HAVE_PTY_H
|
||||||
|
|
||||||
|
@ -719,12 +722,18 @@
|
||||||
/* Define to 1 if you have the `siginterrupt' function. */
|
/* Define to 1 if you have the `siginterrupt' function. */
|
||||||
#undef HAVE_SIGINTERRUPT
|
#undef HAVE_SIGINTERRUPT
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `sigpending' function. */
|
||||||
|
#undef HAVE_SIGPENDING
|
||||||
|
|
||||||
/* Define to 1 if you have the <signal.h> header file. */
|
/* Define to 1 if you have the <signal.h> header file. */
|
||||||
#undef HAVE_SIGNAL_H
|
#undef HAVE_SIGNAL_H
|
||||||
|
|
||||||
/* Define to 1 if you have the `sigrelse' function. */
|
/* Define to 1 if you have the `sigrelse' function. */
|
||||||
#undef HAVE_SIGRELSE
|
#undef HAVE_SIGRELSE
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `sigwait' function. */
|
||||||
|
#undef HAVE_SIGWAIT
|
||||||
|
|
||||||
/* Define to 1 if you have the `snprintf' function. */
|
/* Define to 1 if you have the `snprintf' function. */
|
||||||
#undef HAVE_SNPRINTF
|
#undef HAVE_SNPRINTF
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue