Issue #22054: Add os.get_blocking() and os.set_blocking() functions to get and
set the blocking mode of a file descriptor (False if the O_NONBLOCK flag is set, True otherwise). These functions are not available on Windows.
This commit is contained in:
parent
6aa4269ed2
commit
1db9e7bb19
|
@ -807,6 +807,17 @@ as internal buffering of data.
|
||||||
Availability: Unix.
|
Availability: Unix.
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: get_blocking(fd)
|
||||||
|
|
||||||
|
Get the blocking mode of the file descriptor: ``False`` if the
|
||||||
|
:data:`O_NONBLOCK` flag is set, ``True`` if the flag is cleared.
|
||||||
|
|
||||||
|
See also :func:`set_blocking` and :meth:`socket.socket.setblocking`.
|
||||||
|
|
||||||
|
Availability: Unix.
|
||||||
|
|
||||||
|
.. versionadded:: 3.5
|
||||||
|
|
||||||
.. function:: isatty(fd)
|
.. function:: isatty(fd)
|
||||||
|
|
||||||
Return ``True`` if the file descriptor *fd* is open and connected to a
|
Return ``True`` if the file descriptor *fd* is open and connected to a
|
||||||
|
@ -1107,6 +1118,18 @@ or `the MSDN <http://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Window
|
||||||
.. versionadded:: 3.3
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: set_blocking(fd, blocking)
|
||||||
|
|
||||||
|
Set the blocking mode of the specified file descriptor. Set the
|
||||||
|
:data:`O_NONBLOCK` flag if blocking is ``False``, clear the flag otherwise.
|
||||||
|
|
||||||
|
See also :func:`get_blocking` and :meth:`socket.socket.setblocking`.
|
||||||
|
|
||||||
|
Availability: Unix.
|
||||||
|
|
||||||
|
.. versionadded:: 3.5
|
||||||
|
|
||||||
|
|
||||||
.. data:: SF_NODISKIO
|
.. data:: SF_NODISKIO
|
||||||
SF_MNOWAIT
|
SF_MNOWAIT
|
||||||
SF_SYNC
|
SF_SYNC
|
||||||
|
|
|
@ -70,7 +70,14 @@ PyAPI_FUNC(int) _Py_set_inheritable(int fd, int inheritable,
|
||||||
int *atomic_flag_works);
|
int *atomic_flag_works);
|
||||||
|
|
||||||
PyAPI_FUNC(int) _Py_dup(int fd);
|
PyAPI_FUNC(int) _Py_dup(int fd);
|
||||||
#endif
|
|
||||||
|
#ifndef MS_WINDOWS
|
||||||
|
PyAPI_FUNC(int) _Py_get_blocking(int fd);
|
||||||
|
|
||||||
|
PyAPI_FUNC(int) _Py_set_blocking(int fd, int blocking);
|
||||||
|
#endif /* !MS_WINDOWS */
|
||||||
|
|
||||||
|
#endif /* Py_LIMITED_API */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
"""Selector event loop for Unix with signal handling."""
|
"""Selector event loop for Unix with signal handling."""
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
import fcntl
|
|
||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
import socket
|
import socket
|
||||||
|
@ -259,12 +258,6 @@ class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop):
|
||||||
return server
|
return server
|
||||||
|
|
||||||
|
|
||||||
def _set_nonblocking(fd):
|
|
||||||
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
|
||||||
flags = flags | os.O_NONBLOCK
|
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
|
|
||||||
|
|
||||||
|
|
||||||
class _UnixReadPipeTransport(transports.ReadTransport):
|
class _UnixReadPipeTransport(transports.ReadTransport):
|
||||||
|
|
||||||
max_size = 256 * 1024 # max bytes we read in one event loop iteration
|
max_size = 256 * 1024 # max bytes we read in one event loop iteration
|
||||||
|
@ -280,7 +273,7 @@ class _UnixReadPipeTransport(transports.ReadTransport):
|
||||||
stat.S_ISSOCK(mode) or
|
stat.S_ISSOCK(mode) or
|
||||||
stat.S_ISCHR(mode)):
|
stat.S_ISCHR(mode)):
|
||||||
raise ValueError("Pipe transport is for pipes/sockets only.")
|
raise ValueError("Pipe transport is for pipes/sockets only.")
|
||||||
_set_nonblocking(self._fileno)
|
os.set_blocking(self._fileno, False)
|
||||||
self._protocol = protocol
|
self._protocol = protocol
|
||||||
self._closing = False
|
self._closing = False
|
||||||
self._loop.add_reader(self._fileno, self._read_ready)
|
self._loop.add_reader(self._fileno, self._read_ready)
|
||||||
|
@ -373,7 +366,7 @@ class _UnixWritePipeTransport(transports._FlowControlMixin,
|
||||||
stat.S_ISCHR(mode)):
|
stat.S_ISCHR(mode)):
|
||||||
raise ValueError("Pipe transport is only for "
|
raise ValueError("Pipe transport is only for "
|
||||||
"pipes, sockets and character devices")
|
"pipes, sockets and character devices")
|
||||||
_set_nonblocking(self._fileno)
|
os.set_blocking(self._fileno, False)
|
||||||
self._protocol = protocol
|
self._protocol = protocol
|
||||||
self._buffer = []
|
self._buffer = []
|
||||||
self._conn_lost = 0
|
self._conn_lost = 0
|
||||||
|
|
|
@ -590,8 +590,6 @@ def close_all(map=None, ignore_all=False):
|
||||||
# Regardless, this is useful for pipes, and stdin/stdout...
|
# Regardless, this is useful for pipes, and stdin/stdout...
|
||||||
|
|
||||||
if os.name == 'posix':
|
if os.name == 'posix':
|
||||||
import fcntl
|
|
||||||
|
|
||||||
class file_wrapper:
|
class file_wrapper:
|
||||||
# Here we override just enough to make a file
|
# Here we override just enough to make a file
|
||||||
# look like a socket for the purposes of asyncore.
|
# look like a socket for the purposes of asyncore.
|
||||||
|
@ -642,9 +640,7 @@ if os.name == 'posix':
|
||||||
pass
|
pass
|
||||||
self.set_file(fd)
|
self.set_file(fd)
|
||||||
# set it to non-blocking mode
|
# set it to non-blocking mode
|
||||||
flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0)
|
os.set_blocking(fd, False)
|
||||||
flags = flags | os.O_NONBLOCK
|
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
|
|
||||||
|
|
||||||
def set_file(self, fd):
|
def set_file(self, fd):
|
||||||
self.socket = file_wrapper(fd)
|
self.socket = file_wrapper(fd)
|
||||||
|
|
|
@ -306,9 +306,9 @@ class UnixReadPipeTransportTests(test_utils.TestCase):
|
||||||
self.pipe = mock.Mock(spec_set=io.RawIOBase)
|
self.pipe = mock.Mock(spec_set=io.RawIOBase)
|
||||||
self.pipe.fileno.return_value = 5
|
self.pipe.fileno.return_value = 5
|
||||||
|
|
||||||
fcntl_patcher = mock.patch('fcntl.fcntl')
|
blocking_patcher = mock.patch('os.set_blocking')
|
||||||
fcntl_patcher.start()
|
blocking_patcher.start()
|
||||||
self.addCleanup(fcntl_patcher.stop)
|
self.addCleanup(blocking_patcher.stop)
|
||||||
|
|
||||||
fstat_patcher = mock.patch('os.fstat')
|
fstat_patcher = mock.patch('os.fstat')
|
||||||
m_fstat = fstat_patcher.start()
|
m_fstat = fstat_patcher.start()
|
||||||
|
@ -469,9 +469,9 @@ class UnixWritePipeTransportTests(test_utils.TestCase):
|
||||||
self.pipe = mock.Mock(spec_set=io.RawIOBase)
|
self.pipe = mock.Mock(spec_set=io.RawIOBase)
|
||||||
self.pipe.fileno.return_value = 5
|
self.pipe.fileno.return_value = 5
|
||||||
|
|
||||||
fcntl_patcher = mock.patch('fcntl.fcntl')
|
blocking_patcher = mock.patch('os.set_blocking')
|
||||||
fcntl_patcher.start()
|
blocking_patcher.start()
|
||||||
self.addCleanup(fcntl_patcher.stop)
|
self.addCleanup(blocking_patcher.stop)
|
||||||
|
|
||||||
fstat_patcher = mock.patch('os.fstat')
|
fstat_patcher = mock.patch('os.fstat')
|
||||||
m_fstat = fstat_patcher.start()
|
m_fstat = fstat_patcher.start()
|
||||||
|
|
|
@ -44,10 +44,6 @@ try:
|
||||||
import threading
|
import threading
|
||||||
except ImportError:
|
except ImportError:
|
||||||
threading = None
|
threading = None
|
||||||
try:
|
|
||||||
import fcntl
|
|
||||||
except ImportError:
|
|
||||||
fcntl = None
|
|
||||||
|
|
||||||
def _default_chunk_size():
|
def _default_chunk_size():
|
||||||
"""Get the default TextIOWrapper chunk size"""
|
"""Get the default TextIOWrapper chunk size"""
|
||||||
|
@ -3230,26 +3226,20 @@ class MiscIOTest(unittest.TestCase):
|
||||||
with self.open(support.TESTFN, **kwargs) as f:
|
with self.open(support.TESTFN, **kwargs) as f:
|
||||||
self.assertRaises(TypeError, pickle.dumps, f, protocol)
|
self.assertRaises(TypeError, pickle.dumps, f, protocol)
|
||||||
|
|
||||||
@unittest.skipUnless(fcntl, 'fcntl required for this test')
|
|
||||||
def test_nonblock_pipe_write_bigbuf(self):
|
def test_nonblock_pipe_write_bigbuf(self):
|
||||||
self._test_nonblock_pipe_write(16*1024)
|
self._test_nonblock_pipe_write(16*1024)
|
||||||
|
|
||||||
@unittest.skipUnless(fcntl, 'fcntl required for this test')
|
|
||||||
def test_nonblock_pipe_write_smallbuf(self):
|
def test_nonblock_pipe_write_smallbuf(self):
|
||||||
self._test_nonblock_pipe_write(1024)
|
self._test_nonblock_pipe_write(1024)
|
||||||
|
|
||||||
def _set_non_blocking(self, fd):
|
@unittest.skipUnless(hasattr(os, 'set_blocking'),
|
||||||
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
'os.set_blocking() required for this test')
|
||||||
self.assertNotEqual(flags, -1)
|
|
||||||
res = fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
|
||||||
self.assertEqual(res, 0)
|
|
||||||
|
|
||||||
def _test_nonblock_pipe_write(self, bufsize):
|
def _test_nonblock_pipe_write(self, bufsize):
|
||||||
sent = []
|
sent = []
|
||||||
received = []
|
received = []
|
||||||
r, w = os.pipe()
|
r, w = os.pipe()
|
||||||
self._set_non_blocking(r)
|
os.set_blocking(r, False)
|
||||||
self._set_non_blocking(w)
|
os.set_blocking(w, False)
|
||||||
|
|
||||||
# To exercise all code paths in the C implementation we need
|
# To exercise all code paths in the C implementation we need
|
||||||
# to play with buffer sizes. For instance, if we choose a
|
# to play with buffer sizes. For instance, if we choose a
|
||||||
|
|
|
@ -1376,6 +1376,16 @@ class TestInvalidFD(unittest.TestCase):
|
||||||
def test_writev(self):
|
def test_writev(self):
|
||||||
self.check(os.writev, [b'abc'])
|
self.check(os.writev, [b'abc'])
|
||||||
|
|
||||||
|
def test_inheritable(self):
|
||||||
|
self.check(os.get_inheritable)
|
||||||
|
self.check(os.set_inheritable, True)
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(os, 'get_blocking'),
|
||||||
|
'needs os.get_blocking() and os.set_blocking()')
|
||||||
|
def test_blocking(self):
|
||||||
|
self.check(os.get_blocking)
|
||||||
|
self.check(os.set_blocking, True)
|
||||||
|
|
||||||
|
|
||||||
class LinkTests(unittest.TestCase):
|
class LinkTests(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -2591,6 +2601,21 @@ class FDInheritanceTests(unittest.TestCase):
|
||||||
self.assertEqual(os.get_inheritable(slave_fd), False)
|
self.assertEqual(os.get_inheritable(slave_fd), False)
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(os, 'get_blocking'),
|
||||||
|
'needs os.get_blocking() and os.set_blocking()')
|
||||||
|
class BlockingTests(unittest.TestCase):
|
||||||
|
def test_blocking(self):
|
||||||
|
fd = os.open(__file__, os.O_RDONLY)
|
||||||
|
self.addCleanup(os.close, fd)
|
||||||
|
self.assertEqual(os.get_blocking(fd), True)
|
||||||
|
|
||||||
|
os.set_blocking(fd, False)
|
||||||
|
self.assertEqual(os.get_blocking(fd), False)
|
||||||
|
|
||||||
|
os.set_blocking(fd, True)
|
||||||
|
self.assertEqual(os.get_blocking(fd), True)
|
||||||
|
|
||||||
|
|
||||||
@support.reap_threads
|
@support.reap_threads
|
||||||
def test_main():
|
def test_main():
|
||||||
support.run_unittest(
|
support.run_unittest(
|
||||||
|
@ -2626,6 +2651,7 @@ def test_main():
|
||||||
CPUCountTests,
|
CPUCountTests,
|
||||||
FDInheritanceTests,
|
FDInheritanceTests,
|
||||||
Win32JunctionTests,
|
Win32JunctionTests,
|
||||||
|
BlockingTests,
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -9,7 +9,6 @@ import errno
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
import fcntl
|
|
||||||
import platform
|
import platform
|
||||||
import pwd
|
import pwd
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -355,7 +354,7 @@ class PosixTester(unittest.TestCase):
|
||||||
def test_oscloexec(self):
|
def test_oscloexec(self):
|
||||||
fd = os.open(support.TESTFN, os.O_RDONLY|os.O_CLOEXEC)
|
fd = os.open(support.TESTFN, os.O_RDONLY|os.O_CLOEXEC)
|
||||||
self.addCleanup(os.close, fd)
|
self.addCleanup(os.close, fd)
|
||||||
self.assertTrue(fcntl.fcntl(fd, fcntl.F_GETFD) & fcntl.FD_CLOEXEC)
|
self.assertFalse(os.get_inheritable(fd))
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(posix, 'O_EXLOCK'),
|
@unittest.skipUnless(hasattr(posix, 'O_EXLOCK'),
|
||||||
'test needs posix.O_EXLOCK')
|
'test needs posix.O_EXLOCK')
|
||||||
|
@ -605,8 +604,8 @@ class PosixTester(unittest.TestCase):
|
||||||
self.addCleanup(os.close, w)
|
self.addCleanup(os.close, w)
|
||||||
self.assertFalse(os.get_inheritable(r))
|
self.assertFalse(os.get_inheritable(r))
|
||||||
self.assertFalse(os.get_inheritable(w))
|
self.assertFalse(os.get_inheritable(w))
|
||||||
self.assertTrue(fcntl.fcntl(r, fcntl.F_GETFL) & os.O_NONBLOCK)
|
self.assertFalse(os.get_blocking(r))
|
||||||
self.assertTrue(fcntl.fcntl(w, fcntl.F_GETFL) & os.O_NONBLOCK)
|
self.assertFalse(os.get_blocking(w))
|
||||||
# try reading from an empty pipe: this should fail, not block
|
# try reading from an empty pipe: this should fail, not block
|
||||||
self.assertRaises(OSError, os.read, r, 1)
|
self.assertRaises(OSError, os.read, r, 1)
|
||||||
# try a write big enough to fill-up the pipe: this should either
|
# try a write big enough to fill-up the pipe: this should either
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from test.support import verbose, run_unittest, import_module, reap_children
|
from test.support import verbose, run_unittest, import_module, reap_children
|
||||||
|
|
||||||
#Skip these tests if either fcntl or termios is not available
|
# Skip these tests if termios is not available
|
||||||
fcntl = import_module('fcntl')
|
|
||||||
import_module('termios')
|
import_module('termios')
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
|
@ -84,16 +83,18 @@ class PtyTest(unittest.TestCase):
|
||||||
# in master_open(), we need to read the EOF.
|
# in master_open(), we need to read the EOF.
|
||||||
|
|
||||||
# Ensure the fd is non-blocking in case there's nothing to read.
|
# Ensure the fd is non-blocking in case there's nothing to read.
|
||||||
orig_flags = fcntl.fcntl(master_fd, fcntl.F_GETFL)
|
blocking = os.get_blocking(master_fd)
|
||||||
fcntl.fcntl(master_fd, fcntl.F_SETFL, orig_flags | os.O_NONBLOCK)
|
|
||||||
try:
|
try:
|
||||||
s1 = os.read(master_fd, 1024)
|
os.set_blocking(master_fd, False)
|
||||||
self.assertEqual(b'', s1)
|
try:
|
||||||
except OSError as e:
|
s1 = os.read(master_fd, 1024)
|
||||||
if e.errno != errno.EAGAIN:
|
self.assertEqual(b'', s1)
|
||||||
raise
|
except OSError as e:
|
||||||
# Restore the original flags.
|
if e.errno != errno.EAGAIN:
|
||||||
fcntl.fcntl(master_fd, fcntl.F_SETFL, orig_flags)
|
raise
|
||||||
|
finally:
|
||||||
|
# Restore the original flags.
|
||||||
|
os.set_blocking(master_fd, blocking)
|
||||||
|
|
||||||
debug("Writing to slave_fd")
|
debug("Writing to slave_fd")
|
||||||
os.write(slave_fd, TEST_STRING_1)
|
os.write(slave_fd, TEST_STRING_1)
|
||||||
|
|
|
@ -276,7 +276,6 @@ class WakeupSignalTests(unittest.TestCase):
|
||||||
# use a subprocess to have only one thread
|
# use a subprocess to have only one thread
|
||||||
code = """if 1:
|
code = """if 1:
|
||||||
import _testcapi
|
import _testcapi
|
||||||
import fcntl
|
|
||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
import struct
|
import struct
|
||||||
|
@ -299,10 +298,7 @@ class WakeupSignalTests(unittest.TestCase):
|
||||||
|
|
||||||
signal.signal(signal.SIGALRM, handler)
|
signal.signal(signal.SIGALRM, handler)
|
||||||
read, write = os.pipe()
|
read, write = os.pipe()
|
||||||
for fd in (read, write):
|
os.set_blocking(write, False)
|
||||||
flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0)
|
|
||||||
flags = flags | os.O_NONBLOCK
|
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
|
|
||||||
signal.set_wakeup_fd(write)
|
signal.set_wakeup_fd(write)
|
||||||
|
|
||||||
test()
|
test()
|
||||||
|
@ -322,7 +318,6 @@ class WakeupSignalTests(unittest.TestCase):
|
||||||
code = """if 1:
|
code = """if 1:
|
||||||
import _testcapi
|
import _testcapi
|
||||||
import errno
|
import errno
|
||||||
import fcntl
|
|
||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
|
@ -333,8 +328,7 @@ class WakeupSignalTests(unittest.TestCase):
|
||||||
|
|
||||||
signal.signal(signal.SIGALRM, handler)
|
signal.signal(signal.SIGALRM, handler)
|
||||||
r, w = os.pipe()
|
r, w = os.pipe()
|
||||||
flags = fcntl.fcntl(r, fcntl.F_GETFL, 0)
|
os.set_blocking(r, False)
|
||||||
fcntl.fcntl(r, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
|
||||||
|
|
||||||
# Set wakeup_fd a read-only file descriptor to trigger the error
|
# Set wakeup_fd a read-only file descriptor to trigger the error
|
||||||
signal.set_wakeup_fd(r)
|
signal.set_wakeup_fd(r)
|
||||||
|
|
|
@ -113,6 +113,10 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #22054: Add os.get_blocking() and os.set_blocking() functions to get
|
||||||
|
and set the blocking mode of a file descriptor (False if the O_NONBLOCK flag
|
||||||
|
is set, True otherwise). These functions are not available on Windows.
|
||||||
|
|
||||||
- Issue #17172: Make turtledemo start as active on Mac even when run with
|
- Issue #17172: Make turtledemo start as active on Mac even when run with
|
||||||
subprocess. Patch by Ned Daily and Lita Cho.
|
subprocess. Patch by Ned Daily and Lita Cho.
|
||||||
|
|
||||||
|
|
|
@ -11146,6 +11146,56 @@ posix_set_handle_inheritable(PyObject *self, PyObject *args)
|
||||||
#endif /* MS_WINDOWS */
|
#endif /* MS_WINDOWS */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MS_WINDOWS
|
||||||
|
PyDoc_STRVAR(get_blocking__doc__,
|
||||||
|
"get_blocking(fd) -> bool\n" \
|
||||||
|
"\n" \
|
||||||
|
"Get the blocking mode of the file descriptor:\n" \
|
||||||
|
"False if the O_NONBLOCK flag is set, True if the flag is cleared.");
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
posix_get_blocking(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int blocking;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "i:get_blocking", &fd))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!_PyVerify_fd(fd))
|
||||||
|
return posix_error();
|
||||||
|
|
||||||
|
blocking = _Py_get_blocking(fd);
|
||||||
|
if (blocking < 0)
|
||||||
|
return NULL;
|
||||||
|
return PyBool_FromLong(blocking);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(set_blocking__doc__,
|
||||||
|
"set_blocking(fd, blocking)\n" \
|
||||||
|
"\n" \
|
||||||
|
"Set the blocking mode of the specified file descriptor.\n" \
|
||||||
|
"Set the O_NONBLOCK flag if blocking is False,\n" \
|
||||||
|
"clear the O_NONBLOCK flag otherwise.");
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
posix_set_blocking(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
int fd, blocking;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "ii:set_blocking", &fd, &blocking))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!_PyVerify_fd(fd))
|
||||||
|
return posix_error();
|
||||||
|
|
||||||
|
if (_Py_set_blocking(fd, blocking) < 0)
|
||||||
|
return NULL;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
#endif /* !MS_WINDOWS */
|
||||||
|
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
dump buffer
|
dump buffer
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
@ -11605,6 +11655,10 @@ static PyMethodDef posix_methods[] = {
|
||||||
METH_VARARGS, get_handle_inheritable__doc__},
|
METH_VARARGS, get_handle_inheritable__doc__},
|
||||||
{"set_handle_inheritable", posix_set_handle_inheritable,
|
{"set_handle_inheritable", posix_set_handle_inheritable,
|
||||||
METH_VARARGS, set_handle_inheritable__doc__},
|
METH_VARARGS, set_handle_inheritable__doc__},
|
||||||
|
#endif
|
||||||
|
#ifndef MS_WINDOWS
|
||||||
|
{"get_blocking", posix_get_blocking, METH_VARARGS, get_blocking__doc__},
|
||||||
|
{"set_blocking", posix_set_blocking, METH_VARARGS, set_blocking__doc__},
|
||||||
#endif
|
#endif
|
||||||
{NULL, NULL} /* Sentinel */
|
{NULL, NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
|
@ -1045,3 +1045,56 @@ _Py_dup(int fd)
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef MS_WINDOWS
|
||||||
|
/* Get the blocking mode of the file descriptor.
|
||||||
|
Return 0 if the O_NONBLOCK flag is set, 1 if the flag is cleared,
|
||||||
|
raise an exception and return -1 on error. */
|
||||||
|
int
|
||||||
|
_Py_get_blocking(int fd)
|
||||||
|
{
|
||||||
|
int flags = fcntl(fd, F_GETFL, 0);
|
||||||
|
if (flags < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(flags & O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the blocking mode of the specified file descriptor.
|
||||||
|
|
||||||
|
Set the O_NONBLOCK flag if blocking is False, clear the O_NONBLOCK flag
|
||||||
|
otherwise.
|
||||||
|
|
||||||
|
Return 0 on success, raise an exception and return -1 on error. */
|
||||||
|
int
|
||||||
|
_Py_set_blocking(int fd, int blocking)
|
||||||
|
{
|
||||||
|
#if defined(HAVE_SYS_IOCTL_H) && defined(FIONBIO)
|
||||||
|
int arg = !blocking;
|
||||||
|
if (ioctl(fd, FIONBIO, &arg) < 0)
|
||||||
|
goto error;
|
||||||
|
#else
|
||||||
|
int flags, res;
|
||||||
|
|
||||||
|
flags = fcntl(fd, F_GETFL, 0);
|
||||||
|
if (flags < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (blocking)
|
||||||
|
flags = flags & (~O_NONBLOCK);
|
||||||
|
else
|
||||||
|
flags = flags | O_NONBLOCK;
|
||||||
|
|
||||||
|
res = fcntl(fd, F_SETFL, flags);
|
||||||
|
if (res < 0)
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue