Author: Ronan Lamy <ronan.l...@gmail.com> Branch: py3k Changeset: r83542:c0fce2e85c79 Date: 2016-04-06 16:06 +0100 http://bitbucket.org/pypy/pypy/changeset/c0fce2e85c79/
Log: hg merge default diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -35,3 +35,8 @@ .. branch: win32-lib-name +.. branch: remove-frame-forcing-in-executioncontext + +.. branch: rposix-for-3 + +Wrap more POSIX functions in `rpython.rlib.rposix`. diff --git a/pypy/module/__pypy__/test/test_magic.py b/pypy/module/__pypy__/test/test_magic.py --- a/pypy/module/__pypy__/test/test_magic.py +++ b/pypy/module/__pypy__/test/test_magic.py @@ -57,7 +57,7 @@ assert _promote(1) == 1 assert _promote(1.1) == 1.1 assert _promote("abc") == "abc" - assert _promote(u"abc") == u"abc" + raises(TypeError, _promote, u"abc") l = [] assert _promote(l) is l class A(object): diff --git a/pypy/module/_vmprof/test/test__vmprof.py b/pypy/module/_vmprof/test/test__vmprof.py --- a/pypy/module/_vmprof/test/test__vmprof.py +++ b/pypy/module/_vmprof/test/test__vmprof.py @@ -14,7 +14,7 @@ tmpfile2 = open(self.tmpfilename2, 'wb') tmpfileno2 = tmpfile2.fileno() - import struct, sys + import struct, sys, gc WORD = struct.calcsize('l') @@ -46,6 +46,8 @@ return count import _vmprof + gc.collect() # try to make the weakref list deterministic + gc.collect() # by freeing all dead code objects _vmprof.enable(tmpfileno, 0.01) _vmprof.disable() s = open(self.tmpfilename, 'rb').read() @@ -60,6 +62,8 @@ pass """, d) + gc.collect() + gc.collect() _vmprof.enable(tmpfileno2, 0.01) exec_("""def foo2(): diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -146,7 +146,7 @@ MODEL_X86_64: ['floats', 'singlefloats'], MODEL_X86_64_SSE4: ['floats', 'singlefloats'], MODEL_ARM: ['floats', 'singlefloats', 'longlong'], - MODEL_PPC_64: [], # we don't even have PPC directory, so no + MODEL_PPC_64: ['floats'], MODEL_S390_64: ['floats'], }[backend_name] diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1592,43 +1592,70 @@ resbox = self._do_jit_force_virtual(allboxes, descr, pc) if resbox is not None: return resbox + + # 1. preparation self.metainterp.vable_and_vrefs_before_residual_call() + + # 2. actually do the call now (we'll have cases later): the + # result is stored into 'c_result' for now, which is a Const + metainterp = self.metainterp tp = descr.get_normalized_result_type() - resbox = NOT_HANDLED - opnum = -1 - if effectinfo.oopspecindex == effectinfo.OS_LIBFFI_CALL: - opnum = rop.call_may_force_for_descr(descr) - resbox = self.metainterp.direct_libffi_call(allboxes, descr, - tp) - if resbox is NOT_HANDLED: - if effectinfo.is_call_release_gil(): - opnum = rop.call_release_gil_for_descr(descr) - resbox = self.metainterp.direct_call_release_gil(allboxes, - descr, tp) - elif tp == 'i': - resbox = self.metainterp.execute_and_record_varargs( - rop.CALL_MAY_FORCE_I, allboxes, descr=descr) - elif tp == 'r': - resbox = self.metainterp.execute_and_record_varargs( - rop.CALL_MAY_FORCE_R, allboxes, descr=descr) - elif tp == 'f': - resbox = self.metainterp.execute_and_record_varargs( - rop.CALL_MAY_FORCE_F, allboxes, descr=descr) - elif tp == 'v': - self.metainterp.execute_and_record_varargs( - rop.CALL_MAY_FORCE_N, allboxes, descr=descr) - resbox = None - else: - assert False - if opnum == -1: - opnum = rop.call_may_force_for_descr(descr) - cut_pos = self.metainterp.vrefs_after_residual_call( - self.metainterp._last_op, opnum, allboxes, descr, cut_pos) - vablebox = None + if tp == 'i': + opnum1 = rop.CALL_MAY_FORCE_I + value = executor.execute_varargs(metainterp.cpu, metainterp, + opnum1, allboxes, descr) + c_result = ConstInt(value) + elif tp == 'r': + opnum1 = rop.CALL_MAY_FORCE_R + value = executor.execute_varargs(metainterp.cpu, metainterp, + opnum1, allboxes, descr) + c_result = ConstPtr(value) + elif tp == 'f': + opnum1 = rop.CALL_MAY_FORCE_F + value = executor.execute_varargs(metainterp.cpu, metainterp, + opnum1, allboxes, descr) + c_result = ConstFloat(value) + elif tp == 'v': + opnum1 = rop.CALL_MAY_FORCE_N + executor.execute_varargs(metainterp.cpu, metainterp, + opnum1, allboxes, descr) + c_result = None + else: + assert False + + # 3. after this call, check the vrefs. If any have been + # forced by the call, then we record in the trace a + # VIRTUAL_REF_FINISH---before we record any CALL + self.metainterp.vrefs_after_residual_call() + + # 4. figure out what kind of CALL we need to record + # from the effectinfo and the 'assembler_call' flag if assembler_call: vablebox, resbox = self.metainterp.direct_assembler_call( - self.metainterp._last_op, allboxes, descr, assembler_call_jd, cut_pos) - if resbox and resbox.type != 'v': + allboxes, descr, assembler_call_jd) + else: + vablebox = None + resbox = None + if effectinfo.oopspecindex == effectinfo.OS_LIBFFI_CALL: + resbox = self.metainterp.direct_libffi_call(allboxes, descr) + # ^^^ may return None to mean "can't handle it myself" + if resbox is None: + if effectinfo.is_call_release_gil(): + resbox = self.metainterp.direct_call_release_gil( + allboxes, descr) + else: + resbox = self.metainterp.direct_call_may_force( + allboxes, descr) + + # 5. invalidate the heapcache based on the CALL_MAY_FORCE + # operation executed above in step 2 + self.metainterp.heapcache.invalidate_caches(opnum1, descr, allboxes) + + # 6. put 'c_result' back into the recorded operation + if resbox.type == 'v': + resbox = None # for void calls, must return None below + else: + resbox.copy_value_from(c_result) self.make_result_of_lastop(resbox) self.metainterp.vable_after_residual_call(funcbox) self.metainterp.generate_guard(rop.GUARD_NOT_FORCED, None) @@ -2170,7 +2197,6 @@ profiler.count_ops(opnum, Counters.RECORDED_OPS) self.heapcache.invalidate_caches(opnum, descr, argboxes) op = self.history.record(opnum, argboxes, resvalue, descr) - self._last_op = op self.attach_debug_info(op) if op.type != 'v': return op @@ -2781,7 +2807,7 @@ force_token], None, descr=vinfo.vable_token_descr) - def vrefs_after_residual_call(self, op, opnum, arglist, descr, cut_pos): + def vrefs_after_residual_call(self): vrefinfo = self.staticdata.virtualref_info for i in range(0, len(self.virtualref_boxes), 2): vrefbox = self.virtualref_boxes[i+1] @@ -2791,9 +2817,7 @@ # during this CALL_MAY_FORCE. Mark this fact by # generating a VIRTUAL_REF_FINISH on it and replacing # it by ConstPtr(NULL). - cut_pos = self.stop_tracking_virtualref(i, op, opnum, arglist, - descr, cut_pos) - return cut_pos + self.stop_tracking_virtualref(i) def vable_after_residual_call(self, funcbox): vinfo = self.jitdriver_sd.virtualizable_info @@ -2817,19 +2841,14 @@ # have the eventual exception raised (this is normally done # after the call to vable_after_residual_call()). - def stop_tracking_virtualref(self, i, op, opnum, arglist, descr, cut_pos): + def stop_tracking_virtualref(self, i): virtualbox = self.virtualref_boxes[i] vrefbox = self.virtualref_boxes[i+1] - # record VIRTUAL_REF_FINISH just before the current CALL_MAY_FORCE - self.history.cut(cut_pos) # pop the CALL - self.history.record_nospec(rop.VIRTUAL_REF_FINISH, - [vrefbox, virtualbox], None) - cut_pos = self.history.get_trace_position() - newop = self.history.record_nospec(opnum, arglist, descr) - op.set_position(newop.get_position()) - # mark by replacing it with ConstPtr(NULL) + # record VIRTUAL_REF_FINISH here, which is before the actual + # CALL_xxx is recorded + self.history.record(rop.VIRTUAL_REF_FINISH, [vrefbox, virtualbox], None) + # mark this situation by replacing the vrefbox with ConstPtr(NULL) self.virtualref_boxes[i+1] = self.cpu.ts.CONST_NULL - return cut_pos def handle_possible_exception(self): if self.last_exc_value: @@ -3026,24 +3045,26 @@ newop.copy_value_from(op) return newop - def direct_assembler_call(self, op, arglist, descr, targetjitdriver_sd, cut_pos): - """ Generate a direct call to assembler for portal entry point, - patching the CALL_MAY_FORCE that occurred just now. + def direct_call_may_force(self, argboxes, calldescr): + """ Common case: record in the history a CALL_MAY_FORCE with + 'c_result' as the result of that call. (The actual call has + already been done.) """ - self.history.cut(cut_pos) + opnum = rop.call_may_force_for_descr(calldescr) + return self.history.record_nospec(opnum, argboxes, calldescr) + + def direct_assembler_call(self, arglist, calldescr, targetjitdriver_sd): + """ Record in the history a direct call to assembler for portal + entry point. + """ num_green_args = targetjitdriver_sd.num_green_args greenargs = arglist[1:num_green_args+1] args = arglist[num_green_args+1:] assert len(args) == targetjitdriver_sd.num_red_args warmrunnerstate = targetjitdriver_sd.warmstate token = warmrunnerstate.get_assembler_token(greenargs) - opnum = OpHelpers.call_assembler_for_descr(descr) - oldop = op + opnum = OpHelpers.call_assembler_for_descr(calldescr) op = self.history.record_nospec(opnum, args, descr=token) - if opnum == rop.CALL_ASSEMBLER_N: - op = None - else: - op.copy_value_from(oldop) # # To fix an obscure issue, make sure the vable stays alive # longer than the CALL_ASSEMBLER operation. We do it by @@ -3054,7 +3075,7 @@ else: return None, op - def direct_libffi_call(self, argboxes, orig_calldescr, tp): + def direct_libffi_call(self, argboxes, orig_calldescr): """Generate a direct call to C code using jit_ffi_call() """ # an 'assert' that constant-folds away the rest of this function @@ -3067,7 +3088,7 @@ # box_cif_description = argboxes[1] if not isinstance(box_cif_description, ConstInt): - return NOT_HANDLED + return None # cannot be handled by direct_libffi_call() cif_description = box_cif_description.getint() cif_description = llmemory.cast_int_to_adr(cif_description) cif_description = llmemory.cast_adr_to_ptr(cif_description, @@ -3075,7 +3096,7 @@ extrainfo = orig_calldescr.get_extra_info() calldescr = self.cpu.calldescrof_dynamic(cif_description, extrainfo) if calldescr is None: - return NOT_HANDLED + return None # cannot be handled by direct_libffi_call() # box_exchange_buffer = argboxes[3] arg_boxes = [] @@ -3106,68 +3127,25 @@ # (that is, errno and SetLastError/GetLastError on Windows) # Note these flags match the ones in clibffi.ll_callback c_saveall = ConstInt(rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO) - if tp == 'i': - value = executor.execute_varargs(self.cpu, self, - rop.CALL_MAY_FORCE_I, - argboxes, orig_calldescr) - box_result = self.history.record( - rop.CALL_RELEASE_GIL_I, [c_saveall, argboxes[2]] + arg_boxes, - value, descr=calldescr) - elif tp == 'f': - value = executor.execute_varargs(self.cpu, self, - rop.CALL_MAY_FORCE_F, - argboxes, orig_calldescr) - box_result = self.history.record( - rop.CALL_RELEASE_GIL_F, [c_saveall, argboxes[2]] + arg_boxes, - value, descr=calldescr) - elif tp == 'v': - executor.execute_varargs(self.cpu, self, - rop.CALL_MAY_FORCE_N, - argboxes, orig_calldescr) - self.history.record( - rop.CALL_RELEASE_GIL_N, [c_saveall, argboxes[2]] + arg_boxes, - None, descr=calldescr) - box_result = None - else: - assert False - # + opnum = rop.call_release_gil_for_descr(orig_calldescr) + assert opnum == rop.call_release_gil_for_descr(calldescr) + return self.history.record_nospec(opnum, + [c_saveall, argboxes[2]] + arg_boxes, + calldescr) # note that the result is written back to the exchange_buffer by the # following operation, which should be a raw_store - return box_result - - def direct_call_release_gil(self, argboxes, calldescr, tp): + + def direct_call_release_gil(self, argboxes, calldescr): + if not we_are_translated(): # for llgraph + calldescr._original_func_ = argboxes[0].getint() effectinfo = calldescr.get_extra_info() realfuncaddr, saveerr = effectinfo.call_release_gil_target funcbox = ConstInt(heaptracker.adr2int(realfuncaddr)) savebox = ConstInt(saveerr) - if tp == 'i': - value = executor.execute_varargs(self.cpu, self, - rop.CALL_MAY_FORCE_I, - argboxes, calldescr) - resbox = self.history.record(rop.CALL_RELEASE_GIL_I, - [savebox, funcbox] + argboxes[1:], - value, calldescr) - elif tp == 'f': - value = executor.execute_varargs(self.cpu, self, - rop.CALL_MAY_FORCE_F, - argboxes, calldescr) - resbox = self.history.record(rop.CALL_RELEASE_GIL_F, - [savebox, funcbox] + argboxes[1:], - value, calldescr) - elif tp == 'v': - executor.execute_varargs(self.cpu, self, - rop.CALL_MAY_FORCE_N, - argboxes, calldescr) - self.history.record(rop.CALL_RELEASE_GIL_N, - [savebox, funcbox] + argboxes[1:], - None, calldescr) - resbox = None - else: - assert False, "no CALL_RELEASE_GIL_R" - - if not we_are_translated(): # for llgraph - calldescr._original_func_ = argboxes[0].getint() - return resbox + opnum = rop.call_release_gil_for_descr(calldescr) + return self.history.record_nospec(opnum, + [savebox, funcbox] + argboxes[1:], + calldescr) def do_not_in_trace_call(self, allboxes, descr): self.clear_exception() @@ -3187,8 +3165,6 @@ """Raised after we mutated metainterp.framestack, in order to force it to reload the current top-of-stack frame that gets interpreted.""" -NOT_HANDLED = history.CONST_FALSE - # ____________________________________________________________ def _get_opimpl_method(name, argcodes): diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py --- a/rpython/rlib/rposix.py +++ b/rpython/rlib/rposix.py @@ -22,21 +22,6 @@ from rpython.rlib import rwin32 from rpython.rlib.rwin32file import make_win32_traits -class CConfig: - _compilation_info_ = ExternalCompilationInfo( - includes=['sys/stat.h', - 'unistd.h', - 'fcntl.h'], - ) - for _name in """fchdir fchmod fchmodat fchown fchownat fexecve fdopendir - fpathconf fstat fstatat fstatvfs ftruncate futimens futimes - futimesat linkat lchflags lchmod lchown lstat lutimes - mkdirat mkfifoat mknodat openat readlinkat renameat - symlinkat unlinkat utimensat""".split(): - locals()['HAVE_%s' % _name.upper()] = rffi_platform.Has(_name) -cConfig = rffi_platform.configure(CConfig) -globals().update(cConfig) - class CConstantErrno(CConstant): # these accessors are used when calling get_errno() or set_errno() @@ -618,14 +603,44 @@ config = rffi_platform.configure(CConfig) DIRENT = config['DIRENT'] DIRENTP = lltype.Ptr(DIRENT) - c_opendir = external('opendir', [rffi.CCHARP], DIRP, - save_err=rffi.RFFI_SAVE_ERRNO) + c_opendir = external('opendir', + [rffi.CCHARP], DIRP, save_err=rffi.RFFI_SAVE_ERRNO) + c_fdopendir = external('fdopendir', + [rffi.INT], DIRP, save_err=rffi.RFFI_SAVE_ERRNO) # XXX macro=True is hack to make sure we get the correct kind of # dirent struct (which depends on defines) c_readdir = external('readdir', [DIRP], DIRENTP, macro=True, save_err=rffi.RFFI_FULL_ERRNO_ZERO) c_closedir = external('closedir', [DIRP], rffi.INT) +def _listdir(dirp): + result = [] + while True: + direntp = c_readdir(dirp) + if not direntp: + error = get_saved_errno() + break + namep = rffi.cast(rffi.CCHARP, direntp.c_d_name) + name = rffi.charp2str(namep) + if name != '.' and name != '..': + result.append(name) + c_closedir(dirp) + if error: + raise OSError(error, "readdir failed") + return result + +def fdlistdir(dirfd): + """ + Like listdir(), except that the directory is specified as an open + file descriptor. + + Note: fdlistdir() closes the file descriptor. + """ + dirp = c_fdopendir(dirfd) + if not dirp: + raise OSError(get_saved_errno(), "opendir failed") + return _listdir(dirp) + @replace_os_function('listdir') @specialize.argtype(0) def listdir(path): @@ -634,20 +649,7 @@ dirp = c_opendir(path) if not dirp: raise OSError(get_saved_errno(), "opendir failed") - result = [] - while True: - direntp = c_readdir(dirp) - if not direntp: - error = get_saved_errno() - break - namep = rffi.cast(rffi.CCHARP, direntp.c_d_name) - name = rffi.charp2str(namep) - if name != '.' and name != '..': - result.append(name) - c_closedir(dirp) - if error: - raise OSError(error, "readdir failed") - return result + return _listdir(dirp) else: # _WIN32 case traits = _preferred_traits(path) win32traits = make_win32_traits(traits) @@ -1739,3 +1741,259 @@ def getcontroller(self): from rpython.rlib.rposix_environ import OsEnvironController return OsEnvironController() + + +# ____________________________________________________________ +# Support for f... and ...at families of POSIX functions + +class CConfig: + _compilation_info_ = ExternalCompilationInfo( + includes=['sys/stat.h', + 'unistd.h', + 'fcntl.h'], + ) + for _name in """faccessat fchdir fchmod fchmodat fchown fchownat fexecve + fdopendir fpathconf fstat fstatat fstatvfs ftruncate + futimens futimes futimesat linkat chflags lchflags lchmod lchown + lstat lutimes mkdirat mkfifoat mknodat openat readlinkat renameat + symlinkat unlinkat utimensat""".split(): + locals()['HAVE_%s' % _name.upper()] = rffi_platform.Has(_name) +cConfig = rffi_platform.configure(CConfig) +globals().update(cConfig) + +if not _WIN32: + class CConfig: + _compilation_info_ = ExternalCompilationInfo( + includes=['sys/stat.h', + 'unistd.h', + 'fcntl.h'], + ) + AT_FDCWD = rffi_platform.DefinedConstantInteger('AT_FDCWD') + AT_SYMLINK_NOFOLLOW = rffi_platform.DefinedConstantInteger('AT_SYMLINK_NOFOLLOW') + AT_EACCESS = rffi_platform.DefinedConstantInteger('AT_EACCESS') + AT_REMOVEDIR = rffi_platform.DefinedConstantInteger('AT_REMOVEDIR') + AT_EMPTY_PATH = rffi_platform.DefinedConstantInteger('AT_EMPTY_PATH') + UTIME_NOW = rffi_platform.DefinedConstantInteger('UTIME_NOW') + UTIME_OMIT = rffi_platform.DefinedConstantInteger('UTIME_OMIT') + TIMESPEC = rffi_platform.Struct('struct timespec', [ + ('tv_sec', rffi.TIME_T), + ('tv_nsec', rffi.LONG)]) + + cConfig = rffi_platform.configure(CConfig) + globals().update(cConfig) + TIMESPEC2P = rffi.CArrayPtr(TIMESPEC) + +if HAVE_FACCESSAT: + c_faccessat = external('faccessat', + [rffi.INT, rffi.CCHARP, rffi.INT, rffi.INT], rffi.INT) + + def faccessat(pathname, mode, dir_fd=AT_FDCWD, + effective_ids=False, follow_symlinks=True): + """Thin wrapper around faccessat(2) with an interface simlar to + Python3's os.access(). + """ + flags = 0 + if not follow_symlinks: + flags |= AT_SYMLINK_NOFOLLOW + if effective_ids: + flags |= AT_EACCESS + error = c_faccessat(dir_fd, pathname, mode, flags) + return error == 0 + +if HAVE_FCHMODAT: + c_fchmodat = external('fchmodat', + [rffi.INT, rffi.CCHARP, rffi.INT, rffi.INT], rffi.INT, + save_err=rffi.RFFI_SAVE_ERRNO,) + + def fchmodat(path, mode, dir_fd=AT_FDCWD, follow_symlinks=True): + if follow_symlinks: + flag = 0 + else: + flag = AT_SYMLINK_NOFOLLOW + error = c_fchmodat(dir_fd, path, mode, flag) + handle_posix_error('fchmodat', error) + +if HAVE_FCHOWNAT: + c_fchownat = external('fchownat', + [rffi.INT, rffi.CCHARP, rffi.INT, rffi.INT, rffi.INT], rffi.INT, + save_err=rffi.RFFI_SAVE_ERRNO,) + + def fchownat(path, owner, group, dir_fd=AT_FDCWD, + follow_symlinks=True, empty_path=False): + flag = 0 + if not follow_symlinks: + flag |= AT_SYMLINK_NOFOLLOW + if empty_path: + flag |= AT_EMPTY_PATH + error = c_fchownat(dir_fd, path, owner, group, flag) + handle_posix_error('fchownat', error) + +if HAVE_FEXECVE: + c_fexecve = external('fexecve', + [rffi.INT, rffi.CCHARPP, rffi.CCHARPP], rffi.INT, + save_err=rffi.RFFI_SAVE_ERRNO) + + def fexecve(fd, args, env): + envstrs = [] + for item in env.iteritems(): + envstr = "%s=%s" % item + envstrs.append(envstr) + + # This list conversion already takes care of NUL bytes. + l_args = rffi.ll_liststr2charpp(args) + l_env = rffi.ll_liststr2charpp(envstrs) + c_fexecve(fd, l_args, l_env) + + rffi.free_charpp(l_env) + rffi.free_charpp(l_args) + raise OSError(get_saved_errno(), "execve failed") + +if HAVE_LINKAT: + c_linkat = external('linkat', + [rffi.INT, rffi.CCHARP, rffi.INT, rffi.CCHARP, rffi.INT], rffi.INT) + + def linkat(src, dst, src_dir_fd=AT_FDCWD, dst_dir_fd=AT_FDCWD, + follow_symlinks=True): + """Thin wrapper around linkat(2) with an interface similar to + Python3's os.link() + """ + if follow_symlinks: + flag = 0 + else: + flag = AT_SYMLINK_NOFOLLOW + error = c_linkat(src_dir_fd, src, dst_dir_fd, dst, flag) + handle_posix_error('linkat', error) + +if HAVE_FUTIMENS: + c_futimens = external('futimens', [rffi.INT, TIMESPEC2P], rffi.INT) + + def futimens(fd, atime, atime_ns, mtime, mtime_ns): + l_times = lltype.malloc(TIMESPEC2P.TO, 2, flavor='raw') + rffi.setintfield(l_times[0], 'c_tv_sec', atime) + rffi.setintfield(l_times[0], 'c_tv_nsec', atime_ns) + rffi.setintfield(l_times[1], 'c_tv_sec', mtime) + rffi.setintfield(l_times[1], 'c_tv_nsec', mtime_ns) + error = c_futimens(fd, l_times) + lltype.free(l_times, flavor='raw') + handle_posix_error('futimens', error) + +if HAVE_UTIMENSAT: + c_utimensat = external('utimensat', + [rffi.INT, rffi.CCHARP, TIMESPEC2P, rffi.INT], rffi.INT) + + def utimensat(pathname, atime, atime_ns, mtime, mtime_ns, + dir_fd=AT_FDCWD, follow_symlinks=True): + """Wrapper around utimensat(2) + + To set access time to the current time, pass atime_ns=UTIME_NOW, + atime is then ignored. + + To set modification time to the current time, pass mtime_ns=UTIME_NOW, + mtime is then ignored. + """ + l_times = lltype.malloc(TIMESPEC2P.TO, 2, flavor='raw') + rffi.setintfield(l_times[0], 'c_tv_sec', atime) + rffi.setintfield(l_times[0], 'c_tv_nsec', atime_ns) + rffi.setintfield(l_times[1], 'c_tv_sec', mtime) + rffi.setintfield(l_times[1], 'c_tv_nsec', mtime_ns) + if follow_symlinks: + flag = 0 + else: + flag = AT_SYMLINK_NOFOLLOW + error = c_utimensat(dir_fd, pathname, l_times, flag) + lltype.free(l_times, flavor='raw') + handle_posix_error('utimensat', error) + +if HAVE_MKDIRAT: + c_mkdirat = external('mkdirat', + [rffi.INT, rffi.CCHARP, rffi.INT], rffi.INT, + save_err=rffi.RFFI_SAVE_ERRNO) + + def mkdirat(pathname, mode, dir_fd=AT_FDCWD): + error = c_mkdirat(dir_fd, pathname, mode) + handle_posix_error('mkdirat', error) + +if HAVE_UNLINKAT: + c_unlinkat = external('unlinkat', + [rffi.INT, rffi.CCHARP, rffi.INT], rffi.INT, + save_err=rffi.RFFI_SAVE_ERRNO) + + def unlinkat(pathname, dir_fd=AT_FDCWD, removedir=False): + flag = AT_REMOVEDIR if removedir else 0 + error = c_unlinkat(dir_fd, pathname, flag) + handle_posix_error('unlinkat', error) + +if HAVE_READLINKAT: + c_readlinkat = external( + 'readlinkat', + [rffi.INT, rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T], rffi.SSIZE_T, + save_err=rffi.RFFI_SAVE_ERRNO) + + def readlinkat(pathname, dir_fd=AT_FDCWD): + pathname = _as_bytes0(pathname) + bufsize = 1023 + while True: + buf = lltype.malloc(rffi.CCHARP.TO, bufsize, flavor='raw') + res = widen(c_readlinkat(dir_fd, pathname, buf, bufsize)) + if res < 0: + lltype.free(buf, flavor='raw') + error = get_saved_errno() # failed + raise OSError(error, "readlinkat failed") + elif res < bufsize: + break # ok + else: + # buf too small, try again with a larger buffer + lltype.free(buf, flavor='raw') + bufsize *= 4 + # convert the result to a string + result = rffi.charp2strn(buf, res) + lltype.free(buf, flavor='raw') + return result + +if HAVE_RENAMEAT: + c_renameat = external( + 'renameat', + [rffi.INT, rffi.CCHARP, rffi.INT, rffi.CCHARP], rffi.INT, + save_err=rffi.RFFI_SAVE_ERRNO) + + def renameat(src, dst, src_dir_fd=AT_FDCWD, dst_dir_fd=AT_FDCWD): + error = c_renameat(src_dir_fd, src, dst_dir_fd, dst) + handle_posix_error('renameat', error) + + +if HAVE_SYMLINKAT: + c_symlinkat = external('symlinkat', + [rffi.CCHARP, rffi.INT, rffi.CCHARP], rffi.INT, + save_err=rffi.RFFI_SAVE_ERRNO) + + def symlinkat(src, dst, dir_fd=AT_FDCWD): + error = c_symlinkat(src, dir_fd, dst) + handle_posix_error('symlinkat', error) + +if HAVE_OPENAT: + c_openat = external('openat', + [rffi.INT, rffi.CCHARP, rffi.INT, rffi.MODE_T], rffi.INT, + save_err=rffi.RFFI_SAVE_ERRNO) + + @enforceargs(s_Str0, int, int, int, typecheck=False) + def openat(path, flags, mode, dir_fd=AT_FDCWD): + fd = c_openat(dir_fd, path, flags, mode) + return handle_posix_error('open', fd) + +if HAVE_MKFIFOAT: + c_mkfifoat = external('mkfifoat', + [rffi.INT, rffi.CCHARP, rffi.MODE_T], rffi.INT, + save_err=rffi.RFFI_SAVE_ERRNO) + + def mkfifoat(path, mode, dir_fd=AT_FDCWD): + error = c_mkfifoat(dir_fd, path, mode) + handle_posix_error('mkfifoat', error) + +if HAVE_MKNODAT: + c_mknodat = external('mknodat', + [rffi.INT, rffi.CCHARP, rffi.MODE_T, rffi.INT], rffi.INT, + save_err=rffi.RFFI_SAVE_ERRNO) + + def mknodat(path, mode, device, dir_fd=AT_FDCWD): + error = c_mknodat(dir_fd, path, mode, device) + handle_posix_error('mknodat', error) diff --git a/rpython/rlib/rvmprof/cintf.py b/rpython/rlib/rvmprof/cintf.py --- a/rpython/rlib/rvmprof/cintf.py +++ b/rpython/rlib/rvmprof/cintf.py @@ -1,3 +1,4 @@ +import platform as host_platform import py import sys from rpython.tool.udir import udir @@ -28,8 +29,7 @@ def setup(): - from rpython.jit.backend import detect_cpu - if detect_cpu.autodetect().startswith(detect_cpu.MODEL_S390_64): + if host_platform.machine() == 's390x': raise VMProfPlatformUnsupported("rvmprof not supported on" " s390x CPUs for now") compile_extra = ['-DRPYTHON_LL2CTYPES'] diff --git a/rpython/rlib/test/test_rposix.py b/rpython/rlib/test/test_rposix.py --- a/rpython/rlib/test/test_rposix.py +++ b/rpython/rlib/test/test_rposix.py @@ -7,6 +7,12 @@ import errno import py +def rposix_requires(funcname): + return py.test.mark.skipif(not hasattr(rposix, funcname), + reason="Requires rposix.%s()" % funcname) + +win_only = py.test.mark.skipif("os.name != 'nt'") + class TestPosixFunction: def test_access(self): filename = str(udir.join('test_access.txt')) @@ -29,9 +35,8 @@ for value in times: assert isinstance(value, float) + @py.test.mark.skipif("not hasattr(os, 'getlogin')") def test_getlogin(self): - if not hasattr(os, 'getlogin'): - py.test.skip('posix specific function') try: expected = os.getlogin() except OSError, e: @@ -39,9 +44,8 @@ data = rposix.getlogin() assert data == expected + @win_only def test_utimes(self): - if os.name != 'nt': - py.test.skip('Windows specific feature') # Windows support centiseconds def f(fname, t1): os.utime(fname, (t1, t1)) @@ -51,15 +55,12 @@ t1 = 1159195039.25 compile(f, (str, float))(str(fname), t1) assert t1 == os.stat(str(fname)).st_mtime - if sys.version_info < (2, 7): - py.test.skip('requires Python 2.7') t1 = 5000000000.0 compile(f, (str, float))(str(fname), t1) assert t1 == os.stat(str(fname)).st_mtime + @win_only def test__getfullpathname(self): - if os.name != 'nt': - py.test.skip('nt specific function') posix = __import__(os.name) sysdrv = os.getenv('SystemDrive', 'C:') stuff = sysdrv + 'stuff' @@ -99,11 +100,25 @@ def test_mkdir(self): filename = str(udir.join('test_mkdir.dir')) rposix.mkdir(filename, 0) - exc = py.test.raises(OSError, rposix.mkdir, filename, 0) - assert exc.value.errno == errno.EEXIST + with py.test.raises(OSError) as excinfo: + rposix.mkdir(filename, 0) + assert excinfo.value.errno == errno.EEXIST if sys.platform == 'win32': assert exc.type is WindowsError + @rposix_requires('mkdirat') + def test_mkdirat(self): + relpath = 'test_mkdirat.dir' + filename = str(udir.join(relpath)) + dirfd = os.open(os.path.dirname(filename), os.O_RDONLY) + try: + rposix.mkdirat(relpath, 0, dir_fd=dirfd) + with py.test.raises(OSError) as excinfo: + rposix.mkdirat(relpath, 0, dir_fd=dirfd) + assert excinfo.value.errno == errno.EEXIST + finally: + os.close(dirfd) + def test_strerror(self): assert rposix.strerror(2) == os.strerror(2) @@ -116,10 +131,8 @@ os.unlink(filename) + @py.test.mark.skipif("os.name != 'posix'") def test_execve(self): - if os.name != 'posix': - py.test.skip('posix specific function') - EXECVE_ENV = {"foo": "bar", "baz": "quux"} def run_execve(program, args=None, env=None, do_path_lookup=False): @@ -258,11 +271,8 @@ assert rposix.isatty(-1) is False +@py.test.mark.skipif("not hasattr(os, 'ttyname')") class TestOsExpect(ExpectTest): - def setup_class(cls): - if not hasattr(os, 'ttyname'): - py.test.skip("no ttyname") - def test_ttyname(self): def f(): import os @@ -426,9 +436,8 @@ except Exception: pass + @win_only def test_is_valid_fd(self): - if os.name != 'nt': - py.test.skip('relevant for windows only') assert rposix.is_valid_fd(0) == 1 fid = open(str(udir.join('validate_test.txt')), 'w') fd = fid.fileno() @@ -448,6 +457,59 @@ def _get_filename(self): return str(udir.join('test_open_ascii')) + @rposix_requires('openat') + def test_openat(self): + def f(dirfd): + try: + fd = rposix.openat('test_open_ascii', os.O_RDONLY, 0777, dirfd) + try: + text = os.read(fd, 50) + return text + finally: + os.close(fd) + except OSError: + return '' + + dirfd = os.open(os.path.dirname(self.ufilename), os.O_RDONLY) + try: + assert ll_to_string(interpret(f, [dirfd])) == "test" + finally: + os.close(dirfd) + + @rposix_requires('unlinkat') + def test_unlinkat(self): + def f(dirfd): + return rposix.unlinkat('test_open_ascii', dir_fd=dirfd) + + dirfd = os.open(os.path.dirname(self.ufilename), os.O_RDONLY) + try: + interpret(f, [dirfd]) + finally: + os.close(dirfd) + assert not os.path.exists(self.ufilename) + + def test_utimensat(self): + def f(dirfd): + return rposix.utimensat('test_open_ascii', + 0, rposix.UTIME_NOW, 0, rposix.UTIME_NOW, dir_fd=dirfd) + + dirfd = os.open(os.path.dirname(self.ufilename), os.O_RDONLY) + try: + interpret(f, [dirfd]) # does not crash + finally: + os.close(dirfd) + + def test_fchmodat(self): + def f(dirfd): + return rposix.fchmodat('test_open_ascii', 0777, dirfd) + + dirfd = os.open(os.path.dirname(self.ufilename), os.O_RDONLY) + try: + interpret(f, [dirfd]) # does not crash + finally: + os.close(dirfd) + + class TestPosixUnicode(BasePosixUnicodeOrAscii): def _get_filename(self): return (unicode(udir.join('test_open')) + @@ -465,3 +527,30 @@ os.open('/tmp/t', 0, 0) os.open(u'/tmp/t', 0, 0) compile(f, ()) + + +def test_fdlistdir(tmpdir): + tmpdir.join('file').write('text') + dirfd = os.open(str(tmpdir), os.O_RDONLY) + result = rposix.fdlistdir(dirfd) + # Note: fdlistdir() always closes dirfd + assert result == ['file'] + +def test_symlinkat(tmpdir): + tmpdir.join('file').write('text') + dirfd = os.open(str(tmpdir), os.O_RDONLY) + try: + rposix.symlinkat('file', 'link', dir_fd=dirfd) + assert os.readlink(str(tmpdir.join('link'))) == 'file' + finally: + os.close(dirfd) + +def test_renameat(tmpdir): + tmpdir.join('file').write('text') + dirfd = os.open(str(tmpdir), os.O_RDONLY) + try: + rposix.renameat('file', 'file2', src_dir_fd=dirfd, dst_dir_fd=dirfd) + finally: + os.close(dirfd) + assert tmpdir.join('file').check(exists=False) + assert tmpdir.join('file2').check(exists=True) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit