[pypy-commit] pypy py3.5-noninherit: Implement the basics
arigo
pypy.commits at gmail.com
Fri Aug 26 08:16:30 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: py3.5-noninherit
Changeset: r86552:6ba4a5df9526
Date: 2016-08-26 14:15 +0200
http://bitbucket.org/pypy/pypy/changeset/6ba4a5df9526/
Log: Implement the basics
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -2080,13 +2080,45 @@
eci_inheritable = eci.merge(ExternalCompilationInfo(
separate_module_sources=["""
+#include <errno.h>
+
RPY_EXTERN
int rpy_set_inheritable(int fd, int inheritable)
{
- /* XXX minimal impl. XXX */
- int request = inheritable ? FIONCLEX : FIOCLEX;
- return ioctl(fd, request, NULL);
+ static int ioctl_works = -1;
+ int flags;
+
+ if (ioctl_works != 0) {
+ int request = inheritable ? FIONCLEX : FIOCLEX;
+ int err = ioctl(fd, request, NULL);
+ if (!err) {
+ ioctl_works = 1;
+ return 0;
+ }
+
+ if (errno != ENOTTY && errno != EACCES) {
+ return -1;
+ }
+ else {
+ /* ENOTTY: The ioctl is declared but not supported by the
+ kernel. EACCES: SELinux policy, this can be the case on
+ Android. */
+ ioctl_works = 0;
+ }
+ /* fallback to fcntl() if ioctl() does not work */
+ }
+
+ flags = fcntl(fd, F_GETFD);
+ if (flags < 0)
+ return -1;
+
+ if (inheritable)
+ flags &= ~FD_CLOEXEC;
+ else
+ flags |= FD_CLOEXEC;
+ return fcntl(fd, F_SETFD, flags);
}
+
RPY_EXTERN
int rpy_get_inheritable(int fd)
{
@@ -2106,10 +2138,25 @@
compilation_info=eci_inheritable)
def set_inheritable(fd, inheritable):
- error = c_set_inheritable(fd, inheritable)
- handle_posix_error('set_inheritable', error)
+ result = c_set_inheritable(fd, inheritable)
+ handle_posix_error('set_inheritable', result)
def get_inheritable(fd):
res = c_get_inheritable(fd)
res = handle_posix_error('get_inheritable', res)
return res != 0
+
+class SetNonInheritableCache(object):
+ """Make one prebuilt instance of this for each path that creates
+ file descriptors, where you don't necessarily know if that function
+ returns inheritable or non-inheritable file descriptors.
+ """
+ _immutable_fields_ = ['cached_inheritable?']
+ cached_inheritable = -1 # -1 = don't know yet; 0 = off; 1 = on
+
+ def set_non_inheritable(self, fd):
+ if self.cached_inheritable == -1:
+ self.cached_inheritable = get_inheritable(fd)
+ if self.cached_inheritable == 1:
+ # 'fd' is inheritable; we must manually turn it off
+ set_inheritable(fd, False)
diff --git a/rpython/rlib/test/test_rposix.py b/rpython/rlib/test/test_rposix.py
--- a/rpython/rlib/test/test_rposix.py
+++ b/rpython/rlib/test/test_rposix.py
@@ -589,3 +589,18 @@
assert rposix.get_inheritable(fd1) == False
os.close(fd1)
os.close(fd2)
+
+def test_SetNonInheritableCache():
+ cache = rposix.SetNonInheritableCache()
+ fd1, fd2 = os.pipe()
+ assert rposix.get_inheritable(fd1) == True
+ assert rposix.get_inheritable(fd1) == True
+ assert cache.cached_inheritable == -1
+ cache.set_non_inheritable(fd1)
+ assert cache.cached_inheritable == 1
+ cache.set_non_inheritable(fd2)
+ assert cache.cached_inheritable == 1
+ assert rposix.get_inheritable(fd1) == False
+ assert rposix.get_inheritable(fd1) == False
+ os.close(fd1)
+ os.close(fd2)
More information about the pypy-commit
mailing list