Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
bc808224
Commit
bc808224
authored
Jun 25, 2011
by
Ross Lagerwall
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #12303: Add sigwaitinfo() and sigtimedwait() to the signal module.
parent
bb66972c
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
295 additions
and
23 deletions
+295
-23
Doc/library/signal.rst
Doc/library/signal.rst
+43
-2
Doc/whatsnew/3.3.rst
Doc/whatsnew/3.3.rst
+4
-0
Lib/test/test_signal.py
Lib/test/test_signal.py
+83
-16
Misc/NEWS
Misc/NEWS
+2
-0
Modules/signalmodule.c
Modules/signalmodule.c
+153
-1
configure
configure
+2
-2
configure.in
configure.in
+2
-2
pyconfig.h.in
pyconfig.h.in
+6
-0
No files found.
Doc/library/signal.rst
View file @
bc808224
...
...
@@ -179,7 +179,8 @@ The :mod:`signal` module defines the following functions:
will then be called. Returns nothing. Not on Windows. (See the Unix man page
:manpage:`signal(2)`.)
See also :func:`sigwait` and :func:`sigpending`.
See also :func:`sigwait`, :func:`sigwaitinfo`, :func:`sigtimedwait` and
:func:`sigpending`.
.. function:: pthread_kill(thread_id, signum)
...
...
@@ -334,7 +335,47 @@ The :mod:`signal` module defines the following functions:
Availability: Unix (see the man page :manpage:`sigwait(3)` for further
information).
See also :func:`pause`, :func:`pthread_sigmask` and :func:`sigpending`.
See also :func:`pause`, :func:`pthread_sigmask`, :func:`sigpending`,
:func:`sigwaitinfo` and :func:`sigtimedwait`.
.. versionadded:: 3.3
.. function:: sigwaitinfo(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 and removes it from the pending list of signals. If one of the
signals in *sigset* is already pending for the calling thread, the function
will return immediately with information about that signal. The signal
handler is not called for the delivered signal. The function raises an
:exc:`OSError` with error number set to :const:`errno.EINTR` if it is
interrupted by a signal that is not in *sigset*.
The return value is an object representing the data contained in the
:c:type:`siginfo_t` structure, namely: :attr:`si_signo`, :attr:`si_code`,
:attr:`si_errno`, :attr:`si_pid`, :attr:`si_uid`, :attr:`si_status`,
:attr:`si_band`.
Availability: Unix (see the man page :manpage:`sigwaitinfo(2)` for further
information).
See also :func:`pause`, :func:`sigwait` and :func:`sigtimedwait`.
.. versionadded:: 3.3
.. function:: sigtimedwait(sigset, (timeout_sec, timeout_nsec))
Like :func:`sigtimedwait`, but takes a tuple of ``(seconds, nanoseconds)``
as an additional argument specifying a timeout. If both *timeout_sec* and
*timeout_nsec* are specified as :const:`0`, a poll is performed. Returns
:const:`None` if a timeout occurs.
Availability: Unix (see the man page :manpage:`sigtimedwait(2)` for further
information).
See also :func:`pause`, :func:`sigwait` and :func:`sigwaitinfo`.
.. versionadded:: 3.3
...
...
Doc/whatsnew/3.3.rst
View file @
bc808224
...
...
@@ -169,6 +169,10 @@ signal
* :func:`~signal.pthread_kill`: send a signal to a thread ;
* :func:`~signal.sigpending`: examine pending functions ;
* :func:`~signal.sigwait`: wait a signal.
* :func:`~signal.sigwaitinfo`: wait for a signal, returning detailed
information about it.
* :func:`~signal.sigtimedwait`: like :func:`~signal.sigwaitinfo` but with a
timeout.
* The signal handler writes the signal number as a single byte instead of
a nul byte into the wakeup file descriptor. So it is possible to wait more
...
...
Lib/test/test_signal.py
View file @
bc808224
...
...
@@ -520,6 +520,7 @@ class PendingSignalsTests(unittest.TestCase):
functions.
"""
def
setUp
(
self
):
self
.
hndl_called
=
False
self
.
has_pthread_kill
=
hasattr
(
signal
,
'pthread_kill'
)
def
handler
(
self
,
signum
,
frame
):
...
...
@@ -607,45 +608,35 @@ class PendingSignalsTests(unittest.TestCase):
with
self
.
assertRaises
(
ZeroDivisionError
):
signal
.
pthread_kill
(
current
,
signum
)
@
unittest
.
skipUnless
(
hasattr
(
signal
,
'sigwait'
),
'need signal.sigwait()'
)
@
unittest
.
skipUnless
(
hasattr
(
signal
,
'pthread_sigmask'
),
'need signal.pthread_sigmask()'
)
@
unittest
.
skipUnless
(
hasattr
(
os
,
'fork'
),
'need os.fork()'
)
def
test_sigwait
(
self
):
def
test
(
signum
):
signal
.
alarm
(
1
)
received
=
signal
.
sigwait
([
signum
])
if
received
!=
signum
:
print
(
"sigwait() received %s, not %s"
%
(
received
,
signum
),
file
=
sys
.
stderr
)
os
.
_exit
(
1
)
def
wait_helper
(
self
,
test
,
handler
,
blocked
=
signal
.
SIGALRM
):
signum
=
signal
.
SIGALRM
# sig
wait
must be called with the signal blocked: since the current
# sig
*wait*
must be called with the signal blocked: since the current
# process might have several threads running, we fork() a child process
# to have a single thread.
pid
=
os
.
fork
()
if
pid
==
0
:
# child: block and wait the signal
try
:
signal
.
signal
(
signum
,
self
.
handler
)
signal
.
pthread_sigmask
(
signal
.
SIG_BLOCK
,
[
signum
])
signal
.
signal
(
signum
,
handler
)
signal
.
pthread_sigmask
(
signal
.
SIG_BLOCK
,
[
blocked
])
# Do the tests
test
(
signum
)
# The handler must not be called on unblock
try
:
signal
.
pthread_sigmask
(
signal
.
SIG_UNBLOCK
,
[
signum
])
signal
.
pthread_sigmask
(
signal
.
SIG_UNBLOCK
,
[
blocked
])
except
ZeroDivisionError
:
print
(
"the signal handler has been called"
,
file
=
sys
.
stderr
)
os
.
_exit
(
1
)
except
BaseException
as
err
:
print
(
"error: {}"
.
format
(
err
),
file
=
sys
.
stderr
)
sys
.
stderr
.
flush
()
os
.
_exit
(
1
)
else
:
os
.
_exit
(
0
)
...
...
@@ -653,6 +644,82 @@ class PendingSignalsTests(unittest.TestCase):
# parent: check that the child correcty received the signal
self
.
assertEqual
(
os
.
waitpid
(
pid
,
0
),
(
pid
,
0
))
@
unittest
.
skipUnless
(
hasattr
(
signal
,
'sigwait'
),
'need signal.sigwait()'
)
def
test_sigwait
(
self
):
def
test
(
signum
):
signal
.
alarm
(
1
)
self
.
assertEqual
(
signum
,
signal
.
sigwait
([
signum
]))
self
.
wait_helper
(
test
,
self
.
handler
)
@
unittest
.
skipUnless
(
hasattr
(
signal
,
'sigwaitinfo'
),
'need signal.sigwaitinfo()'
)
def
test_sigwaitinfo
(
self
):
def
test
(
signum
):
signal
.
alarm
(
1
)
info
=
signal
.
sigwaitinfo
([
signum
])
self
.
assertEqual
(
signum
,
info
.
si_signo
)
self
.
wait_helper
(
test
,
self
.
handler
)
@
unittest
.
skipUnless
(
hasattr
(
signal
,
'sigtimedwait'
),
'need signal.sigtimedwait()'
)
def
test_sigtimedwait
(
self
):
def
test
(
signum
):
signal
.
alarm
(
1
)
info
=
signal
.
sigtimedwait
([
signum
],
(
10
,
1000
))
self
.
assertEqual
(
signum
,
info
.
si_signo
)
self
.
wait_helper
(
test
,
self
.
handler
)
# check that polling with sigtimedwait works
@
unittest
.
skipUnless
(
hasattr
(
signal
,
'sigtimedwait'
),
'need signal.sigtimedwait()'
)
def
test_sigtimedwait_poll
(
self
):
def
test
(
signum
):
self
.
kill
(
signum
)
info
=
signal
.
sigtimedwait
([
signum
],
(
0
,
0
))
self
.
assertEqual
(
signum
,
info
.
si_signo
)
self
.
wait_helper
(
test
,
self
.
handler
)
@
unittest
.
skipUnless
(
hasattr
(
signal
,
'sigtimedwait'
),
'need signal.sigtimedwait()'
)
def
test_sigtimedwait_timeout
(
self
):
def
test
(
signum
):
self
.
assertEqual
(
None
,
signal
.
sigtimedwait
([
signum
],
(
1
,
35500
)))
self
.
wait_helper
(
test
,
self
.
handler
)
@
unittest
.
skipUnless
(
hasattr
(
signal
,
'sigtimedwait'
),
'need signal.sigtimedwait()'
)
def
test_sigtimedwait_negative_timeout
(
self
):
signum
=
signal
.
SIGALRM
self
.
assertRaises
(
ValueError
,
signal
.
sigtimedwait
,
[
signum
],
(
-
1
,
-
1
))
self
.
assertRaises
(
ValueError
,
signal
.
sigtimedwait
,
[
signum
],
(
0
,
-
1
))
self
.
assertRaises
(
ValueError
,
signal
.
sigtimedwait
,
[
signum
],
(
-
1
,
0
))
def
alarm_handler
(
self
,
signum
,
frame
):
self
.
hndl_called
=
True
@
unittest
.
skipUnless
(
hasattr
(
signal
,
'sigwaitinfo'
),
'need signal.sigwaitinfo()'
)
def
test_sigwaitinfo_interrupted
(
self
):
def
test
(
signum
):
signal
.
alarm
(
1
)
try
:
signal
.
sigwaitinfo
([
signal
.
SIGUSR1
])
except
OSError
as
e
:
if
e
.
errno
==
errno
.
EINTR
:
self
.
assertTrue
(
self
.
hndl_called
)
else
:
self
.
fail
(
"Expected EINTR to be raised by sigwaitinfo"
)
else
:
self
.
fail
(
"Expected EINTR to be raised by sigwaitinfo"
)
self
.
wait_helper
(
test
,
self
.
alarm_handler
,
signal
.
SIGUSR1
)
@
unittest
.
skipUnless
(
hasattr
(
signal
,
'sigwait'
),
'need signal.sigwait()'
)
@
unittest
.
skipUnless
(
hasattr
(
signal
,
'pthread_sigmask'
),
...
...
Misc/NEWS
View file @
bc808224
...
...
@@ -200,6 +200,8 @@ Core and Builtins
Library
-------
- Issue #12303: Add sigwaitinfo() and sigtimedwait() to the signal module.
- Issue #12404: Remove C89 incompatible code from mmap module. Patch by Akira
Kitada.
...
...
Modules/signalmodule.c
View file @
bc808224
...
...
@@ -507,7 +507,8 @@ PyDoc_STRVAR(getitimer_doc,
Returns current value of given itimer."
);
#endif
#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGWAIT)
#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGWAIT) || \
defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT)
/* Convert an iterable to a sigset.
Return 0 on success, return -1 and raise an exception on error. */
...
...
@@ -679,6 +680,140 @@ PyDoc_STRVAR(signal_sigwait_doc,
Wait a signal."
);
#endif
/* #ifdef HAVE_SIGPENDING */
#if defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT)
static
int
initialized
;
static
PyStructSequence_Field
struct_siginfo_fields
[]
=
{
{
"si_signo"
,
"signal number"
},
{
"si_code"
,
"signal code"
},
{
"si_errno"
,
"errno associated with this signal"
},
{
"si_pid"
,
"sending process ID"
},
{
"si_uid"
,
"real user ID of sending process"
},
{
"si_status"
,
"exit value or signal"
},
{
"si_band"
,
"band event for SIGPOLL"
},
{
0
}
};
PyDoc_STRVAR
(
struct_siginfo__doc__
,
"struct_siginfo: Result from sigwaitinfo or sigtimedwait.
\n\n
\
This object may be accessed either as a tuple of
\n
\
(si_signo, si_code, si_errno, si_pid, si_uid, si_status, si_band),
\n
\
or via the attributes si_signo, si_code, and so on."
);
static
PyStructSequence_Desc
struct_siginfo_desc
=
{
"signal.struct_siginfo"
,
/* name */
struct_siginfo__doc__
,
/* doc */
struct_siginfo_fields
,
/* fields */
7
/* n_in_sequence */
};
static
PyTypeObject
SiginfoType
;
static
PyObject
*
fill_siginfo
(
siginfo_t
*
si
)
{
PyObject
*
result
=
PyStructSequence_New
(
&
SiginfoType
);
if
(
!
result
)
return
NULL
;
PyStructSequence_SET_ITEM
(
result
,
0
,
PyLong_FromLong
((
long
)(
si
->
si_signo
)));
PyStructSequence_SET_ITEM
(
result
,
1
,
PyLong_FromLong
((
long
)(
si
->
si_code
)));
PyStructSequence_SET_ITEM
(
result
,
2
,
PyLong_FromLong
((
long
)(
si
->
si_errno
)));
PyStructSequence_SET_ITEM
(
result
,
3
,
PyLong_FromPid
(
si
->
si_pid
));
PyStructSequence_SET_ITEM
(
result
,
4
,
PyLong_FromLong
((
long
)(
si
->
si_uid
)));
PyStructSequence_SET_ITEM
(
result
,
5
,
PyLong_FromLong
((
long
)(
si
->
si_status
)));
PyStructSequence_SET_ITEM
(
result
,
6
,
PyLong_FromLong
(
si
->
si_band
));
if
(
PyErr_Occurred
())
{
Py_DECREF
(
result
);
return
NULL
;
}
return
result
;
}
#endif
#ifdef HAVE_SIGWAITINFO
static
PyObject
*
signal_sigwaitinfo
(
PyObject
*
self
,
PyObject
*
args
)
{
PyObject
*
signals
;
sigset_t
set
;
siginfo_t
si
;
int
err
;
if
(
!
PyArg_ParseTuple
(
args
,
"O:sigwaitinfo"
,
&
signals
))
return
NULL
;
if
(
iterable_to_sigset
(
signals
,
&
set
))
return
NULL
;
Py_BEGIN_ALLOW_THREADS
err
=
sigwaitinfo
(
&
set
,
&
si
);
Py_END_ALLOW_THREADS
if
(
err
==
-
1
)
return
PyErr_SetFromErrno
(
PyExc_OSError
);
return
fill_siginfo
(
&
si
);
}
PyDoc_STRVAR
(
signal_sigwaitinfo_doc
,
"sigwaitinfo(sigset) -> struct_siginfo
\n
\
\n
\
Wait synchronously for a signal until one of the signals in *sigset* is
\n
\
delivered.
\n
\
Returns a struct_siginfo containing information about the signal."
);
#endif
/* #ifdef HAVE_SIGWAITINFO */
#ifdef HAVE_SIGTIMEDWAIT
static
PyObject
*
signal_sigtimedwait
(
PyObject
*
self
,
PyObject
*
args
)
{
PyObject
*
signals
,
*
timeout
;
struct
timespec
buf
;
sigset_t
set
;
siginfo_t
si
;
int
err
;
if
(
!
PyArg_ParseTuple
(
args
,
"OO:sigtimedwait"
,
&
signals
,
&
timeout
))
return
NULL
;
if
(
!
PyTuple_Check
(
timeout
)
||
PyTuple_Size
(
timeout
)
!=
2
)
{
PyErr_SetString
(
PyExc_TypeError
,
"sigtimedwait() arg 2 must be a tuple "
"(timeout_sec, timeout_nsec)"
);
return
NULL
;
}
else
if
(
!
PyArg_ParseTuple
(
timeout
,
"ll:sigtimedwait"
,
&
(
buf
.
tv_sec
),
&
(
buf
.
tv_nsec
)))
return
NULL
;
if
(
buf
.
tv_sec
<
0
||
buf
.
tv_nsec
<
0
)
{
PyErr_SetString
(
PyExc_ValueError
,
"timeout must be non-negative"
);
return
NULL
;
}
if
(
iterable_to_sigset
(
signals
,
&
set
))
return
NULL
;
Py_BEGIN_ALLOW_THREADS
err
=
sigtimedwait
(
&
set
,
&
si
,
&
buf
);
Py_END_ALLOW_THREADS
if
(
err
==
-
1
)
{
if
(
errno
==
EAGAIN
)
Py_RETURN_NONE
;
else
return
PyErr_SetFromErrno
(
PyExc_OSError
);
}
return
fill_siginfo
(
&
si
);
}
PyDoc_STRVAR
(
signal_sigtimedwait_doc
,
"sigtimedwait(sigset, (timeout_sec, timeout_nsec)) -> struct_siginfo
\n
\
\n
\
Like sigwaitinfo(), but with a timeout specified as a tuple of (seconds,
\n
\
nanoseconds)."
);
#endif
/* #ifdef HAVE_SIGTIMEDWAIT */
#if defined(HAVE_PTHREAD_KILL) && defined(WITH_THREAD)
static
PyObject
*
...
...
@@ -751,6 +886,14 @@ static PyMethodDef signal_methods[] = {
#ifdef HAVE_SIGWAIT
{
"sigwait"
,
(
PyCFunction
)
signal_sigwait
,
METH_VARARGS
,
signal_sigwait_doc
},
#endif
#ifdef HAVE_SIGWAITINFO
{
"sigwaitinfo"
,
(
PyCFunction
)
signal_sigwaitinfo
,
METH_VARARGS
,
signal_sigwaitinfo_doc
},
#endif
#ifdef HAVE_SIGTIMEDWAIT
{
"sigtimedwait"
,
(
PyCFunction
)
signal_sigtimedwait
,
METH_VARARGS
,
signal_sigtimedwait_doc
},
#endif
{
NULL
,
NULL
}
/* sentinel */
};
...
...
@@ -820,6 +963,15 @@ PyInit_signal(void)
if
(
m
==
NULL
)
return
NULL
;
#if defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT)
if
(
!
initialized
)
PyStructSequence_InitType
(
&
SiginfoType
,
&
struct_siginfo_desc
);
Py_INCREF
((
PyObject
*
)
&
SiginfoType
);
PyModule_AddObject
(
m
,
"struct_siginfo"
,
(
PyObject
*
)
&
SiginfoType
);
initialized
=
1
;
#endif
/* Add some symbolic constants to the module */
d
=
PyModule_GetDict
(
m
);
...
...
configure
View file @
bc808224
...
...
@@ -9367,8 +9367,8 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
select
sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid
\
setgid sethostname
\
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf
\
sigaction sigaltstack siginterrupt sigpending
\
sig
relse sigwait
snprintf strftime strlcpy symlinkat
sync
\
sigaction sigaltstack siginterrupt sigpending
sigrelse
\
sig
timedwait sigwait sigwaitinfo
snprintf strftime strlcpy symlinkat
sync
\
sysconf tcgetpgrp tcsetpgrp tempnam timegm
times
tmpfile tmpnam tmpnam_r
\
truncate uname
unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4
\
wcscoll wcsftime wcsxfrm writev _getpty
...
...
configure.in
View file @
bc808224
...
...
@@ -2552,8 +2552,8 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
select sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
setgid sethostname \
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
sigaction sigaltstack siginterrupt sigpending \
sig
relse sigwait
snprintf strftime strlcpy symlinkat sync \
sigaction sigaltstack siginterrupt sigpending
sigrelse
\
sig
timedwait sigwait sigwaitinfo
snprintf strftime strlcpy symlinkat sync \
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \
wcscoll wcsftime wcsxfrm writev _getpty)
...
...
pyconfig.h.in
View file @
bc808224
...
...
@@ -743,9 +743,15 @@
/* Define to 1 if you have the `sigrelse' function. */
#undef HAVE_SIGRELSE
/* Define to 1 if you have the `sigtimedwait' function. */
#undef HAVE_SIGTIMEDWAIT
/* Define to 1 if you have the `sigwait' function. */
#undef HAVE_SIGWAIT
/* Define to 1 if you have the `sigwaitinfo' function. */
#undef HAVE_SIGWAITINFO
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment