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
6f4a354a
Commit
6f4a354a
authored
Mar 30, 2015
by
Victor Stinner
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #23485: select.poll.poll() is now retried when interrupted by a signal
parent
0ddb4f78
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
112 additions
and
62 deletions
+112
-62
Doc/library/select.rst
Doc/library/select.rst
+6
-0
Doc/whatsnew/3.5.rst
Doc/whatsnew/3.5.rst
+1
-1
Lib/asyncore.py
Lib/asyncore.py
+2
-4
Lib/selectors.py
Lib/selectors.py
+3
-4
Lib/test/eintrdata/eintr_tester.py
Lib/test/eintrdata/eintr_tester.py
+17
-3
Modules/selectmodule.c
Modules/selectmodule.c
+83
-50
No files found.
Doc/library/select.rst
View file @
6f4a354a
...
@@ -408,6 +408,12 @@ linearly scanned again. :c:func:`select` is O(highest file descriptor), while
...
@@ -408,6 +408,12 @@ linearly scanned again. :c:func:`select` is O(highest file descriptor), while
returning. If *timeout* is omitted, negative, or :const:`None`, the call will
returning. If *timeout* is omitted, negative, or :const:`None`, the call will
block until there is an event for this poll object.
block until there is an event for this poll object.
.. versionchanged:: 3.5
The function is now retried with a recomputed timeout when interrupted by
a signal, except if the signal handler raises an exception (see
:pep:`475` for the rationale), instead of raising
:exc:`InterruptedError`.
.. _kqueue-objects:
.. _kqueue-objects:
...
...
Doc/whatsnew/3.5.rst
View file @
6f4a354a
...
@@ -621,7 +621,7 @@ Changes in the Python API
...
@@ -621,7 +621,7 @@ Changes in the Python API
- :func:`os.open`, :func:`open`
- :func:`os.open`, :func:`open`
- :func:`os.read`, :func:`os.write`
- :func:`os.read`, :func:`os.write`
- :func:`select.select`
- :func:`select.select`
, :func:`select.poll.poll`
- :func:`time.sleep`
- :func:`time.sleep`
* Before Python 3.5, a :class:`datetime.time` object was considered to be false
* Before Python 3.5, a :class:`datetime.time` object was considered to be false
...
...
Lib/asyncore.py
View file @
6f4a354a
...
@@ -179,10 +179,8 @@ def poll2(timeout=0.0, map=None):
...
@@ -179,10 +179,8 @@ def poll2(timeout=0.0, map=None):
flags
|=
select
.
POLLOUT
flags
|=
select
.
POLLOUT
if
flags
:
if
flags
:
pollster
.
register
(
fd
,
flags
)
pollster
.
register
(
fd
,
flags
)
try
:
r
=
pollster
.
poll
(
timeout
)
r
=
pollster
.
poll
(
timeout
)
except
InterruptedError
:
r
=
[]
for
fd
,
flags
in
r
:
for
fd
,
flags
in
r
:
obj
=
map
.
get
(
fd
)
obj
=
map
.
get
(
fd
)
if
obj
is
None
:
if
obj
is
None
:
...
...
Lib/selectors.py
View file @
6f4a354a
...
@@ -359,11 +359,10 @@ if hasattr(select, 'poll'):
...
@@ -359,11 +359,10 @@ if hasattr(select, 'poll'):
# poll() has a resolution of 1 millisecond, round away from
# poll() has a resolution of 1 millisecond, round away from
# zero to wait *at least* timeout seconds.
# zero to wait *at least* timeout seconds.
timeout
=
math
.
ceil
(
timeout
*
1e3
)
timeout
=
math
.
ceil
(
timeout
*
1e3
)
fd_event_list
=
self
.
_poll
.
poll
(
timeout
)
ready
=
[]
ready
=
[]
try
:
fd_event_list
=
self
.
_poll
.
poll
(
timeout
)
except
InterruptedError
:
return
ready
for
fd
,
event
in
fd_event_list
:
for
fd
,
event
in
fd_event_list
:
events
=
0
events
=
0
if
event
&
~
select
.
POLLIN
:
if
event
&
~
select
.
POLLIN
:
...
...
Lib/test/eintrdata/eintr_tester.py
View file @
6f4a354a
...
@@ -38,8 +38,12 @@ class EINTRBaseTest(unittest.TestCase):
...
@@ -38,8 +38,12 @@ class EINTRBaseTest(unittest.TestCase):
cls
.
signal_period
)
cls
.
signal_period
)
@
classmethod
@
classmethod
def
tearDownClass
(
cls
):
def
stop_alarm
(
cls
):
signal
.
setitimer
(
signal
.
ITIMER_REAL
,
0
,
0
)
signal
.
setitimer
(
signal
.
ITIMER_REAL
,
0
,
0
)
@
classmethod
def
tearDownClass
(
cls
):
cls
.
stop_alarm
()
signal
.
signal
(
signal
.
SIGALRM
,
cls
.
orig_handler
)
signal
.
signal
(
signal
.
SIGALRM
,
cls
.
orig_handler
)
@
classmethod
@
classmethod
...
@@ -260,7 +264,7 @@ class TimeEINTRTest(EINTRBaseTest):
...
@@ -260,7 +264,7 @@ class TimeEINTRTest(EINTRBaseTest):
def
test_sleep
(
self
):
def
test_sleep
(
self
):
t0
=
time
.
monotonic
()
t0
=
time
.
monotonic
()
time
.
sleep
(
self
.
sleep_time
)
time
.
sleep
(
self
.
sleep_time
)
s
ignal
.
alarm
(
0
)
s
elf
.
stop_alarm
(
)
dt
=
time
.
monotonic
()
-
t0
dt
=
time
.
monotonic
()
-
t0
self
.
assertGreaterEqual
(
dt
,
self
.
sleep_time
)
self
.
assertGreaterEqual
(
dt
,
self
.
sleep_time
)
...
@@ -311,7 +315,17 @@ class SelectEINTRTest(EINTRBaseTest):
...
@@ -311,7 +315,17 @@ class SelectEINTRTest(EINTRBaseTest):
def
test_select
(
self
):
def
test_select
(
self
):
t0
=
time
.
monotonic
()
t0
=
time
.
monotonic
()
select
.
select
([],
[],
[],
self
.
sleep_time
)
select
.
select
([],
[],
[],
self
.
sleep_time
)
signal
.
alarm
(
0
)
self
.
stop_alarm
()
dt
=
time
.
monotonic
()
-
t0
self
.
assertGreaterEqual
(
dt
,
self
.
sleep_time
)
@
unittest
.
skipUnless
(
hasattr
(
select
,
'poll'
),
'need select.poll'
)
def
test_poll
(
self
):
poller
=
select
.
poll
()
t0
=
time
.
monotonic
()
poller
.
poll
(
self
.
sleep_time
*
1e3
)
self
.
stop_alarm
()
dt
=
time
.
monotonic
()
-
t0
dt
=
time
.
monotonic
()
-
t0
self
.
assertGreaterEqual
(
dt
,
self
.
sleep_time
)
self
.
assertGreaterEqual
(
dt
,
self
.
sleep_time
)
...
...
Modules/selectmodule.c
View file @
6f4a354a
...
@@ -279,6 +279,7 @@ select_select(PyObject *self, PyObject *args)
...
@@ -279,6 +279,7 @@ select_select(PyObject *self, PyObject *args)
break
;
break
;
}
}
_PyTime_AsTimeval_noraise
(
timeout
,
&
tv
,
_PyTime_ROUND_CEILING
);
_PyTime_AsTimeval_noraise
(
timeout
,
&
tv
,
_PyTime_ROUND_CEILING
);
/* retry select() with the recomputed timeout */
}
}
}
while
(
1
);
}
while
(
1
);
...
@@ -520,30 +521,39 @@ any descriptors that have events or errors to report.");
...
@@ -520,30 +521,39 @@ any descriptors that have events or errors to report.");
static
PyObject
*
static
PyObject
*
poll_poll
(
pollObject
*
self
,
PyObject
*
args
)
poll_poll
(
pollObject
*
self
,
PyObject
*
args
)
{
{
PyObject
*
result_list
=
NULL
,
*
t
out
=
NULL
;
PyObject
*
result_list
=
NULL
,
*
t
imeout_obj
=
NULL
;
int
timeout
=
0
,
poll_result
,
i
,
j
;
int
poll_result
,
i
,
j
;
PyObject
*
value
=
NULL
,
*
num
=
NULL
;
PyObject
*
value
=
NULL
,
*
num
=
NULL
;
_PyTime_t
timeout
,
ms
,
deadline
;
int
async_err
=
0
;
if
(
!
PyArg_
UnpackTuple
(
args
,
"poll"
,
0
,
1
,
&
tout
))
{
if
(
!
PyArg_
ParseTuple
(
args
,
"|O:poll"
,
&
timeout_obj
))
{
return
NULL
;
return
NULL
;
}
}
/* Check values for timeout */
/* Check values for timeout */
if
(
t
out
==
NULL
||
tout
==
Py_None
)
if
(
t
imeout_obj
==
NULL
||
timeout_obj
==
Py_None
)
{
timeout
=
-
1
;
timeout
=
-
1
;
else
if
(
!
PyNumber_Check
(
tout
))
{
ms
=
-
1
;
PyErr_SetString
(
PyExc_TypeError
,
deadline
=
0
;
"timeout must be an integer or None"
);
return
NULL
;
}
}
else
{
else
{
tout
=
PyNumber_Long
(
tout
);
if
(
_PyTime_FromMillisecondsObject
(
&
timeout
,
timeout_obj
,
if
(
!
tout
)
_PyTime_ROUND_CEILING
)
<
0
)
{
if
(
PyErr_ExceptionMatches
(
PyExc_TypeError
))
{
PyErr_SetString
(
PyExc_TypeError
,
"timeout must be an integer or None"
);
}
return
NULL
;
return
NULL
;
timeout
=
_PyLong_AsInt
(
tout
);
}
Py_DECREF
(
tout
);
if
(
timeout
==
-
1
&&
PyErr_Occurred
())
ms
=
_PyTime_AsMilliseconds
(
timeout
,
_PyTime_ROUND_CEILING
);
if
(
ms
<
INT_MIN
||
ms
>
INT_MAX
)
{
PyErr_SetString
(
PyExc_OverflowError
,
"timeout is too large"
);
return
NULL
;
return
NULL
;
}
deadline
=
_PyTime_GetMonotonicClock
()
+
timeout
;
}
}
/* Avoid concurrent poll() invocation, issue 8865 */
/* Avoid concurrent poll() invocation, issue 8865 */
...
@@ -561,14 +571,38 @@ poll_poll(pollObject *self, PyObject *args)
...
@@ -561,14 +571,38 @@ poll_poll(pollObject *self, PyObject *args)
self
->
poll_running
=
1
;
self
->
poll_running
=
1
;
/* call poll() */
/* call poll() */
Py_BEGIN_ALLOW_THREADS
async_err
=
0
;
poll_result
=
poll
(
self
->
ufds
,
self
->
ufd_len
,
timeout
);
do
{
Py_END_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS
errno
=
0
;
poll_result
=
poll
(
self
->
ufds
,
self
->
ufd_len
,
(
int
)
ms
);
Py_END_ALLOW_THREADS
if
(
errno
!=
EINTR
)
break
;
/* poll() was interrupted by a signal */
if
(
PyErr_CheckSignals
())
{
async_err
=
1
;
break
;
}
if
(
timeout
>=
0
)
{
timeout
=
deadline
-
_PyTime_GetMonotonicClock
();
if
(
timeout
<
0
)
{
poll_result
=
0
;
break
;
}
ms
=
_PyTime_AsMilliseconds
(
timeout
,
_PyTime_ROUND_CEILING
);
/* retry poll() with the recomputed timeout */
}
}
while
(
1
);
self
->
poll_running
=
0
;
self
->
poll_running
=
0
;
if
(
poll_result
<
0
)
{
if
(
poll_result
<
0
)
{
PyErr_SetFromErrno
(
PyExc_OSError
);
if
(
!
async_err
)
PyErr_SetFromErrno
(
PyExc_OSError
);
return
NULL
;
return
NULL
;
}
}
...
@@ -577,41 +611,40 @@ poll_poll(pollObject *self, PyObject *args)
...
@@ -577,41 +611,40 @@ poll_poll(pollObject *self, PyObject *args)
result_list
=
PyList_New
(
poll_result
);
result_list
=
PyList_New
(
poll_result
);
if
(
!
result_list
)
if
(
!
result_list
)
return
NULL
;
return
NULL
;
else
{
for
(
i
=
0
,
j
=
0
;
j
<
poll_result
;
j
++
)
{
for
(
i
=
0
,
j
=
0
;
j
<
poll_result
;
j
++
)
{
/* skip to the next fired descriptor */
/* skip to the next fired descriptor */
while
(
!
self
->
ufds
[
i
].
revents
)
{
while
(
!
self
->
ufds
[
i
].
revents
)
{
i
++
;
}
/* if we hit a NULL return, set value to NULL
and break out of loop; code at end will
clean up result_list */
value
=
PyTuple_New
(
2
);
if
(
value
==
NULL
)
goto
error
;
num
=
PyLong_FromLong
(
self
->
ufds
[
i
].
fd
);
if
(
num
==
NULL
)
{
Py_DECREF
(
value
);
goto
error
;
}
PyTuple_SET_ITEM
(
value
,
0
,
num
);
/* The &0xffff is a workaround for AIX. 'revents'
is a 16-bit short, and IBM assigned POLLNVAL
to be 0x8000, so the conversion to int results
in a negative number. See SF bug #923315. */
num
=
PyLong_FromLong
(
self
->
ufds
[
i
].
revents
&
0xffff
);
if
(
num
==
NULL
)
{
Py_DECREF
(
value
);
goto
error
;
}
PyTuple_SET_ITEM
(
value
,
1
,
num
);
if
((
PyList_SetItem
(
result_list
,
j
,
value
))
==
-
1
)
{
Py_DECREF
(
value
);
goto
error
;
}
i
++
;
i
++
;
}
}
/* if we hit a NULL return, set value to NULL
and break out of loop; code at end will
clean up result_list */
value
=
PyTuple_New
(
2
);
if
(
value
==
NULL
)
goto
error
;
num
=
PyLong_FromLong
(
self
->
ufds
[
i
].
fd
);
if
(
num
==
NULL
)
{
Py_DECREF
(
value
);
goto
error
;
}
PyTuple_SET_ITEM
(
value
,
0
,
num
);
/* The &0xffff is a workaround for AIX. 'revents'
is a 16-bit short, and IBM assigned POLLNVAL
to be 0x8000, so the conversion to int results
in a negative number. See SF bug #923315. */
num
=
PyLong_FromLong
(
self
->
ufds
[
i
].
revents
&
0xffff
);
if
(
num
==
NULL
)
{
Py_DECREF
(
value
);
goto
error
;
}
PyTuple_SET_ITEM
(
value
,
1
,
num
);
if
((
PyList_SetItem
(
result_list
,
j
,
value
))
==
-
1
)
{
Py_DECREF
(
value
);
goto
error
;
}
i
++
;
}
}
return
result_list
;
return
result_list
;
...
...
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