Author: fijal
Branch: release-pypy3.5-v5.9.x
Changeset: r93535:42207cd2265c
Date: 2017-12-21 15:53 +0200
http://bitbucket.org/pypy/pypy/changeset/42207cd2265c/

Log:    merge py3.5

diff --git a/extra_tests/requirements.txt b/extra_tests/requirements.txt
--- a/extra_tests/requirements.txt
+++ b/extra_tests/requirements.txt
@@ -1,2 +1,3 @@
 pytest
 hypothesis
+vmprof
diff --git a/extra_tests/test_vmprof_greenlet.py 
b/extra_tests/test_vmprof_greenlet.py
new file mode 100644
--- /dev/null
+++ b/extra_tests/test_vmprof_greenlet.py
@@ -0,0 +1,28 @@
+import time
+import pytest
+import greenlet
+vmprof = pytest.importorskip('vmprof')
+
+def count_samples(filename):
+    stats = vmprof.read_profile(filename)
+    return len(stats.profiles)
+
+def cpuburn(duration):
+    end = time.time() + duration
+    while time.time() < end:
+        pass
+
+def test_sampling_inside_callback(tmpdir):
+    # see also test_sampling_inside_callback inside
+    # pypy/module/_continuation/test/test_stacklet.py
+    #
+    G = greenlet.greenlet(cpuburn)
+    fname = tmpdir.join('log.vmprof')
+    with fname.open('w+b') as f:
+        vmprof.enable(f.fileno(), 1/250.0)
+        G.switch(0.1)
+        vmprof.disable()
+    
+    samples = count_samples(str(fname))
+    # 0.1 seconds at 250Hz should be 25 samples
+    assert 23 < samples < 27
diff --git a/lib-python/2.7/subprocess.py b/lib-python/2.7/subprocess.py
--- a/lib-python/2.7/subprocess.py
+++ b/lib-python/2.7/subprocess.py
@@ -1296,7 +1296,7 @@
                   'copyfile' in caller.f_globals):
         dest_dir = sys.pypy_resolvedirof(target_executable)
         src_dir = sys.pypy_resolvedirof(sys.executable)
-        for libname in ['libpypy-c.so', 'libpypy-c.dylib']:
+        for libname in ['libpypy-c.so', 'libpypy-c.dylib', 'libpypy-c.dll']:
             dest_library = os.path.join(dest_dir, libname)
             src_library = os.path.join(src_dir, libname)
             if os.path.exists(src_library):
diff --git a/lib-python/3/ssl.py b/lib-python/3/ssl.py
--- a/lib-python/3/ssl.py
+++ b/lib-python/3/ssl.py
@@ -140,23 +140,6 @@
 except NameError:
     _SSLv2_IF_EXISTS = None
 
-
-
-
-import os
-class DirEntry:
-    def __init__(self, path, name):
-        self.path = os.path.join(path, name)
-        self.name = name
-    def is_dir(self):
-        return os.path.isdir(self.path)
-def myscandir(path='.'):
-    for name in os.listdir(path):
-        yield DirEntry(path, name)
-os.scandir = myscandir
-
-
-
 if sys.platform == "win32":
     from _ssl import enum_certificates, enum_crls
 
diff --git a/pypy/doc/index-of-release-notes.rst 
b/pypy/doc/index-of-release-notes.rst
--- a/pypy/doc/index-of-release-notes.rst
+++ b/pypy/doc/index-of-release-notes.rst
@@ -6,6 +6,7 @@
 
 .. toctree::
 
+   release-v5.10.0.rst
    release-v5.9.0.rst
    release-v5.8.0.rst
    release-v5.7.1.rst
diff --git a/pypy/doc/release-v5.10.0.rst b/pypy/doc/release-v5.10.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-v5.10.0.rst
@@ -0,0 +1,94 @@
+======================================
+PyPy2.7 and PyPy3.5 v5.10 dual release
+======================================
+
+The PyPy team is proud to release both PyPy2.7 v5.10 (an interpreter supporting
+Python 2.7 syntax), and a final PyPy3.5 v5.10 (an interpreter for Python
+3.5 syntax). The two releases are both based on much the same codebase, thus
+the dual release.
+
+This release is an incremental release with very few new features, the main
+feature being the final PyPy3.5 release that works on linux and OS X with beta
+windows support. It also includes fixes for `vmprof`_ cooperation with 
greenlets.
+
+Compared to 5.9, the 5.10 release contains mostly bugfixes and small 
improvements.
+We have in the pipeline big new features coming for PyPy 6.0 that did not make
+the release cut and should be available within the next couple months.
+
+As always, this release is 100% compatible with the previous one and fixed
+several issues and bugs raised by the growing community of PyPy users.
+As always, we strongly recommend updating.
+
+This release concludes the Mozilla Open Source `grant`_ for having a compatible
+PyPy 3.5 release and we're very grateful for that.  Of course, we will continue
+to improve PyPy 3.5 and probably move to 3.6 during the course of 2018.
+
+You can download the v5.10 releases here:
+
+    http://pypy.org/download.html
+
+We would like to thank our donors for the continued support of the PyPy
+project.
+
+We would also like to thank our contributors and
+encourage new people to join the project. PyPy has many
+layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation
+improvements, tweaking popular `modules`_ to run on pypy, or general `help`_
+with making RPython's JIT even better.
+
+.. _vmprof: http://vmprof.readthedocs.io
+.. _grant: 
https://morepypy.blogspot.com/2016/08/pypy-gets-funding-from-mozilla-for.html
+.. _`PyPy`: index.html
+.. _`RPython`: https://rpython.readthedocs.org
+.. _`modules`: project-ideas.html#make-more-python-modules-pypy-friendly
+.. _`help`: project-ideas.html
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7 and CPython 3.5. It's fast (`PyPy and CPython 2.7.x`_ performance 
comparison)
+due to its integrated tracing JIT compiler.
+
+We also welcome developers of other `dynamic languages`_ to see what RPython
+can do for them.
+
+The PyPy 2.7 release supports: 
+
+  * **x86** machines on most common operating systems
+    (Linux 32/64 bits, Mac OS X 64 bits, Windows 32 bits, OpenBSD, FreeBSD)
+  
+  * newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux,
+  
+  * big- and little-endian variants of **PPC64** running Linux,
+
+  * **s390x** running Linux
+
+.. _`PyPy and CPython 2.7.x`: http://speed.pypy.org
+.. _`dynamic languages`: http://rpython.readthedocs.io/en/latest/examples.html
+
+Changelog
+=========
+
+* improve ssl handling on windows for pypy3 (makes pip work)
+* improve unicode handling in various error reporters
+* fix vmprof cooperation with greenlets
+* fix some things in cpyext
+* test and document the cmp(nan, nan) == 0 behaviour
+* don't crash when calling sleep with inf or nan
+* fix bugs in _io module
+* inspect.isbuiltin() now returns True for functions implemented in C
+* allow the sequences future-import, docstring, future-import for CPython bug 
compatibility
+* Issue #2699: non-ascii messages in warnings
+* posix.lockf
+* fixes for FreeBSD platform
+* add .debug files, so builds contain debugging info, instead of being stripped
+* improvements to cppyy
+* issue #2677 copy pure c PyBuffer_{From,To}Contiguous from cpython
+* issue #2682, split firstword on any whitespace in sqlite3
+* ctypes: allow ptr[0] = foo when ptr is a pointer to struct
+* matplotlib will work with tkagg backend once `matplotlib pr #9356`_ is merged
+* improvements to utf32 surrogate handling
+* cffi version bump to 1.11.2
+
+.. _`matplotlib pr #9356`: https://github.com/matplotlib/matplotlib/pull/9356
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
@@ -2,3 +2,41 @@
 What's new in PyPy3 6.0
 ===========================
 
+.. this is a revision shortly after release-pypy2.7-v5.9.0
+.. startrev:d56dadcef996
+
+
+.. branch: cppyy-packaging
+
+Cleanup and improve cppyy packaging
+
+.. branch: docs-osx-brew-openssl
+
+.. branch: keep-debug-symbols
+
+Add a smartstrip tool, which can optionally keep the debug symbols in a
+separate file, instead of just stripping them away. Use it in packaging
+
+.. branch: bsd-patches
+
+Fix failures on FreeBSD, contributed by David Naylor as patches on the issue
+tracker (issues 2694, 2695, 2696, 2697)
+
+.. branch: run-extra-tests
+
+Run extra_tests/ in buildbot
+
+.. branch: vmprof-0.4.10
+
+Upgrade the _vmprof backend to vmprof 0.4.10
+
+.. branch: fix-vmprof-stacklet-switch
+.. branch: fix-vmprof-stacklet-switch-2
+Fix a vmprof+continulets (i.e. greenelts, eventlet, gevent, ...)
+
+.. branch: win32-vcvars
+
+.. branch: rdict-fast-hash
+
+Make it possible to declare that the hash function of an r_dict is fast in 
RPython.
+
diff --git a/pypy/doc/whatsnew-pypy3-5.10.0.rst 
b/pypy/doc/whatsnew-pypy3-5.10.0.rst
--- a/pypy/doc/whatsnew-pypy3-5.10.0.rst
+++ b/pypy/doc/whatsnew-pypy3-5.10.0.rst
@@ -31,7 +31,7 @@
 Upgrade the _vmprof backend to vmprof 0.4.10
 
 .. branch: fix-vmprof-stacklet-switch
-
+.. branch: fix-vmprof-stacklet-switch-2
 Fix a vmprof+continulets (i.e. greenelts, eventlet, gevent, ...)
 
 .. branch: win32-vcvars
@@ -39,3 +39,4 @@
 .. branch: rdict-fast-hash
 
 Make it possible to declare that the hash function of an r_dict is fast in 
RPython.
+
diff --git a/pypy/module/_continuation/interp_continuation.py 
b/pypy/module/_continuation/interp_continuation.py
--- a/pypy/module/_continuation/interp_continuation.py
+++ b/pypy/module/_continuation/interp_continuation.py
@@ -1,5 +1,6 @@
 from rpython.rlib.rstacklet import StackletThread
 from rpython.rlib import jit
+from rpython.rlib import rvmprof
 from pypy.interpreter.error import OperationError, get_cleared_operation_error
 from pypy.interpreter.error import oefmt
 from pypy.interpreter.executioncontext import ExecutionContext
@@ -241,12 +242,15 @@
     self.h = h
     global_state.clear()
     try:
+        rvmprof.start_sampling()
         frame = self.bottomframe
         w_result = frame.execute_frame()
     except Exception as e:
         global_state.propagate_exception = e
     else:
         global_state.w_value = w_result
+    finally:
+        rvmprof.stop_sampling()
     self.sthread.ec.topframeref = jit.vref_None
     global_state.origin = self
     global_state.destination = self
diff --git a/pypy/module/_continuation/test/test_stacklet.py 
b/pypy/module/_continuation/test/test_stacklet.py
--- a/pypy/module/_continuation/test/test_stacklet.py
+++ b/pypy/module/_continuation/test/test_stacklet.py
@@ -1,7 +1,10 @@
+import pytest
 import os
+from rpython.rlib.rvmprof.test.support import fakevmprof
+from pypy.interpreter.gateway import interp2app
 from pypy.module._continuation.test.support import BaseAppTest
 
-
+@pytest.mark.usefixtures('app_fakevmprof')
 class AppTestStacklet(BaseAppTest):
     def setup_class(cls):
         BaseAppTest.setup_class.im_func(cls)
@@ -34,6 +37,33 @@
                 return res
             return stack
        """)
+        cls.w_appdirect = cls.space.wrap(cls.runappdirect)
+        if cls.runappdirect:
+            # make sure that "self.stack" does not pass the self
+            cls.w_stack = staticmethod(cls.w_stack.im_func)
+
+
+    @pytest.fixture
+    def app_fakevmprof(self, fakevmprof):
+        """
+        This is automaticaly re-initialized for every method: thanks to
+        fakevmprof's finalizer, it checks that we called {start,stop}_sampling
+        the in pairs
+        """
+        w = self.space.wrap
+        i2a = interp2app
+        def is_sampling_enabled(space):
+            return space.wrap(fakevmprof.is_sampling_enabled)
+        self.w_is_sampling_enabled = w(i2a(is_sampling_enabled))
+        #
+        def start_sampling(space):
+            fakevmprof.start_sampling()
+        self.w_start_sampling = w(i2a(start_sampling))
+        #
+        def stop_sampling(space):
+            fakevmprof.stop_sampling()
+        self.w_stop_sampling = w(i2a(stop_sampling))
+
 
     def test_new_empty(self):
         from _continuation import continulet
@@ -797,3 +827,25 @@
         bd50 = continulet(f)
         main.switch(to=bd50)
         print(999)
+
+    def test_sampling_inside_callback(self):
+        if self.appdirect:
+            # see also
+            # extra_tests.test_vmprof_greenlet.test_sampling_inside_callback
+            # for a "translated" version of this test
+            skip("we can't run this until we have _vmprof.is_sampling_enabled")
+        from _continuation import continulet
+        #
+        def my_callback(c1):
+            assert self.is_sampling_enabled()
+            return 42
+        #
+        try:
+            self.start_sampling()
+            assert self.is_sampling_enabled()
+            c = continulet(my_callback)
+            res = c.switch()
+            assert res == 42
+            assert self.is_sampling_enabled()
+        finally:
+            self.stop_sampling()
diff --git a/pypy/module/_continuation/test/test_translated.py 
b/pypy/module/_continuation/test/test_translated.py
--- a/pypy/module/_continuation/test/test_translated.py
+++ b/pypy/module/_continuation/test/test_translated.py
@@ -1,4 +1,5 @@
 import py
+import pytest
 try:
     import _continuation
 except ImportError:
@@ -101,11 +102,7 @@
         particular, we need to ensure that vmprof does not sample the stack in
         the middle of a switch, else we read nonsense.
         """
-        try:
-            import _vmprof
-        except ImportError:
-            py.test.skip("no _vmprof")
-        #
+        _vmprof = pytest.importorskip('_vmprof')
         def switch_forever(c):
             while True:
                 c.switch()
diff --git a/pypy/module/errno/__init__.py b/pypy/module/errno/__init__.py
--- a/pypy/module/errno/__init__.py
+++ b/pypy/module/errno/__init__.py
@@ -1,6 +1,5 @@
-# Package initialisation
 from pypy.interpreter.mixedmodule import MixedModule
-import errno
+from pypy.module.errno.interp_errno import name2code
 
 class Module(MixedModule):
     """This module makes available standard errno system symbols.
@@ -18,9 +17,7 @@
 
     appleveldefs = {}
     interpleveldefs = {"errorcode": "interp_errno.get_errorcode(space)"}
-    
-for name in dir(errno):
-    if name.startswith('__') or name in Module.interpleveldefs:
-        continue
-    Module.interpleveldefs[name] = ("space.newint(%s)" %
-                                    (getattr(errno, name), ))
+
+for name, code in name2code.iteritems():
+    if code is not None:
+        Module.interpleveldefs[name] = ("space.newint(%s)" % code)
diff --git a/pypy/module/errno/interp_errno.py 
b/pypy/module/errno/interp_errno.py
--- a/pypy/module/errno/interp_errno.py
+++ b/pypy/module/errno/interp_errno.py
@@ -1,7 +1,95 @@
-import errno
 from rpython.rlib.objectmodel import not_rpython
+from rpython.rtyper.tool.rffi_platform import DefinedConstantInteger, configure
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+
+# from CPython 3.5
+errors = [
+    "ENODEV", "ENOCSI", "EHOSTUNREACH", "ENOMSG", "EUCLEAN", "EL2NSYNC",
+    "EL2HLT", "ENODATA", "ENOTBLK", "ENOSYS", "EPIPE", "EINVAL", "EOVERFLOW",
+    "EADV", "EINTR", "EUSERS", "ENOTEMPTY", "ENOBUFS", "EPROTO", "EREMOTE",
+    "ENAVAIL", "ECHILD", "ELOOP", "EXDEV", "E2BIG", "ESRCH", "EMSGSIZE",
+    "EAFNOSUPPORT", "EBADR", "EHOSTDOWN", "EPFNOSUPPORT", "ENOPROTOOPT",
+    "EBUSY", "EWOULDBLOCK", "EBADFD", "EDOTDOT", "EISCONN", "ENOANO",
+    "ESHUTDOWN", "ECHRNG", "ELIBBAD", "ENONET", "EBADE", "EBADF", "EMULTIHOP",
+    "EIO", "EUNATCH", "EPROTOTYPE", "ENOSPC", "ENOEXEC", "EALREADY",
+    "ENETDOWN", "ENOTNAM", "EACCES", "ELNRNG", "EILSEQ", "ENOTDIR", "ENOTUNIQ",
+    "EPERM", "EDOM", "EXFULL", "ECONNREFUSED", "EISDIR", "EPROTONOSUPPORT",
+    "EROFS", "EADDRNOTAVAIL", "EIDRM", "ECOMM", "ESRMNT", "EREMOTEIO",
+    "EL3RST", "EBADMSG", "ENFILE", "ELIBMAX", "ESPIPE", "ENOLINK", "ENETRESET",
+    "ETIMEDOUT", "ENOENT", "EEXIST", "EDQUOT", "ENOSTR", "EBADSLT", "EBADRQC",
+    "ELIBACC", "EFAULT", "EFBIG", "EDEADLK", "ENOTCONN", "EDESTADDRREQ",
+    "ELIBSCN", "ENOLCK", "EISNAM", "ECONNABORTED", "ENETUNREACH", "ESTALE",
+    "ENOSR", "ENOMEM", "ENOTSOCK", "ESTRPIPE", "EMLINK", "ERANGE", "ELIBEXEC",
+    "EL3HLT", "ECONNRESET", "EADDRINUSE", "EOPNOTSUPP", "EREMCHG", "EAGAIN",
+    "ENAMETOOLONG", "ENOTTY", "ERESTART", "ESOCKTNOSUPPORT", "ETIME", "EBFONT",
+    "EDEADLOCK", "ETOOMANYREFS", "EMFILE", "ETXTBSY", "EINPROGRESS", "ENXIO",
+    "ENOPKG",]
+
+win_errors = [
+    "WSASY", "WSAEHOSTDOWN", "WSAENETDOWN", "WSAENOTSOCK", "WSAEHOSTUNREACH",
+    "WSAELOOP", "WSAEMFILE", "WSAESTALE", "WSAVERNOTSUPPORTED",
+    "WSAENETUNREACH", "WSAEPROCLIM", "WSAEFAULT", "WSANOTINITIALISED",
+    "WSAEUSERS", "WSAMAKEASYNCREPL", "WSAENOPROTOOPT", "WSAECONNABORTED",
+    "WSAENAMETOOLONG", "WSAENOTEMPTY", "WSAESHUTDOWN", "WSAEAFNOSUPPORT",
+    "WSAETOOMANYREFS", "WSAEACCES", "WSATR", "WSABASEERR", "WSADESCRIPTIO",
+    "WSAEMSGSIZE", "WSAEBADF", "WSAECONNRESET", "WSAGETSELECTERRO",
+    "WSAETIMEDOUT", "WSAENOBUFS", "WSAEDISCON", "WSAEINTR", "WSAEPROTOTYPE",
+    "WSAHOS", "WSAEADDRINUSE", "WSAEADDRNOTAVAIL", "WSAEALREADY",
+    "WSAEPROTONOSUPPORT", "WSASYSNOTREADY", "WSAEWOULDBLOCK",
+    "WSAEPFNOSUPPORT", "WSAEOPNOTSUPP", "WSAEISCONN", "WSAENOTCONN",
+    "WSAEREMOTE", "WSAEINVAL", "WSAEINPROGRESS", "WSAGETSELECTEVEN",
+    "WSAESOCKTNOSUPPORT", "WSAGETASYNCERRO", "WSAMAKESELECTREPL",
+    "WSAGETASYNCBUFLE", "WSAEDESTADDRREQ", "WSAECONNREFUSED", "WSAENETRESET",
+    "WSAN",]
+
+more_errors = [
+    "ENOMEDIUM", "EMEDIUMTYPE", "ECANCELED", "ENOKEY", "EKEYEXPIRED",
+    "EKEYREVOKED", "EKEYREJECTED", "EOWNERDEAD", "ENOTRECOVERABLE", "ERFKILL",
+
+    # Solaris-specific errnos
+    "ECANCELED", "ENOTSUP", "EOWNERDEAD", "ENOTRECOVERABLE", "ELOCKUNMAPPED",
+    "ENOTACTIVE",
+
+    # MacOSX specific errnos
+    "EAUTH", "EBADARCH", "EBADEXEC", "EBADMACHO", "EBADRPC", "EDEVERR",
+    "EFTYPE", "ENEEDAUTH", "ENOATTR", "ENOPOLICY", "EPROCLIM", "EPROCUNAVAIL",
+    "EPROGMISMATCH", "EPROGUNAVAIL", "EPWROFF", "ERPCMISMATCH", "ESHLIBVERS"]
+
+
+
+class CConfig:
+    _compilation_info_ = ExternalCompilationInfo(includes=['sys/errno.h'])
+
+for err_name in errors + win_errors + more_errors:
+    setattr(CConfig, err_name, DefinedConstantInteger(err_name))
+config = configure(CConfig)
+
+errorcode = {}
+name2code = {}
+for err_name in errors:
+    # Note: later names take precedence over earlier ones, if they have the
+    # same value
+    code = config[err_name]
+    if code is not None:
+        errorcode[code] = err_name
+        name2code[err_name] = code
+for name in win_errors:
+    assert name.startswith('WSA')
+    code = config[name]
+    if code is not None:
+        if name[3:] in errors:
+            # errno.EFOO = <WSAEFOO>
+            name2code[name[3:]] = code
+        # errno.WSABAR = <WSABAR>
+        name2code[name] = code
+        errorcode[code] = name
+
+for err_name in more_errors:
+    code = config[err_name]
+    if code is not None:
+        errorcode[code] = err_name
+        name2code[err_name] = code
 
 @not_rpython
 def get_errorcode(space):
-    return space.wrap(errno.errorcode) # initializiation time
-
+    return space.wrap(errorcode)  # initialization time
diff --git a/pypy/module/errno/test/test_errno.py 
b/pypy/module/errno/test/test_errno.py
--- a/pypy/module/errno/test/test_errno.py
+++ b/pypy/module/errno/test/test_errno.py
@@ -3,7 +3,7 @@
 class AppTestErrno:
     spaceconfig = dict(usemodules=['errno'])
 
-    def setup_class(cls): 
+    def setup_class(cls):
         cls.w_errno = cls.space.appexec([], "(): import errno ; return errno")
         cls.w_errorcode = cls.space.wrap(errno.errorcode)
 
@@ -11,28 +11,11 @@
         assert not hasattr(self.errno, '__file__')
 
     def test_constants(self):
-        host_errorcode = self.errorcode.copy()
-        # On some systems, ENOTSUP is an alias to EOPNOTSUPP.  Adjust the
-        # host_errorcode dictionary in case the host interpreter has slightly
-        # different errorcodes than the interpreter under test
-        if ('ENOTSUP' not in host_errorcode.values() and
-            'ENOTSUP' in self.errno.errorcode.values()):
-            host_errorcode[self.errno.ENOTSUP] = 'ENOTSUP'
-        if ('EOPNOTSUPP' not in host_errorcode.values() and
-            'EOPNOTSUPP' in self.errno.errorcode.values()):
-            host_errorcode[self.errno.EOPNOTSUPP] = 'EOPNOTSUPP'
-        for code, name in host_errorcode.items():
+        # Assumes that our constants are a superset of the host's
+        for code, name in self.errorcode.items():
             assert getattr(self.errno, name) == code
 
     def test_errorcode(self):
-        host_errorcode = self.errorcode.copy()
-        # On some systems, ENOTSUP is an alias to EOPNOTSUPP.  Adjust the
-        # host_errorcode dictionary in case the host interpreter has slightly
-        # different errorcodes than the interpreter under test
-        if ('ENOTSUP' not in host_errorcode.values() and
-            'ENOTSUP' in self.errno.errorcode.values()):
-            host_errorcode[self.errno.ENOTSUP] = 'ENOTSUP'
-        if ('EOPNOTSUPP' not in host_errorcode.values() and
-            'EOPNOTSUPP' in self.errno.errorcode.values()):
-            host_errorcode[self.errno.EOPNOTSUPP] = 'EOPNOTSUPP'
-        assert host_errorcode == self.errno.errorcode
+        # Assumes that our codes are a superset of the host's
+        for value, name in self.errorcode.items():
+            assert self.errno.errorcode[value] == name
diff --git a/pypy/module/posix/test/test_scandir.py 
b/pypy/module/posix/test/test_scandir.py
--- a/pypy/module/posix/test/test_scandir.py
+++ b/pypy/module/posix/test/test_scandir.py
@@ -98,8 +98,7 @@
         assert d.stat().st_mode & 0o170000 == 0o100000    # S_IFREG
         assert d.stat().st_size == 0
 
-    @py.test.mark.skipif(sys.platform == "win32",
-                         reason="no symlink support so far")
+    @py.test.mark.skipif(sys.platform == "win32", reason="no symlink support 
so far")
     def test_stat4(self):
         posix = self.posix
         d = next(posix.scandir(self.dir4))
@@ -129,8 +128,7 @@
         assert not d.is_file(follow_symlinks=False)
         assert     d.is_dir(follow_symlinks=False)
 
-    @py.test.mark.skipif(sys.platform == "win32",
-                         reason="no symlink support so far")
+    @py.test.mark.skipif(sys.platform == "win32", reason="no symlink support 
so far")
     def test_dir3(self):
         posix = self.posix
         d = next(posix.scandir(self.dir3))
@@ -141,8 +139,7 @@
         assert     d.is_file(follow_symlinks=True)
         assert not d.is_file(follow_symlinks=False)
 
-    @py.test.mark.skipif(sys.platform == "win32",
-                         reason="no symlink support so far")
+    @py.test.mark.skipif(sys.platform == "win32", reason="no symlink support 
so far")
     def test_dir4(self):
         posix = self.posix
         d = next(posix.scandir(self.dir4))
@@ -153,8 +150,7 @@
         assert     d.is_dir(follow_symlinks=True)
         assert not d.is_dir(follow_symlinks=False)
 
-    @py.test.mark.skipif(sys.platform == "win32",
-                         reason="no symlink support so far")
+    @py.test.mark.skipif(sys.platform == "win32", reason="no symlink support 
so far")
     def test_dir5(self):
         posix = self.posix
         d = next(posix.scandir(self.dir5))
@@ -164,8 +160,7 @@
         assert     d.is_symlink()
         raises(OSError, d.stat)
 
-    @py.test.mark.skipif(sys.platform == "win32",
-                         reason="no symlink support so far")
+    @py.test.mark.skipif(sys.platform == "win32", reason="no symlink support 
so far")
     def test_dir6(self):
         posix = self.posix
         d = next(posix.scandir(self.dir6))
diff --git a/rpython/rlib/rstacklet.py b/rpython/rlib/rstacklet.py
--- a/rpython/rlib/rstacklet.py
+++ b/rpython/rlib/rstacklet.py
@@ -3,7 +3,7 @@
 from rpython.rlib import jit
 from rpython.rlib.objectmodel import fetch_translated_config
 from rpython.rtyper.lltypesystem import lltype, llmemory
-from rpython.rlib.rvmprof import cintf
+from rpython.rlib import rvmprof
 
 DEBUG = False
 
@@ -25,12 +25,12 @@
     def new(self, callback, arg=llmemory.NULL):
         if DEBUG:
             callback = _debug_wrapper(callback)
-        x = cintf.save_rvmprof_stack()
+        x = rvmprof.save_stack()
         try:
-            cintf.empty_rvmprof_stack()
+            rvmprof.empty_stack()
             h = self._gcrootfinder.new(self, callback, arg)
         finally:
-            cintf.restore_rvmprof_stack(x)
+            rvmprof.restore_stack(x)
         if DEBUG:
             debug.add(h)
         return h
@@ -40,11 +40,11 @@
     def switch(self, stacklet):
         if DEBUG:
             debug.remove(stacklet)
-        x = cintf.save_rvmprof_stack()
+        x = rvmprof.save_stack()
         try:
             h = self._gcrootfinder.switch(stacklet)
         finally:
-            cintf.restore_rvmprof_stack(x)
+            rvmprof.restore_stack(x)
         if DEBUG:
             debug.add(h)
         return h
diff --git a/rpython/rlib/rvmprof/__init__.py b/rpython/rlib/rvmprof/__init__.py
--- a/rpython/rlib/rvmprof/__init__.py
+++ b/rpython/rlib/rvmprof/__init__.py
@@ -56,10 +56,27 @@
     return None
 
 def stop_sampling():
-    from rpython.rlib.rvmprof.cintf import vmprof_stop_sampling
-    fd = vmprof_stop_sampling()
-    return rffi.cast(lltype.Signed, fd)
+    return _get_vmprof().stop_sampling()
 
 def start_sampling():
-    from rpython.rlib.rvmprof.cintf import vmprof_start_sampling
-    vmprof_start_sampling()
+    return _get_vmprof().start_sampling()
+
+# ----------------
+# stacklet support
+# ----------------
+#
+# Ideally, vmprof_tl_stack, VMPROFSTACK etc. should be part of "self.cintf":
+# not sure why they are a global. Eventually, we should probably fix all this
+# mess.
+from rpython.rlib.rvmprof.cintf import vmprof_tl_stack, VMPROFSTACK
+
+def save_stack():
+    stop_sampling()
+    return vmprof_tl_stack.get_or_make_raw()
+
+def empty_stack():
+    vmprof_tl_stack.setraw(lltype.nullptr(VMPROFSTACK))
+
+def restore_stack(x):
+    vmprof_tl_stack.setraw(x)
+    start_sampling()
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
@@ -10,71 +10,82 @@
 from rpython.rlib import rthread, jit
 from rpython.rlib.objectmodel import we_are_translated
 from rpython.config.translationoption import get_translation_config
+from rpython.jit.backend import detect_cpu
 
 class VMProfPlatformUnsupported(Exception):
     pass
 
+# vmprof works only on x86 for now
+IS_SUPPORTED = detect_cpu.autodetect().startswith('x86')
+if sys.platform == 'win32':
+    IS_SUPPORTED = False
+
 ROOT = py.path.local(rpythonroot).join('rpython', 'rlib', 'rvmprof')
 SRC = ROOT.join('src')
 SHARED = SRC.join('shared')
 BACKTRACE = SHARED.join('libbacktrace')
 
-compile_extra = ['-DRPYTHON_VMPROF']
-separate_module_files = [
-    SHARED.join('symboltable.c'),
-    SHARED.join('vmprof_unix.c')
-]
-if sys.platform.startswith('linux'):
-    separate_module_files += [
-       BACKTRACE.join('atomic.c'),
-       BACKTRACE.join('backtrace.c'),
-       BACKTRACE.join('state.c'),
-       BACKTRACE.join('elf.c'),
-       BACKTRACE.join('dwarf.c'),
-       BACKTRACE.join('fileline.c'),
-       BACKTRACE.join('mmap.c'),
-       BACKTRACE.join('mmapio.c'),
-       BACKTRACE.join('posix.c'),
-       BACKTRACE.join('sort.c'),
+def make_eci():
+    if make_eci.called:
+        raise ValueError("make_eci() should be called at most once")
+    #
+    compile_extra = ['-DRPYTHON_VMPROF']
+    separate_module_files = [
+        SHARED.join('symboltable.c'),
+        SHARED.join('vmprof_unix.c')
     ]
-    _libs = ['dl']
-    compile_extra += ['-DVMPROF_UNIX']
-    compile_extra += ['-DVMPROF_LINUX']
-elif sys.platform == 'win32':
-    compile_extra += ['-DVMPROF_WINDOWS']
-    separate_module_files = [SHARED.join('vmprof_win.c')]
-    _libs = []
-else:
-    # Guessing a BSD-like Unix platform
-    compile_extra += ['-DVMPROF_UNIX']
-    compile_extra += ['-DVMPROF_MAC']
-    if sys.platform.startswith('freebsd'):
-        _libs = ['unwind']
+    if sys.platform.startswith('linux'):
+        separate_module_files += [
+           BACKTRACE.join('atomic.c'),
+           BACKTRACE.join('backtrace.c'),
+           BACKTRACE.join('state.c'),
+           BACKTRACE.join('elf.c'),
+           BACKTRACE.join('dwarf.c'),
+           BACKTRACE.join('fileline.c'),
+           BACKTRACE.join('mmap.c'),
+           BACKTRACE.join('mmapio.c'),
+           BACKTRACE.join('posix.c'),
+           BACKTRACE.join('sort.c'),
+        ]
+        _libs = ['dl']
+        compile_extra += ['-DVMPROF_UNIX']
+        compile_extra += ['-DVMPROF_LINUX']
+    elif sys.platform == 'win32':
+        compile_extra += ['-DVMPROF_WINDOWS']
+        separate_module_files = [SHARED.join('vmprof_win.c')]
+        _libs = []
     else:
-        _libs = []
+        # Guessing a BSD-like Unix platform
+        compile_extra += ['-DVMPROF_UNIX']
+        compile_extra += ['-DVMPROF_MAC']
+        if sys.platform.startswith('freebsd'):
+            _libs = ['unwind']
+        else:
+            _libs = []
 
-
-eci_kwds = dict(
-    include_dirs = [SRC, SHARED, BACKTRACE],
-    includes = ['rvmprof.h','vmprof_stack.h'],
-    libraries = _libs,
-    separate_module_files = [
-        SRC.join('rvmprof.c'),
-        SHARED.join('compat.c'),
-        SHARED.join('machine.c'),
-        SHARED.join('vmp_stack.c'),
-        SHARED.join('vmprof_memory.c'),
-        SHARED.join('vmprof_common.c'),
-        # symbol table already in separate_module_files
-    ] + separate_module_files,
-    post_include_bits=[],
-    compile_extra=compile_extra
-    )
-if sys.platform != 'win32':
-    eci_kwds['separate_module_files'].append(
-        SHARED.join('vmprof_mt.c'),
-    )
-global_eci = ExternalCompilationInfo(**eci_kwds)
+    eci_kwds = dict(
+        include_dirs = [SRC, SHARED, BACKTRACE],
+        includes = ['rvmprof.h','vmprof_stack.h'],
+        libraries = _libs,
+        separate_module_files = [
+            SRC.join('rvmprof.c'),
+            SHARED.join('compat.c'),
+            SHARED.join('machine.c'),
+            SHARED.join('vmp_stack.c'),
+            SHARED.join('vmprof_memory.c'),
+            SHARED.join('vmprof_common.c'),
+            # symbol table already in separate_module_files
+        ] + separate_module_files,
+        post_include_bits=[],
+        compile_extra=compile_extra
+        )
+    if sys.platform != 'win32':
+        eci_kwds['separate_module_files'].append(
+            SHARED.join('vmprof_mt.c'),
+        )
+    make_eci.called = True
+    return ExternalCompilationInfo(**eci_kwds), eci_kwds
+make_eci.called = False
 
 def configure_libbacktrace_linux():
     bits = 32 if sys.maxsize == 2**31-1 else 64
@@ -85,14 +96,17 @@
     shutil.copy(str(BACKTRACE.join(specific_config)), str(config))
 
 def setup():
+    if not IS_SUPPORTED:
+        raise VMProfPlatformUnsupported
+    
     if sys.platform.startswith('linux'):
         configure_libbacktrace_linux()
 
+    eci, eci_kwds = make_eci()
     eci_kwds['compile_extra'].append('-DRPYTHON_LL2CTYPES')
     platform.verify_eci(ExternalCompilationInfo(
                         **eci_kwds))
 
-    eci = global_eci
     vmprof_init = rffi.llexternal("vmprof_init",
                                   [rffi.INT, rffi.DOUBLE, rffi.INT, rffi.INT,
                                    rffi.CCHARP, rffi.INT, rffi.INT],
@@ -122,32 +136,16 @@
                                               lltype.Signed, 
compilation_info=eci,
                                               _nowrapper=True)
 
+    vmprof_stop_sampling = rffi.llexternal("vmprof_stop_sampling", [],
+                                           rffi.INT, compilation_info=eci,
+                                           _nowrapper=True)
+    vmprof_start_sampling = rffi.llexternal("vmprof_start_sampling", [],
+                                            lltype.Void, compilation_info=eci,
+                                            _nowrapper=True)
+
     return CInterface(locals())
 
 
-# this is always present, but compiles to no-op if RPYTHON_VMPROF is not
-# defined (i.e. if we don't actually use vmprof in the generated C)
-auto_eci = ExternalCompilationInfo(post_include_bits=["""
-#ifndef RPYTHON_VMPROF
-#  define vmprof_stop_sampling()    (-1)
-#  define vmprof_start_sampling()   ((void)0)
-#endif
-"""])
-
-if get_translation_config() is None:
-    # tests need the full eci here
-    _eci = global_eci
-else:
-    _eci = auto_eci
-
-vmprof_stop_sampling = rffi.llexternal("vmprof_stop_sampling", [],
-                                       rffi.INT, compilation_info=_eci,
-                                       _nowrapper=True)
-vmprof_start_sampling = rffi.llexternal("vmprof_start_sampling", [],
-                                        lltype.Void, compilation_info=_eci,
-                                        _nowrapper=True)
-
-
 class CInterface(object):
     def __init__(self, namespace):
         for k, v in namespace.iteritems():
@@ -232,20 +230,6 @@
         leave_code(s)
 
 #
-# stacklet support
-
-def save_rvmprof_stack():
-    vmprof_stop_sampling()
-    return vmprof_tl_stack.get_or_make_raw()
-
-def empty_rvmprof_stack():
-    vmprof_tl_stack.setraw(lltype.nullptr(VMPROFSTACK))
-
-def restore_rvmprof_stack(x):
-    vmprof_tl_stack.setraw(x)
-    vmprof_start_sampling()
-
-#
 # traceback support
 
 def get_rvmprof_stack():
diff --git a/rpython/rlib/rvmprof/dummy.py b/rpython/rlib/rvmprof/dummy.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rvmprof/dummy.py
@@ -0,0 +1,26 @@
+from rpython.rlib.objectmodel import specialize
+
+class DummyVMProf(object):
+
+    def __init__(self):
+        self._unique_id = 0
+
+    def register_code_object_class(self, CodeClass, full_name_func):
+        CodeClass._vmprof_unique_id = self._unique_id
+        self._unique_id += 1
+
+    @specialize.argtype(1)
+    def register_code(self, code, full_name_func):
+        pass
+
+    def enable(self, fileno, interval, memory=0, native=0, real_time=0):
+        pass
+
+    def disable(self):
+        pass
+
+    def start_sampling(self):
+        pass
+
+    def stop_sampling(self):
+        pass
diff --git a/rpython/rlib/rvmprof/rvmprof.py b/rpython/rlib/rvmprof/rvmprof.py
--- a/rpython/rlib/rvmprof/rvmprof.py
+++ b/rpython/rlib/rvmprof/rvmprof.py
@@ -2,6 +2,7 @@
 from rpython.rlib.objectmodel import specialize, we_are_translated, not_rpython
 from rpython.rlib import jit, rposix, rgc
 from rpython.rlib.rvmprof import cintf
+from rpython.rlib.rvmprof.dummy import DummyVMProf
 from rpython.rtyper.annlowlevel import cast_instance_to_gcref
 from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
 from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
@@ -34,6 +35,9 @@
         return []
 
 class VMProf(object):
+    """
+    NOTE: the API of this class should be kept in sync with dummy.DummyVMProf
+    """
 
     _immutable_fields_ = ['is_enabled?']
 
@@ -168,6 +172,21 @@
         if self.cintf.vmprof_register_virtual_function(name, uid, 500000) < 0:
             raise VMProfError("vmprof buffers full!  disk full or too slow")
 
+    def stop_sampling(self):
+        """
+        Temporarily stop the sampling of stack frames. Signals are still
+        delivered, but are ignored.
+        """
+        fd = self.cintf.vmprof_stop_sampling()
+        return rffi.cast(lltype.Signed, fd)
+
+    def start_sampling(self):
+        """
+        Undo the effect of stop_sampling
+        """
+        self.cintf.vmprof_start_sampling()
+
+
 def vmprof_execute_code(name, get_code_fn, result_class=None,
                         _hack_update_stack_untranslated=False):
     """Decorator to be used on the function that interprets a code object.
@@ -240,5 +259,8 @@
 def _get_vmprof():
     global _vmprof_instance
     if _vmprof_instance is None:
-        _vmprof_instance = VMProf()
+        try:
+            _vmprof_instance = VMProf()
+        except cintf.VMProfPlatformUnsupported:
+            _vmprof_instance = DummyVMProf()
     return _vmprof_instance
diff --git a/rpython/rlib/rvmprof/test/support.py 
b/rpython/rlib/rvmprof/test/support.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rvmprof/test/support.py
@@ -0,0 +1,45 @@
+import pytest
+from rpython.rlib import rvmprof
+
+class FakeVMProf(object):
+
+    def __init__(self):
+        self._enabled = False
+        self._ignore_signals = 1
+
+    # --- VMProf official API ---
+    # add fake methods as needed by the tests
+
+    def stop_sampling(self):
+        self._ignore_signals += 1
+
+    def start_sampling(self):
+        assert self._ignore_signals > 0, ('calling start_sampling() without '
+                                          'the corresponding stop_sampling()?')
+        self._ignore_signals -= 1
+
+    # --- FakeVMProf specific API ---
+    # this API is not part of rvmprof, but available only inside tests using
+    # fakevmprof
+
+    @property
+    def is_sampling_enabled(self):
+        return self._ignore_signals == 0
+
+    def check_status(self):
+        """
+        To be called during test teardown
+        """
+        if self._ignore_signals != 1:
+            msg = ('Invalid value for fakevmprof._ignore_signals: expected 1, '
+                   'got %d. This probably means that you called '
+                   '{start,stop}_sampling() a wrong number of times')
+            raise ValueError, msg % self._ignore_signals
+
+
+@pytest.fixture
+def fakevmprof(request, monkeypatch):
+    fake = FakeVMProf()
+    monkeypatch.setattr(rvmprof.rvmprof, '_vmprof_instance', fake)
+    request.addfinalizer(fake.check_status)
+    return fake
diff --git a/rpython/rlib/rvmprof/test/test_support.py 
b/rpython/rlib/rvmprof/test/test_support.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rvmprof/test/test_support.py
@@ -0,0 +1,42 @@
+import pytest
+from rpython.rlib import rvmprof
+from rpython.rlib.rvmprof.test.support import FakeVMProf, fakevmprof
+
+class TestFakeVMProf(object):
+
+    def test_sampling(self):
+        fake = FakeVMProf()
+        assert not fake.is_sampling_enabled
+        #
+        fake.start_sampling()
+        assert fake.is_sampling_enabled
+        #
+        fake.stop_sampling()
+        fake.stop_sampling()
+        assert not fake.is_sampling_enabled
+        #
+        fake.start_sampling()
+        assert not fake.is_sampling_enabled
+        fake.start_sampling()
+        assert fake.is_sampling_enabled
+        #
+        pytest.raises(AssertionError, "fake.start_sampling()")
+    
+    def test_check_status(self):
+        fake = FakeVMProf()
+        fake.stop_sampling()
+        pytest.raises(ValueError, "fake.check_status()")
+
+
+class TestFixture(object):
+
+    def test_fixture(self, fakevmprof):
+        assert isinstance(fakevmprof, FakeVMProf)
+        assert rvmprof._get_vmprof() is fakevmprof
+        #
+        # tweak sampling using the "real" API, and check that we actually used
+        # the fake
+        rvmprof.start_sampling()
+        assert fakevmprof.is_sampling_enabled
+        rvmprof.stop_sampling()
+        assert not fakevmprof.is_sampling_enabled
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to