Author: Joannah Nanjekye <nanjekyejoan...@gmail.com>
Branch: pread/pwrite
Changeset: r90387:c61e7a2fca32
Date: 2017-02-25 13:18 +0300
http://bitbucket.org/pypy/pypy/changeset/c61e7a2fca32/

Log:    retry transparently when we get EINTR error

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
@@ -206,11 +206,18 @@
         interpleveldefs['get_blocking'] = 'interp_posix.get_blocking'
         interpleveldefs['set_blocking'] = 'interp_posix.set_blocking'
 
+    if hasattr(rposix, 'getpriority'):
+        interpleveldefs['getpriority'] = 'interp_posix.getpriority'
+        interpleveldefs['setpriority'] = 'interp_posix.setpriority'
+        for _name in ['PRIO_PROCESS', 'PRIO_PGRP', 'PRIO_USER']:
+            assert getattr(rposix, _name) is not None, "missing %r" % (_name,)
+            interpleveldefs[_name] = 'space.wrap(%d)' % getattr(rposix, _name)
+
     if hasattr(rposix, 'pread'):
         interpleveldefs['pread'] = 'interp_posix.pread'
     if hasattr(rposix, 'pwrite'):
-        interpleveldefs['pwrite'] = 'interp_posix.pwrite'
-        
+       interpleveldefs['pwrite'] = 'interp_posix.pwrite'
+       
     for _name in ["O_CLOEXEC"]:
         if getattr(rposix, _name) is not None:
             interpleveldefs[_name] = 'space.wrap(%d)' % getattr(rposix, _name)
@@ -225,4 +232,9 @@
 for constant in dir(os):
     value = getattr(os, constant)
     if constant.isupper() and type(value) is int:
+        if constant in ['SEEK_SET', 'SEEK_CUR', 'SEEK_END',
+                        'P_NOWAIT', 'P_NOWAITO', 'P_WAIT']:
+            # obscure, but these names are not in CPython's posix module
+            # and if we put it here then they end up twice in 'os.__all__'
+            continue
         Module.interpleveldefs[constant] = "space.wrap(%s)" % value
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
@@ -40,9 +40,9 @@
 
 def wrap_uid(space, uid):
     if uid <= r_uint(sys.maxint):
-        return space.wrap(intmask(uid))
+        return space.newint(intmask(uid))
     else:
-        return space.wrap(uid)     # an unsigned number
+        return space.newint(uid)     # an unsigned number
 wrap_gid = wrap_uid
 
 class FileEncoder(object):
@@ -66,7 +66,7 @@
         self.w_obj = w_obj
 
     def as_bytes(self):
-        return self.space.fsencode_w(self.w_obj)
+        return self.space.bytes0_w(self.w_obj)
 
     def as_unicode(self):
         return self.space.fsdecode_w(self.w_obj)
@@ -85,7 +85,7 @@
             fname = FileEncoder(space, w_fname)
             return func(fname, *args)
         else:
-            fname = space.fsencode_w(w_fname)
+            fname = space.bytes0_w(w_fname)
             return func(fname, *args)
     return dispatch
 
@@ -148,11 +148,15 @@
     try:
         path_b = space.fsencode_w(w_value)
         return Path(-1, path_b, None, w_value)
-    except OperationError:
+    except OperationError as e:
+        if not e.match(space, space.w_TypeError):
+            raise
         if allow_fd:
             fd = unwrap_fd(space, w_value, "string, bytes or integer")
             return Path(fd, None, None, w_value)
-    raise oefmt(space.w_TypeError, "illegal type for path parameter")
+    raise oefmt(space.w_TypeError,
+                "illegal type for path parameter (expected "
+                "string or bytes, got %T)", w_value)
 
 class _PathOrFd(Unwrapper):
     def unwrap(self, space, w_value):
@@ -226,16 +230,22 @@
   If it is unavailable, using it will raise a NotImplementedError."""
     if rposix.O_CLOEXEC is not None:
         flags |= rposix.O_CLOEXEC
+    while True:
+        try:
+            if rposix.HAVE_OPENAT and dir_fd != DEFAULT_DIR_FD:
+                path = space.fsencode_w(w_path)
+                fd = rposix.openat(path, flags, mode, dir_fd)
+            else:
+                fd = dispatch_filename(rposix.open)(space, w_path, flags, mode)
+            break
+        except OSError as e:
+            wrap_oserror2(space, e, w_path, eintr_retry=True)
     try:
-        if rposix.HAVE_OPENAT and dir_fd != DEFAULT_DIR_FD:
-            path = space.fsencode_w(w_path)
-            fd = rposix.openat(path, flags, mode, dir_fd)
-        else:
-            fd = dispatch_filename(rposix.open)(space, w_path, flags, mode)
         _open_inhcache.set_non_inheritable(fd)
     except OSError as e:
-        raise wrap_oserror2(space, e, w_path)
-    return space.wrap(fd)
+        rposix.c_close(fd)
+        raise wrap_oserror2(space, e, w_path, eintr_retry=False)
+    return space.newint(fd)
 
 @unwrap_spec(fd=c_int, position=r_longlong, how=c_int)
 def lseek(space, fd, position, how):
@@ -245,9 +255,9 @@
     try:
         pos = os.lseek(fd, position, how)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     else:
-        return space.wrap(pos)
+        return space.newint(pos)
 
 @unwrap_spec(fd=c_int)
 def isatty(space, fd):
@@ -256,19 +266,20 @@
     try:
         res = os.isatty(fd)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     else:
-        return space.wrap(res)
+        return space.newbool(res)
 
 @unwrap_spec(fd=c_int, length=int)
 def read(space, fd, length):
     """Read data from a file descriptor."""
-    try:
-        s = os.read(fd, length)
-    except OSError as e:
-        raise wrap_oserror(space, e)
-    else:
-        return space.newbytes(s)
+    while True:
+        try:
+            s = os.read(fd, length)
+        except OSError as e:
+            wrap_oserror(space, e, eintr_retry=True)
+        else:
+            return space.newbytes(s)
         
 @unwrap_spec(fd=c_int)
 def write(space, fd, w_data):
@@ -284,15 +295,19 @@
 
 @unwrap_spec(fd=c_int, length=int, offset=int)
 def pread(space, fd, length, offset):
+    """Read a string to a file descriptor at a given offset.
+    """
     try:
         s = rposix.pread(fd, length, offset)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=True)
     else:
-        return space.newbytes(s)
+       return space.newbytes(s)
 
 @unwrap_spec(fd=c_int, offset=int)
 def pwrite(space, fd, w_data, offset):
+    """Write a string to a file descriptor at a given offset.
+    """
     data = space.getarg_w('y*', w_data)
     try:
         res = rposix.pwrite(fd, data.as_str(), offset)
@@ -304,10 +319,14 @@
 @unwrap_spec(fd=c_int)
 def close(space, fd):
     """Close a file descriptor (for low level IO)."""
+    # PEP 475 note: os.close() must not retry upon EINTR.  Like in
+    # previous versions of Python it raises OSError in this case.
+    # The text of PEP 475 seems to suggest that EINTR is eaten and
+    # hidden from app-level, but it is not the case in CPython 3.5.2.
     try:
         os.close(fd)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 @unwrap_spec(fd_low=c_int, fd_high=c_int)
 def closerange(fd_low, fd_high):
@@ -317,10 +336,12 @@
 @unwrap_spec(fd=c_int, length=r_longlong)
 def ftruncate(space, fd, length):
     """Truncate a file (by file descriptor) to a specified length."""
-    try:
-        os.ftruncate(fd, length)
-    except OSError as e:
-        raise wrap_oserror(space, e)
+    while True:
+        try:
+            os.ftruncate(fd, length)
+            break
+        except OSError as e:
+            wrap_oserror(space, e, eintr_retry=True)
 
 def truncate(space, w_path, w_length):
     """Truncate a file to a specified length."""
@@ -330,7 +351,7 @@
         if space.isinstance_w(w_path, space.w_int):
             w_fd = w_path
         else:
-            w_fd = open(space, w_path, os.O_RDWR | os.O_CREAT)
+            w_fd = open(space, w_path, os.O_WRONLY)
             allocated_fd = True
 
         fd = space.c_filedescriptor_w(w_fd)
@@ -344,19 +365,23 @@
 def fsync(space, w_fd):
     """Force write of file with filedescriptor to disk."""
     fd = space.c_filedescriptor_w(w_fd)
-    try:
-        os.fsync(fd)
-    except OSError as e:
-        raise wrap_oserror(space, e)
+    while True:
+        try:
+            os.fsync(fd)
+            break
+        except OSError as e:
+            wrap_oserror(space, e, eintr_retry=True)
 
 def fdatasync(space, w_fd):
     """Force write of file with filedescriptor to disk.
 Does not force update of metadata."""
     fd = space.c_filedescriptor_w(w_fd)
-    try:
-        os.fdatasync(fd)
-    except OSError as e:
-        raise wrap_oserror(space, e)
+    while True:
+        try:
+            os.fdatasync(fd)
+            break
+        except OSError as e:
+            wrap_oserror(space, e, eintr_retry=True)
 
 def sync(space):
     """Force write of everything to disk."""
@@ -366,10 +391,12 @@
     """Change to the directory of the given file descriptor.  fildes must be
 opened on a directory, not a file."""
     fd = space.c_filedescriptor_w(w_fd)
-    try:
-        os.fchdir(fd)
-    except OSError as e:
-        raise wrap_oserror(space, e)
+    while True:
+        try:
+            os.fchdir(fd)
+            break
+        except OSError as e:
+            wrap_oserror(space, e, eintr_retry=True)
 
 # ____________________________________________________________
 
@@ -386,7 +413,7 @@
         if i < rposix_stat.N_INDEXABLE_FIELDS:
             # get the first 10 items by indexing; this gives us
             # 'st_Xtime' as an integer, too
-            w_value = space.wrap(st[i])
+            w_value = space.newint(st[i])
             lst[i] = w_value
         else:
             try:
@@ -396,8 +423,8 @@
                 assert name.startswith('nsec_')
                 value = rposix_stat.get_stat_ns_as_bigint(st, name[5:])
                 value = value.tolong() % 1000000000
-            w_value = space.wrap(value)
-            space.setitem(w_keywords, space.wrap(name), w_value)
+            w_value = space.newint(value)
+            space.setitem(w_keywords, space.newtext(name), w_value)
 
     # Note: 'w_keywords' contains the three attributes 'nsec_Xtime'.
     # We have an app-level property in app_posix.stat_result to
@@ -406,27 +433,27 @@
     # non-rounded values for name-based access
     if stat_float_times:
         space.setitem(w_keywords,
-                      space.wrap('st_atime'), space.wrap(st.st_atime))
+                      space.newtext('st_atime'), space.newfloat(st.st_atime))
         space.setitem(w_keywords,
-                      space.wrap('st_mtime'), space.wrap(st.st_mtime))
+                      space.newtext('st_mtime'), space.newfloat(st.st_mtime))
         space.setitem(w_keywords,
-                      space.wrap('st_ctime'), space.wrap(st.st_ctime))
+                      space.newtext('st_ctime'), space.newfloat(st.st_ctime))
     #else:
     #   filled by the __init__ method
 
     w_tuple = space.newtuple(lst)
     w_stat_result = space.getattr(space.getbuiltinmodule(os.name),
-                                  space.wrap('stat_result'))
+                                  space.newtext('stat_result'))
     return space.call_function(w_stat_result, w_tuple, w_keywords)
 
 
 def build_statvfs_result(space, st):
     vals_w = [None] * len(rposix_stat.STATVFS_FIELDS)
     for i, (name, _) in STATVFS_FIELDS:
-        vals_w[i] = space.wrap(getattr(st, name))
+        vals_w[i] = space.newint(getattr(st, name))
     w_tuple = space.newtuple(vals_w)
     w_statvfs_result = space.getattr(
-        space.getbuiltinmodule(os.name), space.wrap('statvfs_result'))
+        space.getbuiltinmodule(os.name), space.newtext('statvfs_result'))
     return space.call_function(w_statvfs_result, w_tuple)
 
 
@@ -434,12 +461,13 @@
 def fstat(space, fd):
     """Perform a stat system call on the file referenced to by an open
 file descriptor."""
-    try:
-        st = rposix_stat.fstat(fd)
-    except OSError as e:
-        raise wrap_oserror(space, e)
-    else:
-        return build_stat_result(space, st)
+    while True:
+        try:
+            st = rposix_stat.fstat(fd)
+        except OSError as e:
+            wrap_oserror(space, e, eintr_retry=True)
+        else:
+            return build_stat_result(space, st)
 
 @unwrap_spec(
     path=path_or_fd(allow_fd=True),
@@ -485,7 +513,7 @@
             raise oefmt(space.w_NotImplementedError,
                 "%s: unsupported argument combination", funcname)
     except OSError as e:
-        raise wrap_oserror2(space, e, path.w_path)
+        raise wrap_oserror2(space, e, path.w_path, eintr_retry=False)
     else:
         return build_stat_result(space, st)
 
@@ -515,19 +543,20 @@
     state = space.fromcache(StatState)
 
     if newval == -1:
-        return space.wrap(state.stat_float_times)
+        return space.newbool(state.stat_float_times)
     else:
         state.stat_float_times = (newval != 0)
 
 
 @unwrap_spec(fd=c_int)
 def fstatvfs(space, fd):
-    try:
-        st = rposix_stat.fstatvfs(fd)
-    except OSError as e:
-        raise wrap_oserror(space, e)
-    else:
-        return build_statvfs_result(space, st)
+    while True:
+        try:
+            st = rposix_stat.fstatvfs(fd)
+        except OSError as e:
+            wrap_oserror(space, e, eintr_retry=True)
+        else:
+            return build_statvfs_result(space, st)
 
 
 def statvfs(space, w_path):
@@ -543,7 +572,7 @@
             rposix_stat.statvfs,
             allow_fd_fn=rposix_stat.fstatvfs)(space, w_path)
     except OSError as e:
-        raise wrap_oserror2(space, e, w_path)
+        raise wrap_oserror2(space, e, w_path, eintr_retry=False)
     else:
         return build_statvfs_result(space, st)
 
@@ -555,17 +584,19 @@
     try:
         newfd = rposix.dup(fd, inheritable=False)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     else:
-        return space.wrap(newfd)
+        return space.newint(newfd)
 
 @unwrap_spec(fd=c_int, fd2=c_int, inheritable=bool)
 def dup2(space, fd, fd2, inheritable=1):
     """Duplicate a file descriptor."""
+    # like os.close(), this can still raise EINTR to app-level in
+    # CPython 3.5.2
     try:
         rposix.dup2(fd, fd2, inheritable)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 @unwrap_spec(mode=c_int,
     dir_fd=DirFD(rposix.HAVE_FACCESSAT), effective_ids=bool,
@@ -610,9 +641,9 @@
         else:
             ok = dispatch_filename(rposix.access)(space, w_path, mode)
     except OSError as e:
-        raise wrap_oserror2(space, e, w_path)
+        raise wrap_oserror2(space, e, w_path, eintr_retry=False)
     else:
-        return space.wrap(ok)
+        return space.newbool(ok)
 
 
 def times(space):
@@ -624,13 +655,13 @@
     try:
         times = os.times()
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     else:
-        return space.newtuple([space.wrap(times[0]),
-                               space.wrap(times[1]),
-                               space.wrap(times[2]),
-                               space.wrap(times[3]),
-                               space.wrap(times[4])])
+        return space.newtuple([space.newfloat(times[0]),
+                               space.newfloat(times[1]),
+                               space.newfloat(times[2]),
+                               space.newfloat(times[3]),
+                               space.newfloat(times[4])])
 
 @unwrap_spec(command='fsencode')
 def system(space, command):
@@ -638,9 +669,9 @@
     try:
         rc = os.system(command)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     else:
-        return space.wrap(rc)
+        return space.newint(rc)
 
 @unwrap_spec(dir_fd=DirFD(rposix.HAVE_UNLINKAT))
 def unlink(space, w_path, __kwonly__, dir_fd=DEFAULT_DIR_FD):
@@ -659,7 +690,7 @@
         else:
             dispatch_filename(rposix.unlink)(space, w_path)
     except OSError as e:
-        raise wrap_oserror2(space, e, w_path)
+        raise wrap_oserror2(space, e, w_path, eintr_retry=False)
 
 @unwrap_spec(dir_fd=DirFD(rposix.HAVE_UNLINKAT))
 def remove(space, w_path, __kwonly__, dir_fd=DEFAULT_DIR_FD):
@@ -678,7 +709,7 @@
         else:
             dispatch_filename(rposix.unlink)(space, w_path)
     except OSError as e:
-        raise wrap_oserror2(space, e, w_path)
+        raise wrap_oserror2(space, e, w_path, eintr_retry=False)
 
 def _getfullpathname(space, w_path):
     """helper for ntpath.abspath """
@@ -686,13 +717,13 @@
         if space.isinstance_w(w_path, space.w_unicode):
             path = FileEncoder(space, w_path)
             fullpath = rposix.getfullpathname(path)
-            w_fullpath = space.wrap(fullpath)
+            w_fullpath = space.newunicode(fullpath)
         else:
-            path = space.str0_w(w_path)
+            path = space.bytes0_w(w_path)
             fullpath = rposix.getfullpathname(path)
             w_fullpath = space.newbytes(fullpath)
     except OSError as e:
-        raise wrap_oserror2(space, e, w_path)
+        raise wrap_oserror2(space, e, w_path, eintr_retry=False)
     else:
         return w_fullpath
 
@@ -701,7 +732,7 @@
     try:
         cur = os.getcwd()
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     else:
         return space.newbytes(cur)
 
@@ -711,9 +742,9 @@
         try:
             cur = os.getcwdu()
         except OSError as e:
-            raise wrap_oserror(space, e)
+            raise wrap_oserror(space, e, eintr_retry=False)
         else:
-            return space.wrap(cur)
+            return space.newunicode(cur)
 else:
     def getcwd(space):
         """Return the current working directory as a string."""
@@ -728,7 +759,7 @@
         else:
             dispatch_filename(rposix.chdir)(space, w_path)
     except OSError as e:
-        raise wrap_oserror2(space, e, w_path)
+        raise wrap_oserror2(space, e, w_path, eintr_retry=False)
 
 @unwrap_spec(mode=c_int, dir_fd=DirFD(rposix.HAVE_MKDIRAT))
 def mkdir(space, w_path, mode=0o777, __kwonly__=None, dir_fd=DEFAULT_DIR_FD):
@@ -749,7 +780,7 @@
         else:
             dispatch_filename(rposix.mkdir)(space, w_path, mode)
     except OSError as e:
-        raise wrap_oserror2(space, e, w_path)
+        raise wrap_oserror2(space, e, w_path, eintr_retry=False)
 
 @unwrap_spec(dir_fd=DirFD(rposix.HAVE_UNLINKAT))
 def rmdir(space, w_path, __kwonly__, dir_fd=DEFAULT_DIR_FD):
@@ -768,13 +799,13 @@
         else:
             dispatch_filename(rposix.rmdir)(space, w_path)
     except OSError as e:
-        raise wrap_oserror2(space, e, w_path)
+        raise wrap_oserror2(space, e, w_path, eintr_retry=False)
 
 @unwrap_spec(code=c_int)
 def strerror(space, code):
     """Translate an error code to a message string."""
     try:
-        return space.wrap(_strerror(code))
+        return space.newunicode(_strerror(code))
     except ValueError:
         raise oefmt(space.w_ValueError, "strerror() argument out of range")
 
@@ -783,15 +814,15 @@
     try:
         cur = os.getlogin()
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.wrap_fsdecoded(cur)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newfilename(cur)
 
 # ____________________________________________________________
 
 def getstatfields(space):
     # for app_posix.py: export the list of 'st_xxx' names that we know
     # about at RPython level
-    return space.newlist([space.wrap(name) for _, (name, _) in STAT_FIELDS])
+    return space.newlist([space.newtext(name) for _, (name, _) in STAT_FIELDS])
 
 
 class State:
@@ -823,7 +854,7 @@
         for key, value in rwin32._wenviron_items():
             if isinstance(key, str):
                 key = key.upper()
-            space.setitem(w_env, space.wrap(key), space.wrap(value))
+            space.setitem(w_env, space.newtext(key), space.newtext(value))
 
     @unwrap_spec(name=unicode, value=unicode)
     def putenv(space, name, value):
@@ -836,7 +867,7 @@
         try:
             rwin32._wputenv(name, value)
         except OSError as e:
-            raise wrap_oserror(space, e)
+            raise wrap_oserror(space, e, eintr_retry=False)
 else:
     def _convertenviron(space, w_env):
         for key, value in os.environ.items():
@@ -847,7 +878,7 @@
         try:
             dispatch_filename_2(rposix.putenv)(space, w_name, w_value)
         except OSError as e:
-            raise wrap_oserror(space, e)
+            raise wrap_oserror(space, e, eintr_retry=False)
 
     def unsetenv(space, w_name):
         """Delete an environment variable."""
@@ -856,7 +887,7 @@
         except KeyError:
             pass
         except OSError as e:
-            raise wrap_oserror(space, e)
+            raise wrap_oserror(space, e, eintr_retry=False)
 
 
 def listdir(space, w_path=None):
@@ -875,11 +906,11 @@
     if space.is_none(w_path):
         w_path = space.newunicode(u".")
     if space.isinstance_w(w_path, space.w_bytes):
-        dirname = space.str0_w(w_path)
+        dirname = space.bytes0_w(w_path)
         try:
             result = rposix.listdir(dirname)
         except OSError as e:
-            raise wrap_oserror2(space, e, w_path)
+            raise wrap_oserror2(space, e, w_path, eintr_retry=False)
         return space.newlist_bytes(result)
     try:
         path = space.fsencode_w(w_path)
@@ -893,35 +924,35 @@
         try:
             result = rposix.fdlistdir(os.dup(fd))
         except OSError as e:
-            raise wrap_oserror(space, e)
+            raise wrap_oserror(space, e, eintr_retry=False)
     else:
         dirname = FileEncoder(space, w_path)
         try:
             result = rposix.listdir(dirname)
         except OSError as e:
-            raise wrap_oserror2(space, e, w_path)
+            raise wrap_oserror2(space, e, w_path, eintr_retry=False)
     len_result = len(result)
     result_w = [None] * len_result
     for i in range(len_result):
         if _WIN32:
-            result_w[i] = space.wrap(result[i])
+            result_w[i] = space.newunicode(result[i])
         else:
-            result_w[i] = space.wrap_fsdecoded(result[i])
+            result_w[i] = space.newfilename(result[i])
     return space.newlist(result_w)
 
 @unwrap_spec(fd=c_int)
 def get_inheritable(space, fd):
     try:
-        return space.wrap(rposix.get_inheritable(fd))
+        return space.newbool(rposix.get_inheritable(fd))
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 @unwrap_spec(fd=c_int, inheritable=int)
 def set_inheritable(space, fd, inheritable):
     try:
         rposix.set_inheritable(fd, inheritable)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 _pipe_inhcache = rposix.SetNonInheritableCache()
 
@@ -929,19 +960,24 @@
     "Create a pipe.  Returns (read_end, write_end)."
     try:
         fd1, fd2 = rposix.pipe(rposix.O_CLOEXEC or 0)
+    except OSError as e:
+        raise wrap_oserror(space, e, eintr_retry=False)
+    try:
         _pipe_inhcache.set_non_inheritable(fd1)
         _pipe_inhcache.set_non_inheritable(fd2)
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.newtuple([space.wrap(fd1), space.wrap(fd2)])
+        rposix.c_close(fd2)
+        rposix.c_close(fd1)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newtuple([space.newint(fd1), space.newint(fd2)])
 
 @unwrap_spec(flags=c_int)
 def pipe2(space, flags):
     try:
         fd1, fd2 = rposix.pipe2(flags)
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.newtuple([space.wrap(fd1), space.wrap(fd2)])
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newtuple([space.newint(fd1), space.newint(fd2)])
 
 @unwrap_spec(mode=c_int, dir_fd=DirFD(rposix.HAVE_FCHMODAT),
              follow_symlinks=bool)
@@ -966,11 +1002,12 @@
     if not rposix.HAVE_FCHMODAT:
         if not follow_symlinks:
             raise argument_unavailable(space, "chmod", "follow_symlinks")
-        try:
-            dispatch_filename(rposix.chmod)(space, w_path, mode)
-            return
-        except OSError as e:
-            raise wrap_oserror2(space, e, w_path)
+        while True:
+            try:
+                dispatch_filename(rposix.chmod)(space, w_path, mode)
+                return
+            except OSError as e:
+                wrap_oserror2(space, e, w_path, eintr_retry=True)
 
     try:
         path = space.fsencode_w(w_path)
@@ -979,16 +1016,25 @@
             raise oefmt(space.w_TypeError,
                 "argument should be string, bytes or integer, not %T", w_path)
         fd = unwrap_fd(space, w_path)
-        _chmod_fd(space, fd, mode)
-    else:
+        # NB. in CPython 3.5.2, os.chmod(fd) propagates EINTR to app-level,
+        # but os.fchmod(fd) retries automatically.  This might be fixed in
+        # more recent CPythons.
+        while True:
+            try:
+                os.fchmod(fd, mode)
+                return
+            except OSError as e:
+                wrap_oserror(space, e, eintr_retry=True)
+    while True:
         try:
             _chmod_path(path, mode, dir_fd, follow_symlinks)
+            break
         except OSError as e:
             if not follow_symlinks and e.errno in (ENOTSUP, EOPNOTSUPP):
                 # fchmodat() doesn't actually implement follow_symlinks=False
                 # so raise NotImplementedError in this case
                 raise argument_unavailable(space, "chmod", "follow_symlinks")
-            raise wrap_oserror2(space, e, w_path)
+            wrap_oserror2(space, e, w_path, eintr_retry=True)
 
 def _chmod_path(path, mode, dir_fd, follow_symlinks):
     if dir_fd != DEFAULT_DIR_FD or not follow_symlinks:
@@ -996,19 +1042,17 @@
     else:
         rposix.chmod(path, mode)
 
-def _chmod_fd(space, fd, mode):
-    try:
-        os.fchmod(fd, mode)
-    except OSError as e:
-        raise wrap_oserror(space, e)
-
-
 @unwrap_spec(fd=c_int, mode=c_int)
 def fchmod(space, fd, mode):
     """\
     Change the access permissions of the file given by file descriptor fd.
     """
-    _chmod_fd(space, fd, mode)
+    while True:
+        try:
+            os.fchmod(fd, mode)
+            break
+        except OSError as e:
+            wrap_oserror(space, e, eintr_retry=True)
 
 @unwrap_spec(src_dir_fd=DirFD(rposix.HAVE_RENAMEAT),
         dst_dir_fd=DirFD(rposix.HAVE_RENAMEAT))
@@ -1032,7 +1076,8 @@
         else:
             dispatch_filename_2(rposix.rename)(space, w_src, w_dst)
     except OSError as e:
-        raise wrap_oserror2(space, e, w_filename=w_src, w_filename2=w_dst)
+        raise wrap_oserror2(space, e, w_filename=w_src, w_filename2=w_dst,
+                            eintr_retry=False)
 
 @unwrap_spec(src_dir_fd=DirFD(rposix.HAVE_RENAMEAT),
         dst_dir_fd=DirFD(rposix.HAVE_RENAMEAT))
@@ -1056,7 +1101,8 @@
         else:
             dispatch_filename_2(rposix.replace)(space, w_src, w_dst)
     except OSError as e:
-        raise wrap_oserror2(space, e, w_filename=w_src, w_filename2=w_dst)
+        raise wrap_oserror2(space, e, w_filename=w_src, w_filename2=w_dst,
+                            eintr_retry=False)
 
 @unwrap_spec(mode=c_int, dir_fd=DirFD(rposix.HAVE_MKFIFOAT))
 def mkfifo(space, w_path, mode=0666, __kwonly__=None, dir_fd=DEFAULT_DIR_FD):
@@ -1068,14 +1114,18 @@
   and path should be relative; path will then be relative to that directory.
 dir_fd may not be implemented on your platform.
   If it is unavailable, using it will raise a NotImplementedError."""
-    try:
-        if rposix.HAVE_MKFIFOAT and dir_fd != DEFAULT_DIR_FD:
-            path = space.fsencode_w(w_path)
-            rposix.mkfifoat(path, mode, dir_fd)
-        else:
-            dispatch_filename(rposix.mkfifo)(space, w_path, mode)
-    except OSError as e:
-        raise wrap_oserror2(space, e, w_path)
+    # CPython 3.5.2: why does os.mkfifo() retry automatically if it
+    # gets EINTR, but not os.mkdir()?
+    while True:
+        try:
+            if rposix.HAVE_MKFIFOAT and dir_fd != DEFAULT_DIR_FD:
+                path = space.fsencode_w(w_path)
+                rposix.mkfifoat(path, mode, dir_fd)
+            else:
+                dispatch_filename(rposix.mkfifo)(space, w_path, mode)
+            break
+        except OSError as e:
+            wrap_oserror2(space, e, w_path, eintr_retry=True)
 
 @unwrap_spec(mode=c_int, device=c_int, dir_fd=DirFD(rposix.HAVE_MKNODAT))
 def mknod(space, w_path, mode=0600, device=0,
@@ -1093,28 +1143,30 @@
   and path should be relative; path will then be relative to that directory.
 dir_fd may not be implemented on your platform.
   If it is unavailable, using it will raise a NotImplementedError."""
-    try:
-        if rposix.HAVE_MKNODAT and dir_fd != DEFAULT_DIR_FD:
-            fname = space.fsencode_w(w_path)
-            rposix.mknodat(fname, mode, device, dir_fd)
-        else:
-            dispatch_filename(rposix.mknod)(space, w_path, mode, device)
-    except OSError as e:
-        raise wrap_oserror2(space, e, w_path)
+    while True:
+        try:
+            if rposix.HAVE_MKNODAT and dir_fd != DEFAULT_DIR_FD:
+                fname = space.fsencode_w(w_path)
+                rposix.mknodat(fname, mode, device, dir_fd)
+            else:
+                dispatch_filename(rposix.mknod)(space, w_path, mode, device)
+            break
+        except OSError as e:
+            wrap_oserror2(space, e, w_path, eintr_retry=True)
 
 @unwrap_spec(mask=c_int)
 def umask(space, mask):
     "Set the current numeric umask and return the previous umask."
     prevmask = os.umask(mask)
-    return space.wrap(prevmask)
+    return space.newint(prevmask)
 
 def getpid(space):
     "Return the current process id."
     try:
         pid = os.getpid()
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.wrap(pid)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newint(pid)
 
 @unwrap_spec(pid=c_int, signal=c_int)
 def kill(space, pid, signal):
@@ -1122,7 +1174,7 @@
     try:
         rposix.kill(pid, signal)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 @unwrap_spec(pgid=c_int, signal=c_int)
 def killpg(space, pgid, signal):
@@ -1130,7 +1182,7 @@
     try:
         os.killpg(pgid, signal)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 def abort(space):
     """Abort the interpreter immediately.  This 'dumps core' or otherwise fails
@@ -1139,11 +1191,9 @@
     rposix.kill(os.getpid(), signal.SIGABRT)
 
 @unwrap_spec(
-    src='fsencode', dst='fsencode',  # <- simpler: link() is never on Windows
     src_dir_fd=DirFD(rposix.HAVE_LINKAT), dst_dir_fd=DirFD(rposix.HAVE_LINKAT),
     follow_symlinks=bool)
-def link(
-        space, src, dst, __kwonly__,
+def link(space, w_src, w_dst, __kwonly__,
         src_dir_fd=DEFAULT_DIR_FD, dst_dir_fd=DEFAULT_DIR_FD,
         follow_symlinks=True):
     """\
@@ -1160,6 +1210,8 @@
 src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on your
   platform.  If they are unavailable, using them will raise a
   NotImplementedError."""
+    src = space.fsencode_w(w_src)
+    dst = space.fsencode_w(w_dst)
     try:
         if (rposix.HAVE_LINKAT and
             (src_dir_fd != DEFAULT_DIR_FD or dst_dir_fd != DEFAULT_DIR_FD
@@ -1168,7 +1220,8 @@
         else:
             rposix.link(src, dst)
     except OSError as e:
-        raise wrap_oserror(space, e, filename=src, filename2=dst)
+        raise wrap_oserror2(space, e, w_filename=w_src, w_filename2=w_dst,
+                            eintr_retry=False)
 
 
 @unwrap_spec(dir_fd=DirFD(rposix.HAVE_SYMLINKAT))
@@ -1195,7 +1248,8 @@
         else:
             dispatch_filename_2(rposix.symlink)(space, w_src, w_dst)
     except OSError as e:
-        raise wrap_oserror2(space, e, w_filename=w_src, w_filename2=w_dst)
+        raise wrap_oserror2(space, e, w_filename=w_src, w_filename2=w_dst,
+                            eintr_retry=False)
 
 
 @unwrap_spec(
@@ -1216,7 +1270,7 @@
         else:
             result = call_rposix(rposix.readlink, path)
     except OSError as e:
-        raise wrap_oserror2(space, e, path.w_path)
+        raise wrap_oserror2(space, e, path.w_path, eintr_retry=False)
     w_result = space.newbytes(result)
     if space.isinstance_w(path.w_path, space.w_unicode):
         return space.fsdecode(w_result)
@@ -1264,7 +1318,7 @@
         except:
             # Don't clobber the OSError if the fork failed
             pass
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     if pid == 0:
         run_fork_hooks('child', space)
     else:
@@ -1273,22 +1327,27 @@
 
 def fork(space):
     pid, irrelevant = _run_forking_function(space, "F")
-    return space.wrap(pid)
+    return space.newint(pid)
 
 def openpty(space):
     "Open a pseudo-terminal, returning open fd's for both master and slave 
end."
+    master_fd = slave_fd = -1
     try:
         master_fd, slave_fd = os.openpty()
         rposix.set_inheritable(master_fd, False)
         rposix.set_inheritable(slave_fd, False)
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.newtuple([space.wrap(master_fd), space.wrap(slave_fd)])
+        if master_fd >= 0:
+            rposix.c_close(master_fd)
+        if slave_fd >= 0:
+            rposix.c_close(slave_fd)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newtuple([space.newint(master_fd), space.newint(slave_fd)])
 
 def forkpty(space):
     pid, master_fd = _run_forking_function(space, "P")
-    return space.newtuple([space.wrap(pid),
-                           space.wrap(master_fd)])
+    return space.newtuple([space.newint(pid),
+                           space.newint(master_fd)])
 
 @unwrap_spec(pid=c_int, options=c_int)
 def waitpid(space, pid, options):
@@ -1296,11 +1355,15 @@
 
     Wait for completion of a given child process.
     """
-    try:
-        pid, status = os.waitpid(pid, options)
-    except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.newtuple([space.wrap(pid), space.wrap(status)])
+    while True:
+        try:
+            pid, status = os.waitpid(pid, options)
+            break
+        except OSError as e:
+            wrap_oserror(space, e, eintr_retry=True)
+    return space.newtuple([space.newint(pid), space.newint(status)])
+
+# missing: waitid()
 
 @unwrap_spec(status=c_int)
 def _exit(space, status):
@@ -1329,7 +1392,7 @@
     try:
         os.execv(command, args)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 
 def _env2interp(space, w_env):
@@ -1374,12 +1437,12 @@
         try:
             rposix.fexecve(fd, args, env)
         except OSError as e:
-            raise wrap_oserror(space, e)
+            raise wrap_oserror(space, e, eintr_retry=False)
     else:
         try:
             os.execve(path, args, env)
         except OSError as e:
-            raise wrap_oserror(space, e)
+            raise wrap_oserror(space, e, eintr_retry=False)
 
 @unwrap_spec(mode=int, path='fsencode')
 def spawnv(space, mode, path, w_argv):
@@ -1387,8 +1450,8 @@
     try:
         ret = os.spawnv(mode, path, args)
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.wrap(ret)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newint(ret)
 
 @unwrap_spec(mode=int, path='fsencode')
 def spawnve(space, mode, path, w_argv, w_env):
@@ -1397,8 +1460,8 @@
     try:
         ret = os.spawnve(mode, path, args, env)
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.wrap(ret)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newint(ret)
 
 
 @unwrap_spec(
@@ -1505,7 +1568,7 @@
         #    something is wrong with the file, when it also
         #    could be the time stamp that gives a problem. */
         # so we use wrap_oserror() instead of wrap_oserror2() here
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 @specialize.arg(1)
 def do_utimes(space, func, arg, utime):
@@ -1522,7 +1585,7 @@
             func(arg, (atime, mtime))
     except OSError as e:
         # see comment above: don't use wrap_oserror2()
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 @specialize.argtype(1)
 def _dispatch_utime(path, times):
@@ -1549,7 +1612,7 @@
         return time, 0
 
 def convert_ns(space, w_ns_time):
-    w_billion = space.wrap(1000000000)
+    w_billion = space.newint(1000000000)
     w_res = space.divmod(w_ns_time, w_billion)
     res_w = space.fixedview(w_res)
     time_int = space.int_w(res_w[0])
@@ -1565,12 +1628,12 @@
     try:
         r = os.uname()
     except OSError as e:
-        raise wrap_oserror(space, e)
-    l_w = [space.wrap_fsdecoded(i)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    l_w = [space.newfilename(i)
            for i in [r[0], r[1], r[2], r[3], r[4]]]
     w_tuple = space.newtuple(l_w)
     w_uname_result = space.getattr(space.getbuiltinmodule(os.name),
-                                   space.wrap('uname_result'))
+                                   space.newtext('uname_result'))
     return space.call_function(w_uname_result, w_tuple)
 
 def getuid(space):
@@ -1589,7 +1652,7 @@
     try:
         os.setuid(uid)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 @unwrap_spec(euid=c_uid_t)
 def seteuid(space, euid):
@@ -1600,7 +1663,7 @@
     try:
         os.seteuid(euid)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 @unwrap_spec(gid=c_gid_t)
 def setgid(space, gid):
@@ -1611,7 +1674,7 @@
     try:
         os.setgid(gid)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 @unwrap_spec(egid=c_gid_t)
 def setegid(space, egid):
@@ -1622,18 +1685,18 @@
     try:
         os.setegid(egid)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
-@unwrap_spec(path='fsencode')
-def chroot(space, path):
+def chroot(space, w_path):
     """ chroot(path)
 
     Change root directory to path.
     """
+    path = space.fsencode_w(w_path)
     try:
         os.chroot(path)
     except OSError as e:
-        raise wrap_oserror(space, e, path)
+        raise wrap_oserror2(space, e, w_path, eintr_retry=False)
     return space.w_None
 
 def getgid(space):
@@ -1665,7 +1728,7 @@
     try:
         list = os.getgroups()
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     return space.newlist([wrap_gid(space, e) for e in list])
 
 def setgroups(space, w_groups):
@@ -1679,9 +1742,9 @@
     try:
         os.setgroups(list[:])
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
-@unwrap_spec(username=str, gid=c_gid_t)
+@unwrap_spec(username='text', gid=c_gid_t)
 def initgroups(space, username, gid):
     """ initgroups(username, gid) -> None
 
@@ -1692,14 +1755,14 @@
     try:
         os.initgroups(username, gid)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 def getpgrp(space):
     """ getpgrp() -> pgrp
 
     Return the current process group id.
     """
-    return space.wrap(os.getpgrp())
+    return space.newint(os.getpgrp())
 
 def setpgrp(space):
     """ setpgrp()
@@ -1709,7 +1772,7 @@
     try:
         os.setpgrp()
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     return space.w_None
 
 def getppid(space):
@@ -1717,7 +1780,7 @@
 
     Return the parent's process id.
     """
-    return space.wrap(os.getppid())
+    return space.newint(os.getppid())
 
 @unwrap_spec(pid=c_int)
 def getpgid(space, pid):
@@ -1728,8 +1791,8 @@
     try:
         pgid = os.getpgid(pid)
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.wrap(pgid)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newint(pgid)
 
 @unwrap_spec(pid=c_int, pgrp=c_int)
 def setpgid(space, pid, pgrp):
@@ -1740,7 +1803,7 @@
     try:
         os.setpgid(pid, pgrp)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     return space.w_None
 
 @unwrap_spec(ruid=c_uid_t, euid=c_uid_t)
@@ -1752,7 +1815,7 @@
     try:
         os.setreuid(ruid, euid)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 @unwrap_spec(rgid=c_gid_t, egid=c_gid_t)
 def setregid(space, rgid, egid):
@@ -1763,7 +1826,7 @@
     try:
         os.setregid(rgid, egid)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 @unwrap_spec(pid=c_int)
 def getsid(space, pid):
@@ -1774,8 +1837,8 @@
     try:
         sid = os.getsid(pid)
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.wrap(sid)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newint(sid)
 
 def setsid(space):
     """ setsid()
@@ -1785,7 +1848,7 @@
     try:
         os.setsid()
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     return space.w_None
 
 @unwrap_spec(fd=c_int)
@@ -1797,8 +1860,8 @@
     try:
         pgid = os.tcgetpgrp(fd)
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.wrap(pgid)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newint(pgid)
 
 @unwrap_spec(fd=c_int, pgid=c_gid_t)
 def tcsetpgrp(space, fd, pgid):
@@ -1809,7 +1872,7 @@
     try:
         os.tcsetpgrp(fd, pgid)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 def getresuid(space):
     """ getresuid() -> (ruid, euid, suid)
@@ -1819,7 +1882,7 @@
     try:
         (ruid, euid, suid) = os.getresuid()
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     return space.newtuple([wrap_uid(space, ruid),
                            wrap_uid(space, euid),
                            wrap_uid(space, suid)])
@@ -1832,7 +1895,7 @@
     try:
         (rgid, egid, sgid) = os.getresgid()
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     return space.newtuple([wrap_gid(space, rgid),
                            wrap_gid(space, egid),
                            wrap_gid(space, sgid)])
@@ -1846,7 +1909,7 @@
     try:
         os.setresuid(ruid, euid, suid)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 @unwrap_spec(rgid=c_gid_t, egid=c_gid_t, sgid=c_gid_t)
 def setresgid(space, rgid, egid, sgid):
@@ -1857,13 +1920,36 @@
     try:
         os.setresgid(rgid, egid, sgid)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
+
+@unwrap_spec(which=int, who=int)
+def getpriority(space, which, who):
+    """ getpriority(which, who) -> int
+
+    Get program scheduling priority.
+    """
+    try:
+        returned_priority = rposix.getpriority(which, who)
+    except OSError as e:
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newint(returned_priority)
+
+@unwrap_spec(which=int, who=int, priority=int)
+def setpriority(space, which, who, priority):
+    """ setpriority(which, who, priority)
+
+    Set program scheduling priority.
+    """
+    try:
+        rposix.setpriority(which, who, priority)
+    except OSError as e:
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 def declare_new_w_star(name):
     if name in ('WEXITSTATUS', 'WSTOPSIG', 'WTERMSIG'):
         @unwrap_spec(status=c_int)
         def WSTAR(space, status):
-            return space.wrap(getattr(os, name)(status))
+            return space.newint(getattr(os, name)(status))
     else:
         @unwrap_spec(status=c_int)
         def WSTAR(space, status):
@@ -1881,16 +1967,16 @@
 @unwrap_spec(fd=c_int)
 def ttyname(space, fd):
     try:
-        return space.wrap_fsdecoded(os.ttyname(fd))
+        return space.newfilename(os.ttyname(fd))
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 
 def confname_w(space, w_name, namespace):
     # XXX slightly non-nice, reuses the sysconf of the underlying os module
     if space.isinstance_w(w_name, space.w_unicode):
         try:
-            num = namespace[space.str_w(w_name)]
+            num = namespace[space.text_w(w_name)]
         except KeyError:
             raise oefmt(space.w_ValueError, "unrecognized configuration name")
     else:
@@ -1902,8 +1988,8 @@
     try:
         res = os.sysconf(num)
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.wrap(res)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newint(res)
 
 @unwrap_spec(fd=c_int)
 def fpathconf(space, fd, w_name):
@@ -1911,8 +1997,8 @@
     try:
         res = os.fpathconf(fd, num)
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.wrap(res)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newint(res)
 
 @unwrap_spec(path=path_or_fd(allow_fd=hasattr(os, 'fpathconf')))
 def pathconf(space, path, w_name):
@@ -1921,21 +2007,21 @@
         try:
             res = os.fpathconf(path.as_fd, num)
         except OSError as e:
-            raise wrap_oserror(space, e)
+            raise wrap_oserror(space, e, eintr_retry=False)
     else:
         try:
             res = os.pathconf(path.as_bytes, num)
         except OSError as e:
-            raise wrap_oserror2(space, e, path.w_path)
-    return space.wrap(res)
+            raise wrap_oserror2(space, e, path.w_path, eintr_retry=False)
+    return space.newint(res)
 
 def confstr(space, w_name):
     num = confname_w(space, w_name, os.confstr_names)
     try:
         res = os.confstr(num)
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.wrap(res)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newtext(res)
 
 @unwrap_spec(
     uid=c_uid_t, gid=c_gid_t,
@@ -1975,11 +2061,16 @@
         if not follow_symlinks:
             raise oefmt(space.w_ValueError,
                 "chown: cannnot use fd and follow_symlinks together")
-        try:
-            os.fchown(fd, uid, gid)
-        except OSError as e:
-            raise wrap_oserror(space, e)
-    else:
+        # NB. in CPython 3.5.2, os.chown(fd) propagates EINTR to app-level,
+        # but os.fchown(fd) retries automatically.  This might be fixed in
+        # more recent CPythons.
+        while True:
+            try:
+                os.fchown(fd, uid, gid)
+                return
+            except OSError as e:
+                wrap_oserror(space, e, eintr_retry=True)
+    while True:
         # String case
         try:
             if (rposix.HAVE_LCHOWN and
@@ -1992,21 +2083,23 @@
                 assert follow_symlinks
                 assert dir_fd == DEFAULT_DIR_FD
                 os.chown(path, uid, gid)
+            break
         except OSError as e:
-            raise wrap_oserror2(space, e, w_path)
+            wrap_oserror2(space, e, w_path, eintr_retry=True)
 
 
-@unwrap_spec(path='fsencode', uid=c_uid_t, gid=c_gid_t)
-def lchown(space, path, uid, gid):
+@unwrap_spec(uid=c_uid_t, gid=c_gid_t)
+def lchown(space, w_path, uid, gid):
     """lchown(path, uid, gid)
 
 Change the owner and group id of path to the numeric uid and gid.
 This function will not follow symbolic links.
 Equivalent to os.chown(path, uid, gid, follow_symlinks=False)."""
+    path = space.fsencode_w(w_path)
     try:
         os.lchown(path, uid, gid)
     except OSError as e:
-        raise wrap_oserror(space, e, path)
+        raise wrap_oserror2(space, e, w_path, eintr_retry=False)
 
 @unwrap_spec(uid=c_uid_t, gid=c_gid_t)
 def fchown(space, w_fd, uid, gid):
@@ -2015,34 +2108,36 @@
 Change the owner and group id of the file given by file descriptor
 fd to the numeric uid and gid.  Equivalent to os.chown(fd, uid, gid)."""
     fd = space.c_filedescriptor_w(w_fd)
-    try:
-        os.fchown(fd, uid, gid)
-    except OSError as e:
-        raise wrap_oserror(space, e)
+    while True:
+        try:
+            os.fchown(fd, uid, gid)
+            break
+        except OSError as e:
+            wrap_oserror(space, e, eintr_retry=True)
 
 def getloadavg(space):
     try:
         load = os.getloadavg()
     except OSError:
         raise oefmt(space.w_OSError, "Load averages are unobtainable")
-    return space.newtuple([space.wrap(load[0]),
-                           space.wrap(load[1]),
-                           space.wrap(load[2])])
+    return space.newtuple([space.newfloat(load[0]),
+                           space.newfloat(load[1]),
+                           space.newfloat(load[2])])
 
 @unwrap_spec(major=c_int, minor=c_int)
 def makedev(space, major, minor):
     result = os.makedev(major, minor)
-    return space.wrap(result)
+    return space.newint(result)
 
 @unwrap_spec(device="c_uint")
 def major(space, device):
     result = os.major(intmask(device))
-    return space.wrap(result)
+    return space.newint(result)
 
 @unwrap_spec(device="c_uint")
 def minor(space, device):
     result = os.minor(intmask(device))
-    return space.wrap(result)
+    return space.newint(result)
 
 @unwrap_spec(increment=c_int)
 def nice(space, increment):
@@ -2051,8 +2146,14 @@
     try:
         res = os.nice(increment)
     except OSError as e:
-        raise wrap_oserror(space, e)
-    return space.wrap(res)
+        raise wrap_oserror(space, e, eintr_retry=False)
+    return space.newint(res)
+
+class SigCheck:
+    pass
+_sigcheck = SigCheck()
+def _signal_checker():
+    _sigcheck.space.getexecutioncontext().checksignals()
 
 @unwrap_spec(size=int)
 def urandom(space, size):
@@ -2062,16 +2163,22 @@
     """
     context = get(space).random_context
     try:
-        return space.newbytes(rurandom.urandom(context, size))
+        # urandom() takes a final argument that should be a regular function,
+        # not a bound method like 'getexecutioncontext().checksignals'.
+        # Otherwise, we can't use it from several independent places.
+        _sigcheck.space = space
+        return space.newbytes(rurandom.urandom(context, n, _signal_checker))
     except OSError as e:
-        raise wrap_oserror(space, e)
+        # 'rurandom' should catch and retry internally if it gets EINTR
+        # (at least in os.read(), which is probably enough in practice)
+        raise wrap_oserror(space, e, eintr_retry=False)
 
 def ctermid(space):
     """ctermid() -> string
 
     Return the name of the controlling terminal for this process.
     """
-    return space.wrap_fsdecoded(os.ctermid())
+    return space.newfilename(os.ctermid())
 
 @unwrap_spec(fd=c_int)
 def device_encoding(space, fd):
@@ -2084,14 +2191,14 @@
         return space.w_None
     if _WIN32:
         if fd == 0:
-            return space.wrap('cp%d' % rwin32.GetConsoleCP())
+            return space.newtext('cp%d' % rwin32.GetConsoleCP())
         if fd in (1, 2):
-            return space.wrap('cp%d' % rwin32.GetConsoleOutputCP())
+            return space.newtext('cp%d' % rwin32.GetConsoleOutputCP())
     from rpython.rlib import rlocale
     if rlocale.HAVE_LANGINFO:
         codeset = rlocale.nl_langinfo(rlocale.CODESET)
         if codeset:
-            return space.wrap(codeset)
+            return space.newtext(codeset)
     return space.w_None
 
 if _WIN32:
@@ -2102,10 +2209,10 @@
         try:
             info = nt._getfileinformation(fd)
         except OSError as e:
-            raise wrap_oserror(space, e)
-        return space.newtuple([space.wrap(info[0]),
-                               space.wrap(info[1]),
-                               space.wrap(info[2])])
+            raise wrap_oserror(space, e, eintr_retry=False)
+        return space.newtuple([space.newint(info[0]),
+                               space.newint(info[1]),
+                               space.newint(info[2])])
 
     def _getfinalpathname(space, w_path):
         path = space.unicode_w(w_path)
@@ -2113,10 +2220,10 @@
             result = nt._getfinalpathname(path)
         except nt.LLNotImplemented as e:
             raise OperationError(space.w_NotImplementedError,
-                                 space.wrap(e.msg))
+                                 space.newtext(e.msg))
         except OSError as e:
-            raise wrap_oserror2(space, e, w_path)
-        return space.wrap(result)
+            raise wrap_oserror2(space, e, w_path, eintr_retry=False)
+        return space.newunicode(result)
 
 
 def chflags():
@@ -2219,20 +2326,20 @@
             success = rwin32.GetConsoleScreenBufferInfo(handle, buffer_info)
             if not success:
                 raise rwin32.lastSavedWindowsError()
-            w_columns = space.wrap(r_int(buffer_info.c_srWindow.c_Right) - 
r_int(buffer_info.c_srWindow.c_Left) + 1)
-            w_lines = space.wrap(r_int(buffer_info.c_srWindow.c_Bottom) - 
r_int(buffer_info.c_srWindow.c_Top) + 1)
+            w_columns = space.newint(r_int(buffer_info.c_srWindow.c_Right) - 
r_int(buffer_info.c_srWindow.c_Left) + 1)
+            w_lines = space.newint(r_int(buffer_info.c_srWindow.c_Bottom) - 
r_int(buffer_info.c_srWindow.c_Top) + 1)
     else:
         with lltype.scoped_alloc(rposix.WINSIZE) as winsize:
             failed = rposix.c_ioctl_voidp(fd, rposix.TIOCGWINSZ, winsize)
             if failed:
                 raise exception_from_saved_errno(space, space.w_OSError)
 
-            w_columns = space.wrap(r_uint(winsize.c_ws_col))
-            w_lines = space.wrap(r_uint(winsize.c_ws_row))
+            w_columns = space.newint(r_uint(winsize.c_ws_col))
+            w_lines = space.newint(r_uint(winsize.c_ws_row))
 
     w_tuple = space.newtuple([w_columns, w_lines])
     w_terminal_size = space.getattr(space.getbuiltinmodule(os.name),
-                                    space.wrap('terminal_size'))
+                                    space.newtext('terminal_size'))
 
     return space.call_function(w_terminal_size, w_tuple)
 
@@ -2240,14 +2347,14 @@
     count = rposix.cpu_count()
     if count <= 0:
         return space.w_None
-    return space.wrap(count)
+    return space.newint(count)
 
 @unwrap_spec(fd=c_int)
 def get_blocking(space, fd):
     try:
         flags = rposix.get_status_flags(fd)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
     return space.newbool(flags & rposix.O_NONBLOCK == 0)
 
 @unwrap_spec(fd=c_int, blocking=int)
@@ -2260,4 +2367,4 @@
             flags |= rposix.O_NONBLOCK
         rposix.set_status_flags(fd, flags)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, eintr_retry=False)
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
@@ -7,6 +7,7 @@
 
 from rpython.tool.udir import udir
 from pypy.tool.pytest.objspace import gettestobjspace
+from pypy.interpreter.gateway import interp2app
 from rpython.translator.c.test.test_extfunc import need_sparse_files
 from rpython.rlib import rposix
 
@@ -201,6 +202,8 @@
         excinfo = raises(TypeError, self.posix.stat, 2.)
         assert "should be string, bytes or integer, not float" in 
str(excinfo.value)
         raises(ValueError, self.posix.stat, -1)
+        raises(ValueError, self.posix.stat, b"abc\x00def")
+        raises(ValueError, self.posix.stat, u"abc\x00def")
 
     if hasattr(__import__(os.name), "statvfs"):
         def test_statvfs(self):
@@ -359,11 +362,11 @@
         pdir = self.pdir + '/file1'
         posix = self.posix
 
-        assert posix.access(pdir, posix.R_OK)
-        assert posix.access(pdir, posix.W_OK)
+        assert posix.access(pdir, posix.R_OK) is True
+        assert posix.access(pdir, posix.W_OK) is True
         import sys
         if sys.platform != "win32":
-            assert not posix.access(pdir, posix.X_OK)
+            assert posix.access(pdir, posix.X_OK) is False
 
     def test_times(self):
         """
@@ -839,7 +842,7 @@
             fd = os.open(self.path2 + 'test_os_pread', os.O_RDWR | os.O_CREAT)
             try:
                 os.write(fd, b'test')
-                os.lseek(fd, 0, os.SEEK_SET)
+                os.lseek(fd, 0, 0)
                 assert os.pread(fd, 2, 1) == b'es'
                 assert os.read(fd, 2) == b'te'
             finally:
@@ -851,7 +854,7 @@
             fd = os.open(self.path2 + 'test_os_pwrite', os.O_RDWR | os.O_CREAT)
             try:
                 os.write(fd, b'test')
-                os.lseek(fd, 0, os.SEEK_SET)
+                os.lseek(fd, 0, 0)
                 os.pwrite(fd, b'xx', 1)
                 assert os.read(fd, 4) == b'txxt'
             finally:
@@ -874,6 +877,31 @@
         assert st.st_size == 10000000000
     test_largefile.need_sparse_files = True
 
+    if hasattr(rposix, 'getpriority'):
+        def test_os_set_get_priority(self):
+            posix, os = self.posix, self.os
+            childpid = os.fork()
+            if childpid == 0:
+                # in the child (avoids changing the priority of the parent
+                # process)
+                orig_priority = posix.getpriority(posix.PRIO_PROCESS,
+                                                  os.getpid())
+                orig_grp_priority = posix.getpriority(posix.PRIO_PGRP,
+                                                      os.getpgrp())
+                posix.setpriority(posix.PRIO_PROCESS, os.getpid(),
+                                  orig_priority + 1)
+                new_priority = posix.getpriority(posix.PRIO_PROCESS,
+                                                 os.getpid())
+                assert new_priority == orig_priority + 1
+                assert posix.getpriority(posix.PRIO_PGRP, os.getpgrp()) == (
+                    orig_grp_priority)
+                os._exit(0)    # ok
+            #
+            pid1, status1 = os.waitpid(childpid, 0)
+            assert pid1 == childpid
+            assert os.WIFEXITED(status1)
+            assert os.WEXITSTATUS(status1) == 0   # else, test failure
+
     def test_write_buffer(self):
         os = self.posix
         fd = os.open(self.path2 + 'test_write_buffer',
@@ -1090,6 +1118,10 @@
             posix.truncate(dest, 1)
             assert 1 == posix.stat(dest).st_size
 
+            # File does not exist
+            e = raises(OSError, posix.truncate, dest + '-DOESNT-EXIST', 0)
+            assert e.value.filename == dest + '-DOESNT-EXIST'
+
     try:
         os.getlogin()
     except (AttributeError, OSError):
@@ -1389,3 +1421,40 @@
         if os.name == 'posix':
             assert os.open in os.supports_dir_fd  # openat()
 
+
+class AppTestPep475Retry:
+    spaceconfig = {'usemodules': USEMODULES}
+
+    def setup_class(cls):
+        if os.name != 'posix':
+            skip("xxx tests are posix-only")
+        if cls.runappdirect:
+            skip("xxx does not work with -A")
+
+        def fd_data_after_delay(space):
+            g = os.popen("sleep 5 && echo hello", "r")
+            cls._keepalive_g = g
+            return space.wrap(g.fileno())
+
+        cls.w_posix = space.appexec([], GET_POSIX)
+        cls.w_fd_data_after_delay = cls.space.wrap(
+            interp2app(fd_data_after_delay))
+
+    def test_pep475_retry_read(self):
+        import _signal as signal
+        signalled = []
+
+        def foo(*args):
+            signalled.append("ALARM")
+
+        signal.signal(signal.SIGALRM, foo)
+        try:
+            fd = self.fd_data_after_delay()
+            signal.alarm(1)
+            got = self.posix.read(fd, 100)
+            self.posix.close(fd)
+        finally:
+            signal.signal(signal.SIGALRM, signal.SIG_DFL)
+
+        assert signalled != []
+        assert got.startswith(b'h')
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -234,6 +234,7 @@
         _ptyh = 'pty.h'
     includes = ['unistd.h',  'sys/types.h', 'sys/wait.h',
                 'utime.h', 'sys/time.h', 'sys/times.h',
+                'sys/resource.h',
                 'grp.h', 'dirent.h', 'sys/stat.h', 'fcntl.h',
                 'signal.h', 'sys/utsname.h', _ptyh]
     if sys.platform.startswith('freebsd'):
@@ -249,6 +250,9 @@
     SEEK_SET = rffi_platform.DefinedConstantInteger('SEEK_SET')
     SEEK_CUR = rffi_platform.DefinedConstantInteger('SEEK_CUR')
     SEEK_END = rffi_platform.DefinedConstantInteger('SEEK_END')
+    PRIO_PROCESS = rffi_platform.DefinedConstantInteger('PRIO_PROCESS')
+    PRIO_PGRP = rffi_platform.DefinedConstantInteger('PRIO_PGRP')
+    PRIO_USER = rffi_platform.DefinedConstantInteger('PRIO_USER')
     O_NONBLOCK = rffi_platform.DefinedConstantInteger('O_NONBLOCK')
     OFF_T = rffi_platform.SimpleType('off_t')
     OFF_T_SIZE = rffi_platform.SizeOf('off_t')
@@ -262,6 +266,7 @@
     if not _WIN32:
         UID_T = rffi_platform.SimpleType('uid_t', rffi.UINT)
         GID_T = rffi_platform.SimpleType('gid_t', rffi.UINT)
+        ID_T = rffi_platform.SimpleType('id_t', rffi.UINT)
         TIOCGWINSZ = rffi_platform.DefinedConstantInteger('TIOCGWINSZ')
 
         TMS = rffi_platform.Struct(
@@ -1760,6 +1765,22 @@
     def setresgid(rgid, egid, sgid):
         handle_posix_error('setresgid', c_setresgid(rgid, egid, sgid))
 
+    c_getpriority = external('getpriority', [rffi.INT, ID_T], rffi.INT,
+                             save_err=rffi.RFFI_FULL_ERRNO_ZERO)
+    c_setpriority = external('setpriority', [rffi.INT, ID_T, rffi.INT],
+                             rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO)
+
+    def getpriority(which, who):
+        result = widen(c_getpriority(which, who))
+        error = get_saved_errno()
+        if error != 0:
+            raise OSError(error, 'getpriority failed')
+        return result
+
+    def setpriority(which, who, prio):
+        handle_posix_error('setpriority', c_setpriority(which, who, prio))
+
+
 #___________________________________________________________________
 
 c_chroot = external('chroot', [rffi.CCHARP], rffi.INT,
@@ -1804,25 +1825,23 @@
     finally:
         lltype.free(l_utsbuf, flavor='raw')
 
-# These are actually macros on some/most systems
-c_makedev = external('makedev', [rffi.INT, rffi.INT], rffi.INT)
-c_major = external('major', [rffi.INT], rffi.INT)
-c_minor = external('minor', [rffi.INT], rffi.INT)
+if sys.platform != 'win32':
+    # These are actually macros on some/most systems
+    c_makedev = external('makedev', [rffi.INT, rffi.INT], rffi.INT, macro=True)
+    c_major = external('major', [rffi.INT], rffi.INT, macro=True)
+    c_minor = external('minor', [rffi.INT], rffi.INT, macro=True)
 
-@replace_os_function('makedev')
-@jit.dont_look_inside
-def makedev(maj, min):
-    return c_makedev(maj, min)
+    @replace_os_function('makedev')
+    def makedev(maj, min):
+        return c_makedev(maj, min)
 
-@replace_os_function('major')
-@jit.dont_look_inside
-def major(dev):
-    return c_major(dev)
+    @replace_os_function('major')
+    def major(dev):
+        return c_major(dev)
 
-@replace_os_function('minor')
-@jit.dont_look_inside
-def minor(dev):
-    return c_minor(dev)
+    @replace_os_function('minor')
+    def minor(dev):
+        return c_minor(dev)
 
 #___________________________________________________________________
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to