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
3c7d6e06
Commit
3c7d6e06
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
fa09beb1
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 @
3c7d6e06
...
...
@@ -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
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:
...
...
Doc/whatsnew/3.5.rst
View file @
3c7d6e06
...
...
@@ -621,7 +621,7 @@ Changes in the Python API
- :func:`os.open`, :func:`open`
- :func:`os.read`, :func:`os.write`
- :func:`select.select`
- :func:`select.select`
, :func:`select.poll.poll`
- :func:`time.sleep`
* Before Python 3.5, a :class:`datetime.time` object was considered to be false
...
...
Lib/asyncore.py
View file @
3c7d6e06
...
...
@@ -179,10 +179,8 @@ def poll2(timeout=0.0, map=None):
flags
|=
select
.
POLLOUT
if
flags
:
pollster
.
register
(
fd
,
flags
)
try
:
r
=
pollster
.
poll
(
timeout
)
except
InterruptedError
:
r
=
[]
r
=
pollster
.
poll
(
timeout
)
for
fd
,
flags
in
r
:
obj
=
map
.
get
(
fd
)
if
obj
is
None
:
...
...
Lib/selectors.py
View file @
3c7d6e06
...
...
@@ -359,11 +359,10 @@ if hasattr(select, 'poll'):
# poll() has a resolution of 1 millisecond, round away from
# zero to wait *at least* timeout seconds.
timeout
=
math
.
ceil
(
timeout
*
1e3
)
fd_event_list
=
self
.
_poll
.
poll
(
timeout
)
ready
=
[]
try
:
fd_event_list
=
self
.
_poll
.
poll
(
timeout
)
except
InterruptedError
:
return
ready
for
fd
,
event
in
fd_event_list
:
events
=
0
if
event
&
~
select
.
POLLIN
:
...
...
Lib/test/eintrdata/eintr_tester.py
View file @
3c7d6e06
...
...
@@ -38,8 +38,12 @@ class EINTRBaseTest(unittest.TestCase):
cls
.
signal_period
)
@
classmethod
def
tearDownClass
(
cls
):
def
stop_alarm
(
cls
):
signal
.
setitimer
(
signal
.
ITIMER_REAL
,
0
,
0
)
@
classmethod
def
tearDownClass
(
cls
):
cls
.
stop_alarm
()
signal
.
signal
(
signal
.
SIGALRM
,
cls
.
orig_handler
)
@
classmethod
...
...
@@ -260,7 +264,7 @@ class TimeEINTRTest(EINTRBaseTest):
def
test_sleep
(
self
):
t0
=
time
.
monotonic
()
time
.
sleep
(
self
.
sleep_time
)
s
ignal
.
alarm
(
0
)
s
elf
.
stop_alarm
(
)
dt
=
time
.
monotonic
()
-
t0
self
.
assertGreaterEqual
(
dt
,
self
.
sleep_time
)
...
...
@@ -311,7 +315,17 @@ class SelectEINTRTest(EINTRBaseTest):
def
test_select
(
self
):
t0
=
time
.
monotonic
()
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
self
.
assertGreaterEqual
(
dt
,
self
.
sleep_time
)
...
...
Modules/selectmodule.c
View file @
3c7d6e06
...
...
@@ -279,6 +279,7 @@ select_select(PyObject *self, PyObject *args)
break
;
}
_PyTime_AsTimeval_noraise
(
timeout
,
&
tv
,
_PyTime_ROUND_CEILING
);
/* retry select() with the recomputed timeout */
}
}
while
(
1
);
...
...
@@ -520,30 +521,39 @@ any descriptors that have events or errors to report.");
static
PyObject
*
poll_poll
(
pollObject
*
self
,
PyObject
*
args
)
{
PyObject
*
result_list
=
NULL
,
*
t
out
=
NULL
;
int
timeout
=
0
,
poll_result
,
i
,
j
;
PyObject
*
result_list
=
NULL
,
*
t
imeout_obj
=
NULL
;
int
poll_result
,
i
,
j
;
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
;
}
/* Check values for timeout */
if
(
t
out
==
NULL
||
tout
==
Py_None
)
if
(
t
imeout_obj
==
NULL
||
timeout_obj
==
Py_None
)
{
timeout
=
-
1
;
else
if
(
!
PyNumber_Check
(
tout
))
{
PyErr_SetString
(
PyExc_TypeError
,
"timeout must be an integer or None"
);
return
NULL
;
ms
=
-
1
;
deadline
=
0
;
}
else
{
tout
=
PyNumber_Long
(
tout
);
if
(
!
tout
)
if
(
_PyTime_FromMillisecondsObject
(
&
timeout
,
timeout_obj
,
_PyTime_ROUND_CEILING
)
<
0
)
{
if
(
PyErr_ExceptionMatches
(
PyExc_TypeError
))
{
PyErr_SetString
(
PyExc_TypeError
,
"timeout must be an integer or None"
);
}
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
;
}
deadline
=
_PyTime_GetMonotonicClock
()
+
timeout
;
}
/* Avoid concurrent poll() invocation, issue 8865 */
...
...
@@ -561,14 +571,38 @@ poll_poll(pollObject *self, PyObject *args)
self
->
poll_running
=
1
;
/* call poll() */
Py_BEGIN_ALLOW_THREADS
poll_result
=
poll
(
self
->
ufds
,
self
->
ufd_len
,
timeout
);
Py_END_ALLOW_THREADS
async_err
=
0
;
do
{
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
;
if
(
poll_result
<
0
)
{
PyErr_SetFromErrno
(
PyExc_OSError
);
if
(
!
async_err
)
PyErr_SetFromErrno
(
PyExc_OSError
);
return
NULL
;
}
...
...
@@ -577,41 +611,40 @@ poll_poll(pollObject *self, PyObject *args)
result_list
=
PyList_New
(
poll_result
);
if
(
!
result_list
)
return
NULL
;
else
{
for
(
i
=
0
,
j
=
0
;
j
<
poll_result
;
j
++
)
{
/* skip to the next fired descriptor */
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
;
}
for
(
i
=
0
,
j
=
0
;
j
<
poll_result
;
j
++
)
{
/* skip to the next fired descriptor */
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
++
;
}
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