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
f584b63f
Commit
f584b63f
authored
Feb 07, 2015
by
Charles-François Natali
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #23285: PEP 475 -- Retry system calls failing with EINTR.
parent
2635d916
Changes
18
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
753 additions
and
522 deletions
+753
-522
Doc/whatsnew/3.5.rst
Doc/whatsnew/3.5.rst
+10
-0
Lib/_pyio.py
Lib/_pyio.py
+3
-16
Lib/distutils/spawn.py
Lib/distutils/spawn.py
+0
-3
Lib/multiprocessing/connection.py
Lib/multiprocessing/connection.py
+3
-15
Lib/multiprocessing/forkserver.py
Lib/multiprocessing/forkserver.py
+2
-16
Lib/multiprocessing/popen_fork.py
Lib/multiprocessing/popen_fork.py
+0
-3
Lib/socket.py
Lib/socket.py
+0
-2
Lib/socketserver.py
Lib/socketserver.py
+0
-2
Lib/subprocess.py
Lib/subprocess.py
+5
-13
Lib/test/eintrdata/eintr_tester.py
Lib/test/eintrdata/eintr_tester.py
+260
-0
Lib/test/test_eintr.py
Lib/test/test_eintr.py
+20
-0
Lib/test/test_signal.py
Lib/test/test_signal.py
+3
-4
Lib/test/test_socket.py
Lib/test/test_socket.py
+4
-120
Lib/test/test_subprocess.py
Lib/test/test_subprocess.py
+0
-20
Misc/NEWS
Misc/NEWS
+2
-0
Modules/_io/fileio.c
Modules/_io/fileio.c
+70
-55
Modules/posixmodule.c
Modules/posixmodule.c
+244
-141
Modules/socketmodule.c
Modules/socketmodule.c
+127
-112
No files found.
Doc/whatsnew/3.5.rst
View file @
f584b63f
...
...
@@ -111,6 +111,16 @@ Please read on for a comprehensive list of user-facing changes.
PEP written by Carl Meyer
PEP 475: Retry system calls failing with EINTR
----------------------------------------------
:pep:`475` adds support for automatic retry of system calls failing with EINTR:
this means that user code doesn't have to deal with EINTR or InterruptedError
manually, and should make it more robust against asynchronous signal reception.
.. seealso::
:pep:`475` -- Retry system calls failing with EINTR
Other Language Changes
...
...
Lib/_pyio.py
View file @
f584b63f
...
...
@@ -1012,10 +1012,7 @@ class BufferedReader(_BufferedIOMixin):
current_size
=
0
while
True
:
# Read until EOF or until read() would block.
try
:
chunk
=
self
.
raw
.
read
()
except
InterruptedError
:
continue
if
chunk
in
empty_values
:
nodata_val
=
chunk
break
...
...
@@ -1034,10 +1031,7 @@ class BufferedReader(_BufferedIOMixin):
chunks
=
[
buf
[
pos
:]]
wanted
=
max
(
self
.
buffer_size
,
n
)
while
avail
<
n
:
try
:
chunk
=
self
.
raw
.
read
(
wanted
)
except
InterruptedError
:
continue
if
chunk
in
empty_values
:
nodata_val
=
chunk
break
...
...
@@ -1066,12 +1060,7 @@ class BufferedReader(_BufferedIOMixin):
have
=
len
(
self
.
_read_buf
)
-
self
.
_read_pos
if
have
<
want
or
have
<=
0
:
to_read
=
self
.
buffer_size
-
have
while
True
:
try
:
current
=
self
.
raw
.
read
(
to_read
)
except
InterruptedError
:
continue
break
if
current
:
self
.
_read_buf
=
self
.
_read_buf
[
self
.
_read_pos
:]
+
current
self
.
_read_pos
=
0
...
...
@@ -1220,8 +1209,6 @@ class BufferedWriter(_BufferedIOMixin):
while
self
.
_write_buf
:
try
:
n
=
self
.
raw
.
write
(
self
.
_write_buf
)
except
InterruptedError
:
continue
except
BlockingIOError
:
raise
RuntimeError
(
"self.raw should implement RawIOBase: it "
"should not raise BlockingIOError"
)
...
...
Lib/distutils/spawn.py
View file @
f584b63f
...
...
@@ -137,9 +137,6 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0):
try
:
pid
,
status
=
os
.
waitpid
(
pid
,
0
)
except
OSError
as
exc
:
import
errno
if
exc
.
errno
==
errno
.
EINTR
:
continue
if
not
DEBUG
:
cmd
=
executable
raise
DistutilsExecError
(
...
...
Lib/multiprocessing/connection.py
View file @
f584b63f
...
...
@@ -365,10 +365,7 @@ class Connection(_ConnectionBase):
def
_send
(
self
,
buf
,
write
=
_write
):
remaining
=
len
(
buf
)
while
True
:
try
:
n
=
write
(
self
.
_handle
,
buf
)
except
InterruptedError
:
continue
remaining
-=
n
if
remaining
==
0
:
break
...
...
@@ -379,10 +376,7 @@ class Connection(_ConnectionBase):
handle
=
self
.
_handle
remaining
=
size
while
remaining
>
0
:
try
:
chunk
=
read
(
handle
,
remaining
)
except
InterruptedError
:
continue
n
=
len
(
chunk
)
if
n
==
0
:
if
remaining
==
size
:
...
...
@@ -595,13 +589,7 @@ class SocketListener(object):
self
.
_unlink
=
None
def
accept
(
self
):
while
True
:
try
:
s
,
self
.
_last_accepted
=
self
.
_socket
.
accept
()
except
InterruptedError
:
pass
else
:
break
s
.
setblocking
(
True
)
return
Connection
(
s
.
detach
())
...
...
Lib/multiprocessing/forkserver.py
View file @
f584b63f
...
...
@@ -188,8 +188,6 @@ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None):
finally
:
os
.
_exit
(
code
)
except
InterruptedError
:
pass
except
OSError
as
e
:
if
e
.
errno
!=
errno
.
ECONNABORTED
:
raise
...
...
@@ -230,13 +228,7 @@ def read_unsigned(fd):
data
=
b''
length
=
UNSIGNED_STRUCT
.
size
while
len
(
data
)
<
length
:
while
True
:
try
:
s
=
os
.
read
(
fd
,
length
-
len
(
data
))
except
InterruptedError
:
pass
else
:
break
if
not
s
:
raise
EOFError
(
'unexpected EOF'
)
data
+=
s
...
...
@@ -245,13 +237,7 @@ def read_unsigned(fd):
def
write_unsigned
(
fd
,
n
):
msg
=
UNSIGNED_STRUCT
.
pack
(
n
)
while
msg
:
while
True
:
try
:
nbytes
=
os
.
write
(
fd
,
msg
)
except
InterruptedError
:
pass
else
:
break
if
nbytes
==
0
:
raise
RuntimeError
(
'should not get here'
)
msg
=
msg
[
nbytes
:]
...
...
Lib/multiprocessing/popen_fork.py
View file @
f584b63f
import
os
import
sys
import
signal
import
errno
from
.
import
util
...
...
@@ -29,8 +28,6 @@ class Popen(object):
try
:
pid
,
sts
=
os
.
waitpid
(
self
.
pid
,
flag
)
except
OSError
as
e
:
if
e
.
errno
==
errno
.
EINTR
:
continue
# Child process not yet created. See #1731717
# e.errno == errno.ECHILD == 10
return
None
...
...
Lib/socket.py
View file @
f584b63f
...
...
@@ -572,8 +572,6 @@ class SocketIO(io.RawIOBase):
except
timeout
:
self
.
_timeout_occurred
=
True
raise
except
InterruptedError
:
continue
except
error
as
e
:
if
e
.
args
[
0
]
in
_blocking_errnos
:
return
None
...
...
Lib/socketserver.py
View file @
f584b63f
...
...
@@ -553,8 +553,6 @@ class ForkingMixIn:
try
:
pid
,
_
=
os
.
waitpid
(
-
1
,
0
)
self
.
active_children
.
discard
(
pid
)
except
InterruptedError
:
pass
except
ChildProcessError
:
# we don't have any children, we're done
self
.
active_children
.
clear
()
...
...
Lib/subprocess.py
View file @
f584b63f
...
...
@@ -489,14 +489,6 @@ STDOUT = -2
DEVNULL
=
-
3
def
_eintr_retry_call
(
func
,
*
args
):
while
True
:
try
:
return
func
(
*
args
)
except
InterruptedError
:
continue
# XXX This function is only used by multiprocessing and the test suite,
# but it's here so that it can be imported when Python is compiled without
# threads.
...
...
@@ -963,10 +955,10 @@ class Popen(object):
if
self
.
stdin
:
self
.
_stdin_write
(
input
)
elif
self
.
stdout
:
stdout
=
_eintr_retry_call
(
self
.
stdout
.
read
)
stdout
=
self
.
stdout
.
read
(
)
self
.
stdout
.
close
()
elif
self
.
stderr
:
stderr
=
_eintr_retry_call
(
self
.
stderr
.
read
)
stderr
=
self
.
stderr
.
read
(
)
self
.
stderr
.
close
()
self
.
wait
()
else
:
...
...
@@ -1410,7 +1402,7 @@ class Popen(object):
# exception (limited in size)
errpipe_data
=
bytearray
()
while
True
:
part
=
_eintr_retry_call
(
os
.
read
,
errpipe_read
,
50000
)
part
=
os
.
read
(
errpipe_read
,
50000
)
errpipe_data
+=
part
if
not
part
or
len
(
errpipe_data
)
>
50000
:
break
...
...
@@ -1420,7 +1412,7 @@ class Popen(object):
if
errpipe_data
:
try
:
_eintr_retry_call
(
os
.
waitpid
,
self
.
pid
,
0
)
os
.
waitpid
(
self
.
pid
,
0
)
except
ChildProcessError
:
pass
try
:
...
...
@@ -1505,7 +1497,7 @@ class Popen(object):
def
_try_wait
(
self
,
wait_flags
):
"""All callers to this function MUST hold self._waitpid_lock."""
try
:
(
pid
,
sts
)
=
_eintr_retry_call
(
os
.
waitpid
,
self
.
pid
,
wait_flags
)
(
pid
,
sts
)
=
os
.
waitpid
(
self
.
pid
,
wait_flags
)
except
ChildProcessError
:
# This happens if SIGCLD is set to be ignored or waiting
# for child processes has otherwise been disabled for our
...
...
Lib/test/eintrdata/eintr_tester.py
0 → 100644
View file @
f584b63f
"""
This test suite exercises some system calls subject to interruption with EINTR,
to check that it is actually handled transparently.
It is intended to be run by the main test suite within a child process, to
ensure there is no background thread running (so that signals are delivered to
the correct thread).
Signals are generated in-process using setitimer(ITIMER_REAL), which allows
sub-second periodicity (contrarily to signal()).
"""
import
io
import
os
import
signal
import
socket
import
time
import
unittest
from
test
import
support
@
unittest
.
skipUnless
(
hasattr
(
signal
,
"setitimer"
),
"requires setitimer()"
)
class
EINTRBaseTest
(
unittest
.
TestCase
):
""" Base class for EINTR tests. """
# delay for initial signal delivery
signal_delay
=
0.1
# signal delivery periodicity
signal_period
=
0.1
# default sleep time for tests - should obviously have:
# sleep_time > signal_period
sleep_time
=
0.2
@
classmethod
def
setUpClass
(
cls
):
cls
.
orig_handler
=
signal
.
signal
(
signal
.
SIGALRM
,
lambda
*
args
:
None
)
signal
.
setitimer
(
signal
.
ITIMER_REAL
,
cls
.
signal_delay
,
cls
.
signal_period
)
@
classmethod
def
tearDownClass
(
cls
):
signal
.
setitimer
(
signal
.
ITIMER_REAL
,
0
,
0
)
signal
.
signal
(
signal
.
SIGALRM
,
cls
.
orig_handler
)
@
classmethod
def
_sleep
(
cls
):
# default sleep time
time
.
sleep
(
cls
.
sleep_time
)
@
unittest
.
skipUnless
(
hasattr
(
signal
,
"setitimer"
),
"requires setitimer()"
)
class
OSEINTRTest
(
EINTRBaseTest
):
""" EINTR tests for the os module. """
def
_test_wait_multiple
(
self
,
wait_func
):
num
=
3
for
_
in
range
(
num
):
pid
=
os
.
fork
()
if
pid
==
0
:
self
.
_sleep
()
os
.
_exit
(
0
)
for
_
in
range
(
num
):
wait_func
()
def
test_wait
(
self
):
self
.
_test_wait_multiple
(
os
.
wait
)
@
unittest
.
skipUnless
(
hasattr
(
os
,
'wait3'
),
'requires wait3()'
)
def
test_wait3
(
self
):
self
.
_test_wait_multiple
(
lambda
:
os
.
wait3
(
0
))
def
_test_wait_single
(
self
,
wait_func
):
pid
=
os
.
fork
()
if
pid
==
0
:
self
.
_sleep
()
os
.
_exit
(
0
)
else
:
wait_func
(
pid
)
def
test_waitpid
(
self
):
self
.
_test_wait_single
(
lambda
pid
:
os
.
waitpid
(
pid
,
0
))
@
unittest
.
skipUnless
(
hasattr
(
os
,
'wait4'
),
'requires wait4()'
)
def
test_wait4
(
self
):
self
.
_test_wait_single
(
lambda
pid
:
os
.
wait4
(
pid
,
0
))
def
test_read
(
self
):
rd
,
wr
=
os
.
pipe
()
self
.
addCleanup
(
os
.
close
,
rd
)
# wr closed explicitly by parent
# the payload below are smaller than PIPE_BUF, hence the writes will be
# atomic
datas
=
[
b"hello"
,
b"world"
,
b"spam"
]
pid
=
os
.
fork
()
if
pid
==
0
:
os
.
close
(
rd
)
for
data
in
datas
:
# let the parent block on read()
self
.
_sleep
()
os
.
write
(
wr
,
data
)
os
.
_exit
(
0
)
else
:
self
.
addCleanup
(
os
.
waitpid
,
pid
,
0
)
os
.
close
(
wr
)
for
data
in
datas
:
self
.
assertEqual
(
data
,
os
.
read
(
rd
,
len
(
data
)))
def
test_write
(
self
):
rd
,
wr
=
os
.
pipe
()
self
.
addCleanup
(
os
.
close
,
wr
)
# rd closed explicitly by parent
# we must write enough data for the write() to block
data
=
b"xyz"
*
support
.
PIPE_MAX_SIZE
pid
=
os
.
fork
()
if
pid
==
0
:
os
.
close
(
wr
)
read_data
=
io
.
BytesIO
()
# let the parent block on write()
self
.
_sleep
()
while
len
(
read_data
.
getvalue
())
<
len
(
data
):
chunk
=
os
.
read
(
rd
,
2
*
len
(
data
))
read_data
.
write
(
chunk
)
self
.
assertEqual
(
read_data
.
getvalue
(),
data
)
os
.
_exit
(
0
)
else
:
os
.
close
(
rd
)
written
=
0
while
written
<
len
(
data
):
written
+=
os
.
write
(
wr
,
memoryview
(
data
)[
written
:])
self
.
assertEqual
(
0
,
os
.
waitpid
(
pid
,
0
)[
1
])
@
unittest
.
skipUnless
(
hasattr
(
signal
,
"setitimer"
),
"requires setitimer()"
)
class
SocketEINTRTest
(
EINTRBaseTest
):
""" EINTR tests for the socket module. """
@
unittest
.
skipUnless
(
hasattr
(
socket
,
'socketpair'
),
'needs socketpair()'
)
def
_test_recv
(
self
,
recv_func
):
rd
,
wr
=
socket
.
socketpair
()
self
.
addCleanup
(
rd
.
close
)
# wr closed explicitly by parent
# single-byte payload guard us against partial recv
datas
=
[
b"x"
,
b"y"
,
b"z"
]
pid
=
os
.
fork
()
if
pid
==
0
:
rd
.
close
()
for
data
in
datas
:
# let the parent block on recv()
self
.
_sleep
()
wr
.
sendall
(
data
)
os
.
_exit
(
0
)
else
:
self
.
addCleanup
(
os
.
waitpid
,
pid
,
0
)
wr
.
close
()
for
data
in
datas
:
self
.
assertEqual
(
data
,
recv_func
(
rd
,
len
(
data
)))
def
test_recv
(
self
):
self
.
_test_recv
(
socket
.
socket
.
recv
)
@
unittest
.
skipUnless
(
hasattr
(
socket
.
socket
,
'recvmsg'
),
'needs recvmsg()'
)
def
test_recvmsg
(
self
):
self
.
_test_recv
(
lambda
sock
,
data
:
sock
.
recvmsg
(
data
)[
0
])
def
_test_send
(
self
,
send_func
):
rd
,
wr
=
socket
.
socketpair
()
self
.
addCleanup
(
wr
.
close
)
# rd closed explicitly by parent
# we must send enough data for the send() to block
data
=
b"xyz"
*
(
support
.
SOCK_MAX_SIZE
//
3
)
pid
=
os
.
fork
()
if
pid
==
0
:
wr
.
close
()
# let the parent block on send()
self
.
_sleep
()
received_data
=
bytearray
(
len
(
data
))
n
=
0
while
n
<
len
(
data
):
n
+=
rd
.
recv_into
(
memoryview
(
received_data
)[
n
:])
self
.
assertEqual
(
received_data
,
data
)
os
.
_exit
(
0
)
else
:
rd
.
close
()
written
=
0
while
written
<
len
(
data
):
sent
=
send_func
(
wr
,
memoryview
(
data
)[
written
:])
# sendall() returns None
written
+=
len
(
data
)
if
sent
is
None
else
sent
self
.
assertEqual
(
0
,
os
.
waitpid
(
pid
,
0
)[
1
])
def
test_send
(
self
):
self
.
_test_send
(
socket
.
socket
.
send
)
def
test_sendall
(
self
):
self
.
_test_send
(
socket
.
socket
.
sendall
)
@
unittest
.
skipUnless
(
hasattr
(
socket
.
socket
,
'sendmsg'
),
'needs sendmsg()'
)
def
test_sendmsg
(
self
):
self
.
_test_send
(
lambda
sock
,
data
:
sock
.
sendmsg
([
data
]))
def
test_accept
(
self
):
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
self
.
addCleanup
(
sock
.
close
)
sock
.
bind
((
support
.
HOST
,
0
))
_
,
port
=
sock
.
getsockname
()
sock
.
listen
()
pid
=
os
.
fork
()
if
pid
==
0
:
# let parent block on accept()
self
.
_sleep
()
with
socket
.
create_connection
((
support
.
HOST
,
port
)):
self
.
_sleep
()
os
.
_exit
(
0
)
else
:
self
.
addCleanup
(
os
.
waitpid
,
pid
,
0
)
client_sock
,
_
=
sock
.
accept
()
client_sock
.
close
()
@
unittest
.
skipUnless
(
hasattr
(
os
,
'mkfifo'
),
'needs mkfifo()'
)
def
_test_open
(
self
,
do_open_close_reader
,
do_open_close_writer
):
# Use a fifo: until the child opens it for reading, the parent will
# block when trying to open it for writing.
support
.
unlink
(
support
.
TESTFN
)
os
.
mkfifo
(
support
.
TESTFN
)
self
.
addCleanup
(
support
.
unlink
,
support
.
TESTFN
)
pid
=
os
.
fork
()
if
pid
==
0
:
# let the parent block
self
.
_sleep
()
do_open_close_reader
(
support
.
TESTFN
)
os
.
_exit
(
0
)
else
:
self
.
addCleanup
(
os
.
waitpid
,
pid
,
0
)
do_open_close_writer
(
support
.
TESTFN
)
def
test_open
(
self
):
self
.
_test_open
(
lambda
path
:
open
(
path
,
'r'
).
close
(),
lambda
path
:
open
(
path
,
'w'
).
close
())
def
test_os_open
(
self
):
self
.
_test_open
(
lambda
path
:
os
.
close
(
os
.
open
(
path
,
os
.
O_RDONLY
)),
lambda
path
:
os
.
close
(
os
.
open
(
path
,
os
.
O_WRONLY
)))
def
test_main
():
support
.
run_unittest
(
OSEINTRTest
,
SocketEINTRTest
)
if
__name__
==
"__main__"
:
test_main
()
Lib/test/test_eintr.py
0 → 100644
View file @
f584b63f
import
os
import
signal
import
unittest
from
test
import
script_helper
,
support
@
unittest
.
skipUnless
(
os
.
name
==
"posix"
,
"only supported on Unix"
)
class
EINTRTests
(
unittest
.
TestCase
):
@
unittest
.
skipUnless
(
hasattr
(
signal
,
"setitimer"
),
"requires setitimer()"
)
def
test_all
(
self
):
# Run the tester in a sub-process, to make sure there is only one
# thread (for reliable signal delivery).
tester
=
support
.
findfile
(
"eintr_tester.py"
,
subdir
=
"eintrdata"
)
script_helper
.
assert_python_ok
(
tester
)
if
__name__
==
"__main__"
:
unittest
.
main
()
Lib/test/test_signal.py
View file @
f584b63f
...
...
@@ -587,7 +587,7 @@ class SiginterruptTest(unittest.TestCase):
r, w = os.pipe()
def handler(signum, frame):
pass
1 / 0
signal.signal(signal.SIGALRM, handler)
if interrupt is not None:
...
...
@@ -604,9 +604,8 @@ class SiginterruptTest(unittest.TestCase):
try:
# blocking call: read from a pipe without data
os.read(r, 1)
except OSError as err:
if err.errno != errno.EINTR:
raise
except ZeroDivisionError:
pass
else:
sys.exit(2)
sys.exit(3)
...
...
Lib/test/test_socket.py
View file @
f584b63f
...
...
@@ -3590,7 +3590,7 @@ class InterruptedTimeoutBase(unittest.TestCase):
def
setUp
(
self
):
super
().
setUp
()
orig_alrm_handler
=
signal
.
signal
(
signal
.
SIGALRM
,
lambda
signum
,
frame
:
None
)
lambda
signum
,
frame
:
1
/
0
)
self
.
addCleanup
(
signal
.
signal
,
signal
.
SIGALRM
,
orig_alrm_handler
)
self
.
addCleanup
(
self
.
setAlarm
,
0
)
...
...
@@ -3627,13 +3627,11 @@ class InterruptedRecvTimeoutTest(InterruptedTimeoutBase, UDPTestBase):
self
.
serv
.
settimeout
(
self
.
timeout
)
def
checkInterruptedRecv
(
self
,
func
,
*
args
,
**
kwargs
):
# Check that func(*args, **kwargs) raises
OSError with an
# Check that func(*args, **kwargs) raises
# errno of EINTR when interrupted by a signal.
self
.
setAlarm
(
self
.
alarm_time
)
with
self
.
assertRaises
(
OS
Error
)
as
cm
:
with
self
.
assertRaises
(
ZeroDivision
Error
)
as
cm
:
func
(
*
args
,
**
kwargs
)
self
.
assertNotIsInstance
(
cm
.
exception
,
socket
.
timeout
)
self
.
assertEqual
(
cm
.
exception
.
errno
,
errno
.
EINTR
)
def
testInterruptedRecvTimeout
(
self
):
self
.
checkInterruptedRecv
(
self
.
serv
.
recv
,
1024
)
...
...
@@ -3689,12 +3687,10 @@ class InterruptedSendTimeoutTest(InterruptedTimeoutBase,
# Check that func(*args, **kwargs), run in a loop, raises
# OSError with an errno of EINTR when interrupted by a
# signal.
with
self
.
assertRaises
(
OS
Error
)
as
cm
:
with
self
.
assertRaises
(
ZeroDivision
Error
)
as
cm
:
while
True
:
self
.
setAlarm
(
self
.
alarm_time
)
func
(
*
args
,
**
kwargs
)
self
.
assertNotIsInstance
(
cm
.
exception
,
socket
.
timeout
)
self
.
assertEqual
(
cm
.
exception
.
errno
,
errno
.
EINTR
)
# Issue #12958: The following tests have problems on OS X prior to 10.7
@
support
.
requires_mac_ver
(
10
,
7
)
...
...
@@ -4062,117 +4058,6 @@ class FileObjectClassTestCase(SocketConnectedTest):
pass
class
FileObjectInterruptedTestCase
(
unittest
.
TestCase
):
"""Test that the file object correctly handles EINTR internally."""
class
MockSocket
(
object
):
def
__init__
(
self
,
recv_funcs
=
()):
# A generator that returns callables that we'll call for each
# call to recv().
self
.
_recv_step
=
iter
(
recv_funcs
)
def
recv_into
(
self
,
buffer
):
data
=
next
(
self
.
_recv_step
)()
assert
len
(
buffer
)
>=
len
(
data
)
buffer
[:
len
(
data
)]
=
data
return
len
(
data
)
def
_decref_socketios
(
self
):
pass
def
_textiowrap_for_test
(
self
,
buffering
=-
1
):
raw
=
socket
.
SocketIO
(
self
,
"r"
)
if
buffering
<
0
:
buffering
=
io
.
DEFAULT_BUFFER_SIZE
if
buffering
==
0
:
return
raw
buffer
=
io
.
BufferedReader
(
raw
,
buffering
)
text
=
io
.
TextIOWrapper
(
buffer
,
None
,
None
)
text
.
mode
=
"rb"
return
text
@
staticmethod
def
_raise_eintr
():
raise
OSError
(
errno
.
EINTR
,
"interrupted"
)
def
_textiowrap_mock_socket
(
self
,
mock
,
buffering
=-
1
):
raw
=
socket
.
SocketIO
(
mock
,
"r"
)
if
buffering
<
0
:
buffering
=
io
.
DEFAULT_BUFFER_SIZE
if
buffering
==
0
:
return
raw
buffer
=
io
.
BufferedReader
(
raw
,
buffering
)
text
=
io
.
TextIOWrapper
(
buffer
,
None
,
None
)
text
.
mode
=
"rb"
return
text
def
_test_readline
(
self
,
size
=-
1
,
buffering
=-
1
):
mock_sock
=
self
.
MockSocket
(
recv_funcs
=
[
lambda
:
b"This is the first line
\
n
And the sec"
,
self
.
_raise_eintr
,
lambda
:
b"ond line is here
\
n
"
,
lambda
:
b""
,
lambda
:
b""
,
# XXX(gps): io library does an extra EOF read
])
fo
=
mock_sock
.
_textiowrap_for_test
(
buffering
=
buffering
)
self
.
assertEqual
(
fo
.
readline
(
size
),
"This is the first line
\
n
"
)
self
.
assertEqual
(
fo
.
readline
(
size
),
"And the second line is here
\
n
"
)
def
_test_read
(
self
,
size
=-
1
,
buffering
=-
1
):
mock_sock
=
self
.
MockSocket
(
recv_funcs
=
[
lambda
:
b"This is the first line
\
n
And the sec"
,
self
.
_raise_eintr
,
lambda
:
b"ond line is here
\
n
"
,
lambda
:
b""
,
lambda
:
b""
,
# XXX(gps): io library does an extra EOF read
])
expecting
=
(
b"This is the first line
\
n
"
b"And the second line is here
\
n
"
)
fo
=
mock_sock
.
_textiowrap_for_test
(
buffering
=
buffering
)
if
buffering
==
0
:
data
=
b''
else
:
data
=
''
expecting
=
expecting
.
decode
(
'utf-8'
)
while
len
(
data
)
!=
len
(
expecting
):
part
=
fo
.
read
(
size
)
if
not
part
:
break
data
+=
part
self
.
assertEqual
(
data
,
expecting
)
def
test_default
(
self
):
self
.
_test_readline
()
self
.
_test_readline
(
size
=
100
)
self
.
_test_read
()
self
.
_test_read
(
size
=
100
)
def
test_with_1k_buffer
(
self
):
self
.
_test_readline
(
buffering
=
1024
)
self
.
_test_readline
(
size
=
100
,
buffering
=
1024
)
self
.
_test_read
(
buffering
=
1024
)
self
.
_test_read
(
size
=
100
,
buffering
=
1024
)
def
_test_readline_no_buffer
(
self
,
size
=-
1
):
mock_sock
=
self
.
MockSocket
(
recv_funcs
=
[
lambda
:
b"a"
,
lambda
:
b"
\
n
"
,
lambda
:
b"B"
,
self
.
_raise_eintr
,
lambda
:
b"b"
,
lambda
:
b""
,
])
fo
=
mock_sock
.
_textiowrap_for_test
(
buffering
=
0
)
self
.
assertEqual
(
fo
.
readline
(
size
),
b"a
\
n
"
)
self
.
assertEqual
(
fo
.
readline
(
size
),
b"Bb"
)
def
test_no_buffer
(
self
):
self
.
_test_readline_no_buffer
()
self
.
_test_readline_no_buffer
(
size
=
4
)
self
.
_test_read
(
buffering
=
0
)
self
.
_test_read
(
size
=
100
,
buffering
=
0
)
class
UnbufferedFileObjectClassTestCase
(
FileObjectClassTestCase
):
"""Repeat the tests from FileObjectClassTestCase with bufsize==0.
...
...
@@ -5388,7 +5273,6 @@ def test_main():
tests
.
extend
([
NonBlockingTCPTests
,
FileObjectClassTestCase
,
FileObjectInterruptedTestCase
,
UnbufferedFileObjectClassTestCase
,
LineBufferedFileObjectClassTestCase
,
SmallBufferedFileObjectClassTestCase
,
...
...
Lib/test/test_subprocess.py
View file @
f584b63f
...
...
@@ -2421,25 +2421,6 @@ class ProcessTestCaseNoPoll(ProcessTestCase):
ProcessTestCase
.
tearDown
(
self
)
class
HelperFunctionTests
(
unittest
.
TestCase
):
@
unittest
.
skipIf
(
mswindows
,
"errno and EINTR make no sense on windows"
)
def
test_eintr_retry_call
(
self
):
record_calls
=
[]
def
fake_os_func
(
*
args
):
record_calls
.
append
(
args
)
if
len
(
record_calls
)
==
2
:
raise
OSError
(
errno
.
EINTR
,
"fake interrupted system call"
)
return
tuple
(
reversed
(
args
))
self
.
assertEqual
((
999
,
256
),
subprocess
.
_eintr_retry_call
(
fake_os_func
,
256
,
999
))
self
.
assertEqual
([(
256
,
999
)],
record_calls
)
# This time there will be an EINTR so it will loop once.
self
.
assertEqual
((
666
,),
subprocess
.
_eintr_retry_call
(
fake_os_func
,
666
))
self
.
assertEqual
([(
256
,
999
),
(
666
,),
(
666
,)],
record_calls
)
@
unittest
.
skipUnless
(
mswindows
,
"Windows-specific tests"
)
class
CommandsWithSpaces
(
BaseTestCase
):
...
...
@@ -2528,7 +2509,6 @@ def test_main():
Win32ProcessTestCase
,
CommandTests
,
ProcessTestCaseNoPoll
,
HelperFunctionTests
,
CommandsWithSpaces
,
ContextManagerTests
,
)
...
...
Misc/NEWS
View file @
f584b63f
...
...
@@ -10,6 +10,8 @@ Release date: TBA
Core and Builtins
-----------------
- Issue #23285: PEP 475 - EINTR handling.
- Issue #22735: Fix many edge cases (including crashes) involving custom mro()
implementations.
...
...
Modules/_io/fileio.c
View file @
f584b63f
...
...
@@ -218,6 +218,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
#ifdef HAVE_FSTAT
struct
stat
fdfstat
;
#endif
int
async_err
=
0
;
assert
(
PyFileIO_Check
(
oself
));
if
(
self
->
fd
>=
0
)
{
...
...
@@ -360,6 +361,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
errno
=
0
;
if
(
opener
==
Py_None
)
{
do
{
Py_BEGIN_ALLOW_THREADS
#ifdef MS_WINDOWS
if
(
widename
!=
NULL
)
...
...
@@ -369,6 +371,8 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
self
->
fd
=
open
(
name
,
flags
,
0666
);
Py_END_ALLOW_THREADS
}
while
(
self
->
fd
<
0
&&
errno
==
EINTR
&&
!
(
async_err
=
PyErr_CheckSignals
()));
}
else
{
PyObject
*
fdobj
;
...
...
@@ -397,6 +401,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
fd_is_own
=
1
;
if
(
self
->
fd
<
0
)
{
if
(
!
async_err
)
PyErr_SetFromErrnoWithFilenameObject
(
PyExc_OSError
,
nameobj
);
goto
error
;
}
...
...
@@ -550,7 +555,7 @@ fileio_readinto(fileio *self, PyObject *args)
{
Py_buffer
pbuf
;
Py_ssize_t
n
,
len
;
int
err
;
int
err
,
async_err
=
0
;
if
(
self
->
fd
<
0
)
return
err_closed
();
...
...
@@ -562,6 +567,7 @@ fileio_readinto(fileio *self, PyObject *args)
if
(
_PyVerify_fd
(
self
->
fd
))
{
len
=
pbuf
.
len
;
do
{
Py_BEGIN_ALLOW_THREADS
errno
=
0
;
#ifdef MS_WINDOWS
...
...
@@ -572,6 +578,8 @@ fileio_readinto(fileio *self, PyObject *args)
n
=
read
(
self
->
fd
,
pbuf
.
buf
,
len
);
#endif
Py_END_ALLOW_THREADS
}
while
(
n
<
0
&&
errno
==
EINTR
&&
!
(
async_err
=
PyErr_CheckSignals
()));
}
else
n
=
-
1
;
err
=
errno
;
...
...
@@ -580,6 +588,7 @@ fileio_readinto(fileio *self, PyObject *args)
if
(
err
==
EAGAIN
)
Py_RETURN_NONE
;
errno
=
err
;
if
(
!
async_err
)
PyErr_SetFromErrno
(
PyExc_IOError
);
return
NULL
;
}
...
...
@@ -627,6 +636,7 @@ fileio_readall(fileio *self)
Py_ssize_t
bytes_read
=
0
;
Py_ssize_t
n
;
size_t
bufsize
;
int
async_err
=
0
;
if
(
self
->
fd
<
0
)
return
err_closed
();
...
...
@@ -673,6 +683,7 @@ fileio_readall(fileio *self)
return
NULL
;
}
}
do
{
Py_BEGIN_ALLOW_THREADS
errno
=
0
;
n
=
bufsize
-
bytes_read
;
...
...
@@ -684,16 +695,11 @@ fileio_readall(fileio *self)
n
=
read
(
self
->
fd
,
PyBytes_AS_STRING
(
result
)
+
bytes_read
,
n
);
#endif
Py_END_ALLOW_THREADS
}
while
(
n
<
0
&&
errno
==
EINTR
&&
!
(
async_err
=
PyErr_CheckSignals
()));
if
(
n
==
0
)
break
;
if
(
n
<
0
)
{
if
(
errno
==
EINTR
)
{
if
(
PyErr_CheckSignals
())
{
Py_DECREF
(
result
);
return
NULL
;
}
continue
;
}
if
(
errno
==
EAGAIN
)
{
if
(
bytes_read
>
0
)
break
;
...
...
@@ -701,6 +707,7 @@ fileio_readall(fileio *self)
Py_RETURN_NONE
;
}
Py_DECREF
(
result
);
if
(
!
async_err
)
PyErr_SetFromErrno
(
PyExc_IOError
);
return
NULL
;
}
...
...
@@ -723,6 +730,7 @@ fileio_read(fileio *self, PyObject *args)
char
*
ptr
;
Py_ssize_t
n
;
Py_ssize_t
size
=
-
1
;
int
async_err
=
0
;
PyObject
*
bytes
;
if
(
self
->
fd
<
0
)
...
...
@@ -747,6 +755,7 @@ fileio_read(fileio *self, PyObject *args)
ptr
=
PyBytes_AS_STRING
(
bytes
);
if
(
_PyVerify_fd
(
self
->
fd
))
{
do
{
Py_BEGIN_ALLOW_THREADS
errno
=
0
;
#ifdef MS_WINDOWS
...
...
@@ -755,6 +764,8 @@ fileio_read(fileio *self, PyObject *args)
n
=
read
(
self
->
fd
,
ptr
,
size
);
#endif
Py_END_ALLOW_THREADS
}
while
(
n
<
0
&&
errno
==
EINTR
&&
!
(
async_err
=
PyErr_CheckSignals
()));
}
else
n
=
-
1
;
...
...
@@ -764,6 +775,7 @@ fileio_read(fileio *self, PyObject *args)
if
(
err
==
EAGAIN
)
Py_RETURN_NONE
;
errno
=
err
;
if
(
!
async_err
)
PyErr_SetFromErrno
(
PyExc_IOError
);
return
NULL
;
}
...
...
@@ -783,7 +795,7 @@ fileio_write(fileio *self, PyObject *args)
{
Py_buffer
pbuf
;
Py_ssize_t
n
,
len
;
int
err
;
int
err
,
async_err
=
0
;
if
(
self
->
fd
<
0
)
return
err_closed
();
...
...
@@ -794,6 +806,7 @@ fileio_write(fileio *self, PyObject *args)
return
NULL
;
if
(
_PyVerify_fd
(
self
->
fd
))
{
do
{
Py_BEGIN_ALLOW_THREADS
errno
=
0
;
len
=
pbuf
.
len
;
...
...
@@ -804,14 +817,15 @@ fileio_write(fileio *self, PyObject *args)
binary and the length is greater than 66,000 bytes (or less,
depending on heap usage). */
len
=
32767
;
}
else
if
(
len
>
INT_MAX
)
}
else
if
(
len
>
INT_MAX
)
len
=
INT_MAX
;
n
=
write
(
self
->
fd
,
pbuf
.
buf
,
(
int
)
len
);
#else
n
=
write
(
self
->
fd
,
pbuf
.
buf
,
len
);
#endif
Py_END_ALLOW_THREADS
}
while
(
n
<
0
&&
errno
==
EINTR
&&
!
(
async_err
=
PyErr_CheckSignals
()));
}
else
n
=
-
1
;
err
=
errno
;
...
...
@@ -822,6 +836,7 @@ fileio_write(fileio *self, PyObject *args)
if
(
err
==
EAGAIN
)
Py_RETURN_NONE
;
errno
=
err
;
if
(
!
async_err
)
PyErr_SetFromErrno
(
PyExc_IOError
);
return
NULL
;
}
...
...
Modules/posixmodule.c
View file @
f584b63f
This diff is collapsed.
Click to expand it.
Modules/socketmodule.c
View file @
f584b63f
...
...
@@ -2037,6 +2037,7 @@ sock_accept(PySocketSockObject *s)
PyObject
*
addr
=
NULL
;
PyObject
*
res
=
NULL
;
int
timeout
;
int
async_err
=
0
;
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
/* accept4() is available on Linux 2.6.28+ and glibc 2.10 */
static
int
accept4_works
=
-
1
;
...
...
@@ -2050,7 +2051,7 @@ sock_accept(PySocketSockObject *s)
return
select_error
();
BEGIN_SELECT_LOOP
(
s
)
do
{
Py_BEGIN_ALLOW_THREADS
timeout
=
internal_select_ex
(
s
,
0
,
interval
);
if
(
!
timeout
)
{
...
...
@@ -2070,7 +2071,7 @@ sock_accept(PySocketSockObject *s)
#endif
}
Py_END_ALLOW_THREADS
}
while
(
newfd
<
0
&&
errno
==
EINTR
&&
!
(
async_err
=
PyErr_CheckSignals
()));
if
(
timeout
==
1
)
{
PyErr_SetString
(
socket_timeout
,
"timed out"
);
return
NULL
;
...
...
@@ -2078,7 +2079,7 @@ sock_accept(PySocketSockObject *s)
END_SELECT_LOOP
(
s
)
if
(
newfd
==
INVALID_SOCKET
)
return
s
->
errorhandler
()
;
return
(
!
async_err
)
?
s
->
errorhandler
()
:
NULL
;
#ifdef MS_WINDOWS
if
(
!
SetHandleInformation
((
HANDLE
)
newfd
,
HANDLE_FLAG_INHERIT
,
0
))
{
...
...
@@ -2341,6 +2342,10 @@ sock_close(PySocketSockObject *s)
{
SOCKET_T
fd
;
/* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/
* and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
* for more details.
*/
if
((
fd
=
s
->
sock_fd
)
!=
-
1
)
{
s
->
sock_fd
=
-
1
;
Py_BEGIN_ALLOW_THREADS
...
...
@@ -2513,10 +2518,8 @@ sock_connect_ex(PySocketSockObject *s, PyObject *addro)
/* Signals are not errors (though they may raise exceptions). Adapted
from PyErr_SetFromErrnoWithFilenameObject(). */
#ifdef EINTR
if
(
res
==
EINTR
&&
PyErr_CheckSignals
())
return
NULL
;
#endif
return
PyLong_FromLong
((
long
)
res
);
}
...
...
@@ -2650,6 +2653,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags)
{
Py_ssize_t
outlen
=
-
1
;
int
timeout
;
int
async_err
=
0
;
if
(
!
IS_SELECTABLE
(
s
))
{
select_error
();
...
...
@@ -2661,6 +2665,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags)
}
BEGIN_SELECT_LOOP
(
s
)
do
{
Py_BEGIN_ALLOW_THREADS
timeout
=
internal_select_ex
(
s
,
0
,
interval
);
if
(
!
timeout
)
{
...
...
@@ -2673,6 +2678,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags)
#endif
}
Py_END_ALLOW_THREADS
}
while
(
outlen
<
0
&&
errno
==
EINTR
&&
!
(
async_err
=
PyErr_CheckSignals
()));
if
(
timeout
==
1
)
{
PyErr_SetString
(
socket_timeout
,
"timed out"
);
...
...
@@ -2682,6 +2688,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags)
if
(
outlen
<
0
)
{
/* Note: the call to errorhandler() ALWAYS indirectly returned
NULL, so ignore its return value */
if
(
!
async_err
)
s
->
errorhandler
();
return
-
1
;
}
...
...
@@ -2819,6 +2826,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags,
int
timeout
;
Py_ssize_t
n
=
-
1
;
socklen_t
addrlen
;
int
async_err
=
0
;
*
addr
=
NULL
;
...
...
@@ -2831,6 +2839,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags,
}
BEGIN_SELECT_LOOP
(
s
)
do
{
Py_BEGIN_ALLOW_THREADS
memset
(
&
addrbuf
,
0
,
addrlen
);
timeout
=
internal_select_ex
(
s
,
0
,
interval
);
...
...
@@ -2846,6 +2855,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags,
#endif
}
Py_END_ALLOW_THREADS
}
while
(
n
<
0
&&
errno
==
EINTR
&&
!
(
async_err
=
PyErr_CheckSignals
()));
if
(
timeout
==
1
)
{
PyErr_SetString
(
socket_timeout
,
"timed out"
);
...
...
@@ -2853,6 +2863,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags,
}
END_SELECT_LOOP
(
s
)
if
(
n
<
0
)
{
if
(
!
async_err
)
s
->
errorhandler
();
return
-
1
;
}
...
...
@@ -2993,6 +3004,7 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
{
ssize_t
bytes_received
=
-
1
;
int
timeout
;
int
async_err
=
0
;
sock_addr_t
addrbuf
;
socklen_t
addrbuflen
;
struct
msghdr
msg
=
{
0
};
...
...
@@ -3028,6 +3040,7 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
}
BEGIN_SELECT_LOOP
(
s
)
do
{
Py_BEGIN_ALLOW_THREADS
;
msg
.
msg_name
=
SAS2SA
(
&
addrbuf
);
msg
.
msg_namelen
=
addrbuflen
;
...
...
@@ -3043,9 +3056,12 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
PyErr_SetString
(
socket_timeout
,
"timed out"
);
goto
finally
;
}
}
while
(
bytes_received
<
0
&&
errno
==
EINTR
&&
!
(
async_err
=
PyErr_CheckSignals
()));
END_SELECT_LOOP
(
s
)
if
(
bytes_received
<
0
)
{
if
(
!
async_err
)
s
->
errorhandler
();
goto
finally
;
}
...
...
@@ -3305,6 +3321,7 @@ sock_send(PySocketSockObject *s, PyObject *args)
{
char
*
buf
;
Py_ssize_t
len
,
n
=
-
1
;
int
async_err
=
0
;
int
flags
=
0
,
timeout
;
Py_buffer
pbuf
;
...
...
@@ -3319,6 +3336,7 @@ sock_send(PySocketSockObject *s, PyObject *args)
len
=
pbuf
.
len
;
BEGIN_SELECT_LOOP
(
s
)
do
{
Py_BEGIN_ALLOW_THREADS
timeout
=
internal_select_ex
(
s
,
1
,
interval
);
if
(
!
timeout
)
{
...
...
@@ -3331,6 +3349,7 @@ sock_send(PySocketSockObject *s, PyObject *args)
#endif
}
Py_END_ALLOW_THREADS
}
while
(
n
<
0
&&
errno
==
EINTR
&&
!
(
async_err
=
PyErr_CheckSignals
()));
if
(
timeout
==
1
)
{
PyBuffer_Release
(
&
pbuf
);
PyErr_SetString
(
socket_timeout
,
"timed out"
);
...
...
@@ -3340,7 +3359,7 @@ sock_send(PySocketSockObject *s, PyObject *args)
PyBuffer_Release
(
&
pbuf
);
if
(
n
<
0
)
return
s
->
errorhandler
()
;
return
(
!
async_err
)
?
s
->
errorhandler
()
:
NULL
;
return
PyLong_FromSsize_t
(
n
);
}
...
...
@@ -3359,7 +3378,8 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
{
char
*
buf
;
Py_ssize_t
len
,
n
=
-
1
;
int
flags
=
0
,
timeout
,
saved_errno
;
int
async_err
=
0
;
int
flags
=
0
,
timeout
;
Py_buffer
pbuf
;
if
(
!
PyArg_ParseTuple
(
args
,
"y*|i:sendall"
,
&
pbuf
,
&
flags
))
...
...
@@ -3391,29 +3411,16 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
PyErr_SetString
(
socket_timeout
,
"timed out"
);
return
NULL
;
}
/* PyErr_CheckSignals() might change errno */
saved_errno
=
errno
;
/* We must run our signal handlers before looping again.
send() can return a successful partial write when it is
interrupted, so we can't restrict ourselves to EINTR. */
if
(
PyErr_CheckSignals
())
{
PyBuffer_Release
(
&
pbuf
);
return
NULL
;
}
if
(
n
<
0
)
{
/* If interrupted, try again */
if
(
saved_errno
==
EINTR
)
continue
;
else
break
;
}
if
(
n
>=
0
)
{
buf
+=
n
;
len
-=
n
;
}
while
(
len
>
0
);
}
}
while
(
len
>
0
&&
(
n
>=
0
||
errno
==
EINTR
)
&&
!
(
async_err
=
PyErr_CheckSignals
()));
PyBuffer_Release
(
&
pbuf
);
if
(
n
<
0
)
return
s
->
errorhandler
()
;
if
(
n
<
0
||
async_err
)
return
(
!
async_err
)
?
s
->
errorhandler
()
:
NULL
;
Py_INCREF
(
Py_None
);
return
Py_None
;
...
...
@@ -3439,6 +3446,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
Py_ssize_t
len
,
arglen
;
sock_addr_t
addrbuf
;
int
addrlen
,
n
=
-
1
,
flags
,
timeout
;
int
async_err
=
0
;
flags
=
0
;
arglen
=
PyTuple_Size
(
args
);
...
...
@@ -3473,6 +3481,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
}
BEGIN_SELECT_LOOP
(
s
)
do
{
Py_BEGIN_ALLOW_THREADS
timeout
=
internal_select_ex
(
s
,
1
,
interval
);
if
(
!
timeout
)
{
...
...
@@ -3487,6 +3496,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
#endif
}
Py_END_ALLOW_THREADS
}
while
(
n
<
0
&&
errno
==
EINTR
&&
!
(
async_err
=
PyErr_CheckSignals
()));
if
(
timeout
==
1
)
{
PyBuffer_Release
(
&
pbuf
);
...
...
@@ -3496,7 +3506,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
END_SELECT_LOOP
(
s
)
PyBuffer_Release
(
&
pbuf
);
if
(
n
<
0
)
return
s
->
errorhandler
()
;
return
(
!
async_err
)
?
s
->
errorhandler
()
:
NULL
;
return
PyLong_FromSsize_t
(
n
);
}
...
...
@@ -3528,6 +3538,7 @@ sock_sendmsg(PySocketSockObject *s, PyObject *args)
void
*
controlbuf
=
NULL
;
size_t
controllen
,
controllen_last
;
ssize_t
bytes_sent
=
-
1
;
int
async_err
=
0
;
int
addrlen
,
timeout
,
flags
=
0
;
PyObject
*
data_arg
,
*
cmsg_arg
=
NULL
,
*
addr_arg
=
NULL
,
*
data_fast
=
NULL
,
*
cmsg_fast
=
NULL
,
*
retval
=
NULL
;
...
...
@@ -3685,6 +3696,7 @@ sock_sendmsg(PySocketSockObject *s, PyObject *args)
}
BEGIN_SELECT_LOOP
(
s
)
do
{
Py_BEGIN_ALLOW_THREADS
;
timeout
=
internal_select_ex
(
s
,
1
,
interval
);
if
(
!
timeout
)
...
...
@@ -3694,9 +3706,12 @@ sock_sendmsg(PySocketSockObject *s, PyObject *args)
PyErr_SetString
(
socket_timeout
,
"timed out"
);
goto
finally
;
}
}
while
(
bytes_sent
<
0
&&
errno
==
EINTR
&&
!
(
async_err
=
PyErr_CheckSignals
()));
END_SELECT_LOOP
(
s
)
if
(
bytes_sent
<
0
)
{
if
(
!
async_err
)
s
->
errorhandler
();
goto
finally
;
}
...
...
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