Author: Armin Rigo <[email protected]>
Branch: py3.5
Changeset: r90564:33eb17e3bdc3
Date: 2017-03-05 12:54 +0100
http://bitbucket.org/pypy/pypy/changeset/33eb17e3bdc3/

Log:    Implement sendfile() in the posix module. (Not implemented so far:
        the extra BSD or OS/X arguments)

diff --git a/pypy/module/posix/__init__.py b/pypy/module/posix/__init__.py
--- a/pypy/module/posix/__init__.py
+++ b/pypy/module/posix/__init__.py
@@ -213,6 +213,9 @@
             assert getattr(rposix, _name) is not None, "missing %r" % (_name,)
             interpleveldefs[_name] = 'space.wrap(%d)' % getattr(rposix, _name)
 
+    if hasattr(rposix, 'sendfile'):
+        interpleveldefs['sendfile'] = 'interp_posix.sendfile'
+
     for _name in ["O_CLOEXEC"]:
         if getattr(rposix, _name) is not None:
             interpleveldefs[_name] = 'space.wrap(%d)' % getattr(rposix, _name)
diff --git a/pypy/module/posix/interp_posix.py 
b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -24,6 +24,7 @@
 
 
 _WIN32 = sys.platform == 'win32'
+_LINUX = sys.platform.startswith('linux')
 if _WIN32:
     from rpython.rlib import rwin32
 
@@ -2346,3 +2347,30 @@
         rposix.set_status_flags(fd, flags)
     except OSError as e:
         raise wrap_oserror(space, e, eintr_retry=False)
+
+@unwrap_spec(out=c_int, in_=c_int, count=int)
+def sendfile(space, out, in_, w_offset, count):
+    # NB. argument name difference with CPython: "in" versus "in_".
+    # According to a comment in posixmodule.c, the authors are aware that
+    # "in" is a Python keyword and so the argument name is bogus, but don't
+    # do anything about it anyway.  PyPy calls it "in_" instead because
+    # "in" would require all sorts of special cases.  I hope nobody
+    # relies on the strange name of CPython.
+
+    # XXX only supports the common arguments for now (BSD takes more)
+    if _LINUX and space.is_none(w_offset):
+        while True:
+            try:
+                res = rposix.sendfile_no_offset(out, in_, count)
+                break
+            except OSError as e:
+                wrap_oserror(space, e, eintr_retry=True)
+    else:
+        offset = space.gateway_r_longlong_w(w_offset)
+        while True:
+            try:
+                res = rposix.sendfile(out, in_, offset, count)
+                break
+            except OSError as e:
+                wrap_oserror(space, e, eintr_retry=True)
+    return space.newint(res)
diff --git a/pypy/module/posix/test/test_posix2.py 
b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -14,7 +14,7 @@
 USEMODULES = ['binascii', 'posix', 'signal', 'struct', 'time']
 # py3k os.open uses subprocess, requiring the following per platform
 if os.name != 'nt':
-    USEMODULES += ['fcntl', 'select', '_posixsubprocess']
+    USEMODULES += ['fcntl', 'select', '_posixsubprocess', '_socket']
 else:
     USEMODULES += ['_rawffi', 'thread']
 
@@ -1189,6 +1189,36 @@
             raises(OSError, posix.get_blocking, 1234567)
             raises(OSError, posix.set_blocking, 1234567, True)
 
+    if sys.platform != 'win32':
+        def test_sendfile(self):
+            import _socket, posix
+            s1, s2 = _socket.socketpair()
+            fd = posix.open(self.path, posix.O_RDONLY)
+            res = posix.sendfile(s1.fileno(), fd, 3, 5)
+            assert res == 5
+            assert posix.lseek(fd, 0, 1) == 0
+            data = s2.recv(10)
+            expected = b'this is a test'[3:8]
+            assert data == expected
+            posix.close(fd)
+            s2.close()
+            s1.close()
+
+    if sys.platform.startswith('linux'):
+        def test_sendfile_no_offset(self):
+            import _socket, posix
+            s1, s2 = _socket.socketpair()
+            fd = posix.open(self.path, posix.O_RDONLY)
+            posix.lseek(fd, 3, 0)
+            res = posix.sendfile(s1.fileno(), fd, None, 5)
+            assert res == 5
+            assert posix.lseek(fd, 0, 1) == 8
+            data = s2.recv(10)
+            expected = b'this is a test'[3:8]
+            assert data == expected
+            posix.close(fd)
+            s2.close()
+            s1.close()
 
     def test_urandom(self):
         os = self.posix
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to