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