Author: Ronan Lamy <[email protected]>
Branch: py3k-update
Changeset: r83994:4363df660a6b
Date: 2016-04-27 18:52 +0100
http://bitbucket.org/pypy/pypy/changeset/4363df660a6b/
Log: hg merge 73a49ec9edc3
diff --git a/lib_pypy/_collections.py b/lib_pypy/_collections.py
--- a/lib_pypy/_collections.py
+++ b/lib_pypy/_collections.py
@@ -320,8 +320,7 @@
def __reduce_ex__(self, proto):
return type(self), (list(self), self.maxlen)
- def __hash__(self):
- raise TypeError("deque objects are unhashable")
+ __hash__ = None
def __copy__(self):
return self.__class__(self, self.maxlen)
diff --git a/lib_pypy/_pypy_wait.py b/lib_pypy/_pypy_wait.py
--- a/lib_pypy/_pypy_wait.py
+++ b/lib_pypy/_pypy_wait.py
@@ -1,51 +1,22 @@
-from resource import _struct_rusage, struct_rusage
-from ctypes import CDLL, c_int, POINTER, byref
-from ctypes.util import find_library
+from resource import ffi, lib, _make_struct_rusage
__all__ = ["wait3", "wait4"]
-libc = CDLL(find_library("c"))
-c_wait3 = libc.wait3
-c_wait3.argtypes = [POINTER(c_int), c_int, POINTER(_struct_rusage)]
-c_wait3.restype = c_int
-
-c_wait4 = libc.wait4
-c_wait4.argtypes = [c_int, POINTER(c_int), c_int, POINTER(_struct_rusage)]
-c_wait4.restype = c_int
-
-def create_struct_rusage(c_struct):
- return struct_rusage((
- float(c_struct.ru_utime),
- float(c_struct.ru_stime),
- c_struct.ru_maxrss,
- c_struct.ru_ixrss,
- c_struct.ru_idrss,
- c_struct.ru_isrss,
- c_struct.ru_minflt,
- c_struct.ru_majflt,
- c_struct.ru_nswap,
- c_struct.ru_inblock,
- c_struct.ru_oublock,
- c_struct.ru_msgsnd,
- c_struct.ru_msgrcv,
- c_struct.ru_nsignals,
- c_struct.ru_nvcsw,
- c_struct.ru_nivcsw))
def wait3(options):
- status = c_int()
- _rusage = _struct_rusage()
- pid = c_wait3(byref(status), c_int(options), byref(_rusage))
+ status = ffi.new("int *")
+ ru = ffi.new("struct rusage *")
+ pid = lib.wait3(status, options, ru)
- rusage = create_struct_rusage(_rusage)
+ rusage = _make_struct_rusage(ru)
- return pid, status.value, rusage
+ return pid, status[0], rusage
def wait4(pid, options):
- status = c_int()
- _rusage = _struct_rusage()
- pid = c_wait4(c_int(pid), byref(status), c_int(options), byref(_rusage))
+ status = ffi.new("int *")
+ ru = ffi.new("struct rusage *")
+ pid = lib.wait4(pid, status, options, ru)
- rusage = create_struct_rusage(_rusage)
+ rusage = _make_struct_rusage(ru)
- return pid, status.value, rusage
+ return pid, status[0], rusage
diff --git a/lib_pypy/_resource_build.py b/lib_pypy/_resource_build.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_resource_build.py
@@ -0,0 +1,118 @@
+from cffi import FFI
+
+ffi = FFI()
+
+# Note: we don't directly expose 'struct timeval' or 'struct rlimit'
+
+
+rlimit_consts = '''
+RLIMIT_CPU
+RLIMIT_FSIZE
+RLIMIT_DATA
+RLIMIT_STACK
+RLIMIT_CORE
+RLIMIT_NOFILE
+RLIMIT_OFILE
+RLIMIT_VMEM
+RLIMIT_AS
+RLIMIT_RSS
+RLIMIT_NPROC
+RLIMIT_MEMLOCK
+RLIMIT_SBSIZE
+RLIM_INFINITY
+RUSAGE_SELF
+RUSAGE_CHILDREN
+RUSAGE_BOTH
+'''.split()
+
+rlimit_consts = ['#ifdef %s\n\t{"%s", %s},\n#endif\n' % (s, s, s)
+ for s in rlimit_consts]
+
+
+ffi.set_source("_resource_cffi", """
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+static const struct my_rlimit_def {
+ const char *name;
+ long long value;
+} my_rlimit_consts[] = {
+$RLIMIT_CONSTS
+ { NULL, 0 }
+};
+
+#define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001)
+
+static double my_utime(struct rusage *input)
+{
+ return doubletime(input->ru_utime);
+}
+
+static double my_stime(struct rusage *input)
+{
+ return doubletime(input->ru_stime);
+}
+
+static int my_getrlimit(int resource, long long result[2])
+{
+ struct rlimit rl;
+ if (getrlimit(resource, &rl) == -1)
+ return -1;
+ result[0] = rl.rlim_cur;
+ result[1] = rl.rlim_max;
+ return 0;
+}
+
+static int my_setrlimit(int resource, long long cur, long long max)
+{
+ struct rlimit rl;
+ rl.rlim_cur = cur & RLIM_INFINITY;
+ rl.rlim_max = max & RLIM_INFINITY;
+ return setrlimit(resource, &rl);
+}
+
+""".replace('$RLIMIT_CONSTS', ''.join(rlimit_consts)))
+
+
+ffi.cdef("""
+
+#define RLIM_NLIMITS ...
+
+const struct my_rlimit_def {
+ const char *name;
+ long long value;
+} my_rlimit_consts[];
+
+struct rusage {
+ long ru_maxrss;
+ long ru_ixrss;
+ long ru_idrss;
+ long ru_isrss;
+ long ru_minflt;
+ long ru_majflt;
+ long ru_nswap;
+ long ru_inblock;
+ long ru_oublock;
+ long ru_msgsnd;
+ long ru_msgrcv;
+ long ru_nsignals;
+ long ru_nvcsw;
+ long ru_nivcsw;
+ ...;
+};
+
+static double my_utime(struct rusage *);
+static double my_stime(struct rusage *);
+void getrusage(int who, struct rusage *result);
+int my_getrlimit(int resource, long long result[2]);
+int my_setrlimit(int resource, long long cur, long long max);
+
+int wait3(int *status, int options, struct rusage *rusage);
+int wait4(int pid, int *status, int options, struct rusage *rusage);
+""")
+
+
+if __name__ == "__main__":
+ ffi.compile()
diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py
--- a/lib_pypy/cffi/cparser.py
+++ b/lib_pypy/cffi/cparser.py
@@ -29,7 +29,8 @@
_r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b")
_r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b")
_r_cdecl = re.compile(r"\b__cdecl\b")
-_r_extern_python = re.compile(r'\bextern\s*"Python"\s*.')
+_r_extern_python = re.compile(r'\bextern\s*"'
+ r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.')
_r_star_const_space = re.compile( # matches "* const "
r"[*]\s*((const|volatile|restrict)\b\s*)+")
@@ -88,6 +89,12 @@
# void __cffi_extern_python_start;
# int foo(int);
# void __cffi_extern_python_stop;
+ #
+ # input: `extern "Python+C" int foo(int);`
+ # output:
+ # void __cffi_extern_python_plus_c_start;
+ # int foo(int);
+ # void __cffi_extern_python_stop;
parts = []
while True:
match = _r_extern_python.search(csource)
@@ -98,7 +105,10 @@
#print ''.join(parts)+csource
#print '=>'
parts.append(csource[:match.start()])
- parts.append('void __cffi_extern_python_start; ')
+ if 'C' in match.group(1):
+ parts.append('void __cffi_extern_python_plus_c_start; ')
+ else:
+ parts.append('void __cffi_extern_python_start; ')
if csource[endpos] == '{':
# grouping variant
closing = csource.find('}', endpos)
@@ -302,7 +312,7 @@
break
#
try:
- self._inside_extern_python = False
+ self._inside_extern_python = '__cffi_extern_python_stop'
for decl in iterator:
if isinstance(decl, pycparser.c_ast.Decl):
self._parse_decl(decl)
@@ -376,8 +386,10 @@
tp = self._get_type_pointer(tp, quals)
if self._options.get('dllexport'):
tag = 'dllexport_python '
- elif self._inside_extern_python:
+ elif self._inside_extern_python == '__cffi_extern_python_start':
tag = 'extern_python '
+ elif self._inside_extern_python == '__cffi_extern_python_plus_c_start':
+ tag = 'extern_python_plus_c '
else:
tag = 'function '
self._declare(tag + decl.name, tp)
@@ -421,11 +433,9 @@
# hack: `extern "Python"` in the C source is replaced
# with "void __cffi_extern_python_start;" and
# "void __cffi_extern_python_stop;"
- self._inside_extern_python = not self._inside_extern_python
- assert self._inside_extern_python == (
- decl.name == '__cffi_extern_python_start')
+ self._inside_extern_python = decl.name
else:
- if self._inside_extern_python:
+ if self._inside_extern_python
!='__cffi_extern_python_stop':
raise api.CDefError(
"cannot declare constants or "
"variables with 'extern \"Python\"'")
diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py
--- a/lib_pypy/cffi/recompiler.py
+++ b/lib_pypy/cffi/recompiler.py
@@ -1145,11 +1145,11 @@
def _generate_cpy_extern_python_collecttype(self, tp, name):
assert isinstance(tp, model.FunctionPtrType)
self._do_collect_type(tp)
+ _generate_cpy_dllexport_python_collecttype = \
+ _generate_cpy_extern_python_plus_c_collecttype = \
+ _generate_cpy_extern_python_collecttype
- def _generate_cpy_dllexport_python_collecttype(self, tp, name):
- self._generate_cpy_extern_python_collecttype(tp, name)
-
- def _generate_cpy_extern_python_decl(self, tp, name, dllexport=False):
+ def _extern_python_decl(self, tp, name, tag_and_space):
prnt = self._prnt
if isinstance(tp.result, model.VoidType):
size_of_result = '0'
@@ -1184,11 +1184,7 @@
size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % (
tp.result.get_c_name(''), size_of_a,
tp.result.get_c_name(''), size_of_a)
- if dllexport:
- tag = 'CFFI_DLLEXPORT'
- else:
- tag = 'static'
- prnt('%s %s' % (tag, tp.result.get_c_name(name_and_arguments)))
+ prnt('%s%s' % (tag_and_space,
tp.result.get_c_name(name_and_arguments)))
prnt('{')
prnt(' char a[%s];' % size_of_a)
prnt(' char *p = a;')
@@ -1206,8 +1202,14 @@
prnt()
self._num_externpy += 1
+ def _generate_cpy_extern_python_decl(self, tp, name):
+ self._extern_python_decl(tp, name, 'static ')
+
def _generate_cpy_dllexport_python_decl(self, tp, name):
- self._generate_cpy_extern_python_decl(tp, name, dllexport=True)
+ self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ')
+
+ def _generate_cpy_extern_python_plus_c_decl(self, tp, name):
+ self._extern_python_decl(tp, name, '')
def _generate_cpy_extern_python_ctx(self, tp, name):
if self.target_is_python:
@@ -1220,8 +1222,9 @@
self._lsts["global"].append(
GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name))
- def _generate_cpy_dllexport_python_ctx(self, tp, name):
- self._generate_cpy_extern_python_ctx(tp, name)
+ _generate_cpy_dllexport_python_ctx = \
+ _generate_cpy_extern_python_plus_c_ctx = \
+ _generate_cpy_extern_python_ctx
def _string_literal(self, s):
def _char_repr(c):
diff --git a/lib_pypy/ctypes_config_cache/.empty
b/lib_pypy/ctypes_config_cache/.empty
new file mode 100644
--- /dev/null
+++ b/lib_pypy/ctypes_config_cache/.empty
@@ -0,0 +1,1 @@
+dummy file to allow old buildbot configuration to run
diff --git a/lib_pypy/ctypes_config_cache/__init__.py
b/lib_pypy/ctypes_config_cache/__init__.py
deleted file mode 100644
diff --git a/lib_pypy/ctypes_config_cache/dumpcache.py
b/lib_pypy/ctypes_config_cache/dumpcache.py
deleted file mode 100644
--- a/lib_pypy/ctypes_config_cache/dumpcache.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import sys, os
-from ctypes_configure import dumpcache
-
-def dumpcache2(basename, config):
- size = 32 if sys.maxint <= 2**32 else 64
- filename = '_%s_%s_.py' % (basename, size)
- dumpcache.dumpcache(__file__, filename, config)
- #
- filename = os.path.join(os.path.dirname(__file__),
- '_%s_cache.py' % (basename,))
- g = open(filename, 'w')
- print >> g, '''\
-import sys
-_size = 32 if sys.maxsize <= 2**32 else 64
-# XXX relative import, should be removed together with
-# XXX the relative imports done e.g. by lib_pypy/pypy_test/test_hashlib
-_mod = __import__("_%s_%%s_" %% (_size,),
- globals(), locals(), ["*"], level=1)
-globals().update(_mod.__dict__)\
-''' % (basename,)
- g.close()
diff --git a/lib_pypy/ctypes_config_cache/locale.ctc.py
b/lib_pypy/ctypes_config_cache/locale.ctc.py
deleted file mode 100644
--- a/lib_pypy/ctypes_config_cache/locale.ctc.py
+++ /dev/null
@@ -1,73 +0,0 @@
-"""
-'ctypes_configure' source for _locale.py.
-Run this to rebuild _locale_cache.py.
-"""
-
-from ctypes_configure.configure import (configure, ExternalCompilationInfo,
- ConstantInteger, DefinedConstantInteger, SimpleType, check_eci)
-import dumpcache
-
-# ____________________________________________________________
-
-_CONSTANTS = [
- 'LC_CTYPE',
- 'LC_TIME',
- 'LC_COLLATE',
- 'LC_MONETARY',
- 'LC_MESSAGES',
- 'LC_NUMERIC',
- 'LC_ALL',
- 'CHAR_MAX',
-]
-
-class LocaleConfigure:
- _compilation_info_ = ExternalCompilationInfo(includes=['limits.h',
- 'locale.h'])
-for key in _CONSTANTS:
- setattr(LocaleConfigure, key, DefinedConstantInteger(key))
-
-config = configure(LocaleConfigure, noerr=True)
-for key, value in config.items():
- if value is None:
- del config[key]
- _CONSTANTS.remove(key)
-
-# ____________________________________________________________
-
-eci = ExternalCompilationInfo(includes=['locale.h', 'langinfo.h'])
-HAS_LANGINFO = check_eci(eci)
-
-if HAS_LANGINFO:
- # list of all possible names
- langinfo_names = [
- "RADIXCHAR", "THOUSEP", "CRNCYSTR",
- "D_T_FMT", "D_FMT", "T_FMT", "AM_STR", "PM_STR",
- "CODESET", "T_FMT_AMPM", "ERA", "ERA_D_FMT", "ERA_D_T_FMT",
- "ERA_T_FMT", "ALT_DIGITS", "YESEXPR", "NOEXPR", "_DATE_FMT",
- ]
- for i in range(1, 8):
- langinfo_names.append("DAY_%d" % i)
- langinfo_names.append("ABDAY_%d" % i)
- for i in range(1, 13):
- langinfo_names.append("MON_%d" % i)
- langinfo_names.append("ABMON_%d" % i)
-
- class LanginfoConfigure:
- _compilation_info_ = eci
- nl_item = SimpleType('nl_item')
- for key in langinfo_names:
- setattr(LanginfoConfigure, key, DefinedConstantInteger(key))
-
- langinfo_config = configure(LanginfoConfigure)
- for key, value in langinfo_config.items():
- if value is None:
- del langinfo_config[key]
- langinfo_names.remove(key)
- config.update(langinfo_config)
- _CONSTANTS += langinfo_names
-
-# ____________________________________________________________
-
-config['ALL_CONSTANTS'] = tuple(_CONSTANTS)
-config['HAS_LANGINFO'] = HAS_LANGINFO
-dumpcache.dumpcache2('locale', config)
diff --git a/lib_pypy/ctypes_config_cache/rebuild.py
b/lib_pypy/ctypes_config_cache/rebuild.py
deleted file mode 100755
--- a/lib_pypy/ctypes_config_cache/rebuild.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#! /usr/bin/env python
-# Run this script to rebuild all caches from the *.ctc.py files.
-
-import os, sys
-
-sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__),
'..', '..')))
-
-import py
-
-_dirpath = os.path.dirname(__file__) or os.curdir
-
-from rpython.tool.ansi_print import AnsiLogger
-log = AnsiLogger("ctypes_config_cache")
-
-
-def rebuild_one(name):
- filename = os.path.join(_dirpath, name)
- d = {'__file__': filename}
- path = sys.path[:]
- try:
- sys.path.insert(0, _dirpath)
- execfile(filename, d)
- finally:
- sys.path[:] = path
-
-def try_rebuild():
- size = 32 if sys.maxint <= 2**32 else 64
- # remove the files '_*_size_.py'
- left = {}
- for p in os.listdir(_dirpath):
- if p.startswith('_') and (p.endswith('_%s_.py' % size) or
- p.endswith('_%s_.pyc' % size)):
- os.unlink(os.path.join(_dirpath, p))
- elif p.startswith('_') and (p.endswith('_.py') or
- p.endswith('_.pyc')):
- for i in range(2, len(p)-4):
- left[p[:i]] = True
- # remove the files '_*_cache.py' if there is no '_*_*_.py' left around
- for p in os.listdir(_dirpath):
- if p.startswith('_') and (p.endswith('_cache.py') or
- p.endswith('_cache.pyc')):
- if p[:-9] not in left:
- os.unlink(os.path.join(_dirpath, p))
- #
- for p in os.listdir(_dirpath):
- if p.endswith('.ctc.py'):
- try:
- rebuild_one(p)
- except Exception, e:
- log.ERROR("Running %s:\n %s: %s" % (
- os.path.join(_dirpath, p),
- e.__class__.__name__, e))
-
-
-if __name__ == '__main__':
- try_rebuild()
diff --git a/lib_pypy/ctypes_config_cache/resource.ctc.py
b/lib_pypy/ctypes_config_cache/resource.ctc.py
deleted file mode 100644
--- a/lib_pypy/ctypes_config_cache/resource.ctc.py
+++ /dev/null
@@ -1,62 +0,0 @@
-"""
-'ctypes_configure' source for resource.py.
-Run this to rebuild _resource_cache.py.
-"""
-
-
-from ctypes import sizeof
-import dumpcache
-from ctypes_configure.configure import (configure,
- ExternalCompilationInfo, ConstantInteger, DefinedConstantInteger,
- SimpleType)
-
-
-_CONSTANTS = (
- 'RLIM_INFINITY',
- 'RLIM_NLIMITS',
-)
-_OPTIONAL_CONSTANTS = (
- 'RLIMIT_CPU',
- 'RLIMIT_FSIZE',
- 'RLIMIT_DATA',
- 'RLIMIT_STACK',
- 'RLIMIT_CORE',
- 'RLIMIT_RSS',
- 'RLIMIT_NPROC',
- 'RLIMIT_NOFILE',
- 'RLIMIT_OFILE',
- 'RLIMIT_MEMLOCK',
- 'RLIMIT_AS',
- 'RLIMIT_LOCKS',
- 'RLIMIT_SIGPENDING',
- 'RLIMIT_MSGQUEUE',
- 'RLIMIT_NICE',
- 'RLIMIT_RTPRIO',
- 'RLIMIT_VMEM',
-
- 'RUSAGE_BOTH',
- 'RUSAGE_SELF',
- 'RUSAGE_CHILDREN',
-)
-
-# Setup our configure
-class ResourceConfigure:
- _compilation_info_ = ExternalCompilationInfo(includes=['sys/resource.h'])
- rlim_t = SimpleType('rlim_t')
-for key in _CONSTANTS:
- setattr(ResourceConfigure, key, ConstantInteger(key))
-for key in _OPTIONAL_CONSTANTS:
- setattr(ResourceConfigure, key, DefinedConstantInteger(key))
-
-# Configure constants and types
-config = configure(ResourceConfigure)
-config['rlim_t_max'] = (1<<(sizeof(config['rlim_t']) * 8)) - 1
-optional_constants = []
-for key in _OPTIONAL_CONSTANTS:
- if config[key] is not None:
- optional_constants.append(key)
- else:
- del config[key]
-
-config['ALL_CONSTANTS'] = _CONSTANTS + tuple(optional_constants)
-dumpcache.dumpcache2('resource', config)
diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py
--- a/lib_pypy/pwd.py
+++ b/lib_pypy/pwd.py
@@ -1,4 +1,4 @@
-# ctypes implementation: Victor Stinner, 2008-05-08
+# indirectly based on ctypes implementation: Victor Stinner, 2008-05-08
"""
This module provides access to the Unix password database.
It is available on all Unix versions.
diff --git a/lib_pypy/resource.py b/lib_pypy/resource.py
--- a/lib_pypy/resource.py
+++ b/lib_pypy/resource.py
@@ -1,15 +1,8 @@
-import sys
-if sys.platform == 'win32':
- raise ImportError('resource module not available for win32')
+"""http://docs.python.org/library/resource"""
-# load the platform-specific cache made by running resource.ctc.py
-from ctypes_config_cache._resource_cache import *
-
-from ctypes_support import standard_c_lib as libc
-from ctypes_support import get_errno
-from ctypes import Structure, c_int, c_long, byref, POINTER
+from _resource_cffi import ffi, lib
from errno import EINVAL, EPERM
-import _structseq
+import _structseq, os
try: from __pypy__ import builtinify
except ImportError: builtinify = lambda f: f
@@ -18,104 +11,37 @@
class error(Exception):
pass
+class struct_rusage(metaclass=_structseq.structseqtype):
+ """struct_rusage: Result from getrusage.
-# Read required libc functions
-_getrusage = libc.getrusage
-_getrlimit = libc.getrlimit
-_setrlimit = libc.setrlimit
-try:
- _getpagesize = libc.getpagesize
- _getpagesize.argtypes = ()
- _getpagesize.restype = c_int
-except AttributeError:
- from os import sysconf
- _getpagesize = None
+This object may be accessed either as a tuple of
+ (utime,stime,maxrss,ixrss,idrss,isrss,minflt,majflt,
+ nswap,inblock,oublock,msgsnd,msgrcv,nsignals,nvcsw,nivcsw)
+or via the attributes ru_utime, ru_stime, ru_maxrss, and so on."""
+ __metaclass__ = _structseq.structseqtype
-class timeval(Structure):
- _fields_ = (
- ("tv_sec", c_long),
- ("tv_usec", c_long),
- )
- def __str__(self):
- return "(%s, %s)" % (self.tv_sec, self.tv_usec)
+ ru_utime = _structseq.structseqfield(0, "user time used")
+ ru_stime = _structseq.structseqfield(1, "system time used")
+ ru_maxrss = _structseq.structseqfield(2, "max. resident set size")
+ ru_ixrss = _structseq.structseqfield(3, "shared memory size")
+ ru_idrss = _structseq.structseqfield(4, "unshared data size")
+ ru_isrss = _structseq.structseqfield(5, "unshared stack size")
+ ru_minflt = _structseq.structseqfield(6, "page faults not requiring I/O")
+ ru_majflt = _structseq.structseqfield(7, "page faults requiring I/O")
+ ru_nswap = _structseq.structseqfield(8, "number of swap outs")
+ ru_inblock = _structseq.structseqfield(9, "block input operations")
+ ru_oublock = _structseq.structseqfield(10, "block output operations")
+ ru_msgsnd = _structseq.structseqfield(11, "IPC messages sent")
+ ru_msgrcv = _structseq.structseqfield(12, "IPC messages received")
+ ru_nsignals = _structseq.structseqfield(13,"signals received")
+ ru_nvcsw = _structseq.structseqfield(14, "voluntary context switches")
+ ru_nivcsw = _structseq.structseqfield(15, "involuntary context switches")
- def __float__(self):
- return self.tv_sec + self.tv_usec/1000000.0
-
-class _struct_rusage(Structure):
- _fields_ = (
- ("ru_utime", timeval),
- ("ru_stime", timeval),
- ("ru_maxrss", c_long),
- ("ru_ixrss", c_long),
- ("ru_idrss", c_long),
- ("ru_isrss", c_long),
- ("ru_minflt", c_long),
- ("ru_majflt", c_long),
- ("ru_nswap", c_long),
- ("ru_inblock", c_long),
- ("ru_oublock", c_long),
- ("ru_msgsnd", c_long),
- ("ru_msgrcv", c_long),
- ("ru_nsignals", c_long),
- ("ru_nvcsw", c_long),
- ("ru_nivcsw", c_long),
- )
-
-_getrusage.argtypes = (c_int, POINTER(_struct_rusage))
-_getrusage.restype = c_int
-
-
-class struct_rusage(metaclass=_structseq.structseqtype):
- ru_utime = _structseq.structseqfield(0)
- ru_stime = _structseq.structseqfield(1)
- ru_maxrss = _structseq.structseqfield(2)
- ru_ixrss = _structseq.structseqfield(3)
- ru_idrss = _structseq.structseqfield(4)
- ru_isrss = _structseq.structseqfield(5)
- ru_minflt = _structseq.structseqfield(6)
- ru_majflt = _structseq.structseqfield(7)
- ru_nswap = _structseq.structseqfield(8)
- ru_inblock = _structseq.structseqfield(9)
- ru_oublock = _structseq.structseqfield(10)
- ru_msgsnd = _structseq.structseqfield(11)
- ru_msgrcv = _structseq.structseqfield(12)
- ru_nsignals = _structseq.structseqfield(13)
- ru_nvcsw = _structseq.structseqfield(14)
- ru_nivcsw = _structseq.structseqfield(15)
-
-@builtinify
-def rlimit_check_bounds(rlim_cur, rlim_max):
- if rlim_cur > rlim_t_max:
- raise ValueError("%d does not fit into rlim_t" % rlim_cur)
- if rlim_max > rlim_t_max:
- raise ValueError("%d does not fit into rlim_t" % rlim_max)
-
-class rlimit(Structure):
- _fields_ = (
- ("rlim_cur", rlim_t),
- ("rlim_max", rlim_t),
- )
-
-_getrlimit.argtypes = (c_int, POINTER(rlimit))
-_getrlimit.restype = c_int
-_setrlimit.argtypes = (c_int, POINTER(rlimit))
-_setrlimit.restype = c_int
-
-
-@builtinify
-def getrusage(who):
- ru = _struct_rusage()
- ret = _getrusage(who, byref(ru))
- if ret == -1:
- errno = get_errno()
- if errno == EINVAL:
- raise ValueError("invalid who parameter")
- raise error(errno)
+def _make_struct_rusage(ru):
return struct_rusage((
- float(ru.ru_utime),
- float(ru.ru_stime),
+ lib.my_utime(ru),
+ lib.my_stime(ru),
ru.ru_maxrss,
ru.ru_ixrss,
ru.ru_idrss,
@@ -133,48 +59,59 @@
))
@builtinify
+def getrusage(who):
+ ru = ffi.new("struct rusage *")
+ if lib.getrusage(who, ru) == -1:
+ if ffi.errno == EINVAL:
+ raise ValueError("invalid who parameter")
+ raise error(ffi.errno)
+ return _make_struct_rusage(ru)
+
+@builtinify
def getrlimit(resource):
- if not(0 <= resource < RLIM_NLIMITS):
+ if not (0 <= resource < lib.RLIM_NLIMITS):
return ValueError("invalid resource specified")
- rlim = rlimit()
- ret = _getrlimit(resource, byref(rlim))
- if ret == -1:
- errno = get_errno()
- raise error(errno)
- return (rlim.rlim_cur, rlim.rlim_max)
+ result = ffi.new("long long[2]")
+ if lib.my_getrlimit(resource, result) == -1:
+ raise error(ffi.errno)
+ return (result[0], result[1])
@builtinify
-def setrlimit(resource, rlim):
- if not(0 <= resource < RLIM_NLIMITS):
+def setrlimit(resource, limits):
+ if not (0 <= resource < lib.RLIM_NLIMITS):
return ValueError("invalid resource specified")
- rlimit_check_bounds(*rlim)
- rlim = rlimit(rlim[0], rlim[1])
- ret = _setrlimit(resource, byref(rlim))
- if ret == -1:
- errno = get_errno()
- if errno == EINVAL:
- return ValueError("current limit exceeds maximum limit")
- elif errno == EPERM:
- return ValueError("not allowed to raise maximum limit")
+ limits = tuple(limits)
+ if len(limits) != 2:
+ raise ValueError("expected a tuple of 2 integers")
+
+ if lib.my_setrlimit(resource, limits[0], limits[1]) == -1:
+ if ffi.errno == EINVAL:
+ raise ValueError("current limit exceeds maximum limit")
+ elif ffi.errno == EPERM:
+ raise ValueError("not allowed to raise maximum limit")
else:
- raise error(errno)
+ raise error(ffi.errno)
+
@builtinify
def getpagesize():
- if _getpagesize:
- return _getpagesize()
- else:
- try:
- return sysconf("SC_PAGE_SIZE")
- except ValueError:
- # Irix 5.3 has _SC_PAGESIZE, but not _SC_PAGE_SIZE
- return sysconf("SC_PAGESIZE")
+ return os.sysconf("SC_PAGESIZE")
-__all__ = ALL_CONSTANTS + (
- 'error', 'timeval', 'struct_rusage', 'rlimit',
- 'getrusage', 'getrlimit', 'setrlimit', 'getpagesize',
+
+def _setup():
+ all_constants = []
+ p = lib.my_rlimit_consts
+ while p.name:
+ name = ffi.string(p.name)
+ globals()[name] = int(p.value)
+ all_constants.append(name)
+ p += 1
+ return all_constants
+
+__all__ = tuple(_setup()) + (
+ 'error', 'getpagesize', 'struct_rusage',
+ 'getrusage', 'getrlimit', 'setrlimit',
)
-
-del ALL_CONSTANTS
+del _setup
diff --git a/pypy/goal/targetpypystandalone.py
b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -344,10 +344,6 @@
return PyPyJitPolicy(pypy_hooks)
def get_entry_point(self, config):
- from pypy.tool.lib_pypy import import_from_lib_pypy
- rebuild = import_from_lib_pypy('ctypes_config_cache/rebuild')
- rebuild.try_rebuild()
-
space = make_objspace(config)
# manually imports app_main.py
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
@@ -1353,8 +1353,8 @@
ffi = FFI(backend=self.Backend())
ffi.cdef("enum foo;")
from cffi import __version_info__
- if __version_info__ < (1, 6):
- py.test.skip("re-enable me in version 1.6")
+ if __version_info__ < (1, 7):
+ py.test.skip("re-enable me in version 1.7")
e = py.test.raises(CDefError, ffi.cast, "enum foo", -1)
assert str(e.value) == (
"'enum foo' has no values explicitly defined: refusing to guess "
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
@@ -1511,7 +1511,9 @@
void boz(void);
}
""")
- lib = verify(ffi, 'test_extern_python_1', "")
+ lib = verify(ffi, 'test_extern_python_1', """
+ static void baz(int, int); /* forward */
+ """)
assert ffi.typeof(lib.bar) == ffi.typeof("int(*)(int, int)")
with FdWriteCapture() as f:
res = lib.bar(4, 5)
@@ -1745,6 +1747,35 @@
assert lib.mycb1(200) == 242
assert lib.indirect_call(300) == 342
+def test_extern_python_plus_c():
+ ffi = FFI()
+ ffi.cdef("""
+ extern "Python+C" int foo(int);
+ extern "C +\tPython" int bar(int);
+ int call_me(int);
+ """)
+ lib = verify(ffi, 'test_extern_python_plus_c', """
+ int foo(int);
+ #ifdef __GNUC__
+ __attribute__((visibility("hidden")))
+ #endif
+ int bar(int);
+
+ static int call_me(int x) {
+ return foo(x) - bar(x);
+ }
+ """)
+ #
+ @ffi.def_extern()
+ def foo(x):
+ return x * 42
+ @ffi.def_extern()
+ def bar(x):
+ return x * 63
+ assert lib.foo(100) == 4200
+ assert lib.bar(100) == 6300
+ assert lib.call_me(100) == -2100
+
def test_introspect_function():
ffi = FFI()
ffi.cdef("float f1(double);")
diff --git a/pypy/module/test_lib_pypy/cffi_tests/embedding/empty.py
b/pypy/module/test_lib_pypy/cffi_tests/embedding/empty.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/test_lib_pypy/cffi_tests/embedding/empty.py
@@ -0,0 +1,11 @@
+# Generated by pypy/tool/import_cffi.py
+import cffi
+
+ffi = cffi.FFI()
+
+ffi.embedding_api("")
+
+ffi.set_source("_empty_cffi", "")
+
+fn = ffi.compile(verbose=True)
+print('FILENAME: %s' % (fn,))
diff --git a/pypy/module/test_lib_pypy/test_collections.py
b/pypy/module/test_lib_pypy/test_collections.py
--- a/pypy/module/test_lib_pypy/test_collections.py
+++ b/pypy/module/test_lib_pypy/test_collections.py
@@ -62,6 +62,12 @@
raises(IndexError, d.remove, 'c')
assert len(d) == 0
+ def test_deque_unhashable(self):
+ from collections import Hashable
+ d = self.get_deque()
+ raises(TypeError, hash, d)
+ assert not isinstance(d, Hashable)
+
class AppTestDequeExtra:
spaceconfig = dict(usemodules=('binascii', 'struct',))
diff --git a/pypy/module/test_lib_pypy/test_ctypes_config_cache.py
b/pypy/module/test_lib_pypy/test_ctypes_config_cache.py
deleted file mode 100644
--- a/pypy/module/test_lib_pypy/test_ctypes_config_cache.py
+++ /dev/null
@@ -1,44 +0,0 @@
-import py
-import sys, os
-from rpython.tool.udir import udir
-
-dirpath = py.path.local(__file__).dirpath().dirpath().dirpath().dirpath()
-dirpath = dirpath.join('lib_pypy').join('ctypes_config_cache')
-
-
-def run(filename, outputname):
- filepath = dirpath.join(filename)
- tmpdir = udir.ensure('testcache-' + os.path.splitext(filename)[0],
- dir=True)
- tmpdir.join('dumpcache.py').write(dirpath.join('dumpcache.py').read())
- path = sys.path[:]
- sys.modules.pop('dumpcache', None)
- try:
- sys.path.insert(0, str(tmpdir))
- execfile(str(filepath), {})
- finally:
- sys.path[:] = path
- sys.modules.pop('dumpcache', None)
- #
- outputpath = tmpdir.join(outputname)
- assert outputpath.check(exists=1)
- modname = os.path.splitext(outputname)[0]
- try:
- sys.path.insert(0, str(tmpdir))
- d = {}
- execfile(str(outputpath), d)
- finally:
- sys.path[:] = path
- return d
-
-
-def test_resource():
- if sys.platform == 'win32':
- py.test.skip('no resource module on this platform')
- d = run('resource.ctc.py', '_resource_cache.py')
- assert 'RLIM_NLIMITS' in d
-
-def test_locale():
- d = run('locale.ctc.py', '_locale_cache.py')
- assert 'LC_ALL' in d
- assert 'CHAR_MAX' in d
diff --git a/pypy/module/test_lib_pypy/test_os_wait.py
b/pypy/module/test_lib_pypy/test_os_wait.py
--- a/pypy/module/test_lib_pypy/test_os_wait.py
+++ b/pypy/module/test_lib_pypy/test_os_wait.py
@@ -1,52 +1,36 @@
-# Generates the resource cache (it might be there already, but maybe not)
+# Assumes that _resource_cffi is there already
from __future__ import absolute_import
import os
+import py
+from pypy.module.test_lib_pypy import test_resource # side-effect: skip()
-import py
-from lib_pypy.ctypes_config_cache import rebuild
-from pypy.module.test_lib_pypy.support import import_lib_pypy
+from lib_pypy import _pypy_wait
+def test_os_wait3():
+ wait3 = _pypy_wait.wait3
+ exit_status = 0x33
+ child = os.fork()
+ if child == 0: # in child
+ os._exit(exit_status)
+ else:
+ pid, status, rusage = wait3(0)
+ assert child == pid
+ assert os.WIFEXITED(status)
+ assert os.WEXITSTATUS(status) == exit_status
+ assert isinstance(rusage.ru_utime, float)
+ assert isinstance(rusage.ru_maxrss, int)
-class AppTestOsWait:
-
- spaceconfig = dict(usemodules=('_rawffi', 'fcntl', 'itertools', 'select',
- 'signal', '_posixsubprocess'))
-
- def setup_class(cls):
- if not hasattr(os, "fork"):
- py.test.skip("Need fork() to test wait3/wait4()")
- rebuild.rebuild_one('resource.ctc.py')
- cls.space.appexec([], "(): import ctypes")
- cls.w__pypy_wait = import_lib_pypy(
- cls.space, '_pypy_wait')
-
- def test_os_wait3(self):
- import os
- wait3 = self._pypy_wait.wait3
- exit_status = 0x33
- child = os.fork()
- if child == 0: # in child
- os._exit(exit_status)
- else:
- pid, status, rusage = wait3(0)
- assert child == pid
- assert os.WIFEXITED(status)
- assert os.WEXITSTATUS(status) == exit_status
- assert isinstance(rusage.ru_utime, float)
- assert isinstance(rusage.ru_maxrss, int)
-
- def test_os_wait4(self):
- import os
- wait4 = self._pypy_wait.wait4
- exit_status = 0x33
- child = os.fork()
- if child == 0: # in child
- os._exit(exit_status)
- else:
- pid, status, rusage = wait4(child, 0)
- assert child == pid
- assert os.WIFEXITED(status)
- assert os.WEXITSTATUS(status) == exit_status
- assert isinstance(rusage.ru_utime, float)
- assert isinstance(rusage.ru_maxrss, int)
+def test_os_wait4():
+ wait4 = _pypy_wait.wait4
+ exit_status = 0x33
+ child = os.fork()
+ if child == 0: # in child
+ os._exit(exit_status)
+ else:
+ pid, status, rusage = wait4(child, 0)
+ assert child == pid
+ assert os.WIFEXITED(status)
+ assert os.WEXITSTATUS(status) == exit_status
+ assert isinstance(rusage.ru_utime, float)
+ assert isinstance(rusage.ru_maxrss, int)
diff --git a/pypy/module/test_lib_pypy/test_resource.py
b/pypy/module/test_lib_pypy/test_resource.py
--- a/pypy/module/test_lib_pypy/test_resource.py
+++ b/pypy/module/test_lib_pypy/test_resource.py
@@ -1,45 +1,49 @@
from __future__ import absolute_import
-from lib_pypy.ctypes_config_cache import rebuild
-from pypy.module.test_lib_pypy.support import import_lib_pypy
-
import os
if os.name != 'posix':
skip('resource.h only available on unix')
-class AppTestResource:
+try:
+ from lib_pypy import resource
+except ImportError as e:
+ skip(str(e))
- spaceconfig = dict(usemodules=('_rawffi', 'fcntl', 'itertools', 'select',
- 'signal'))
- def setup_class(cls):
- rebuild.rebuild_one('resource.ctc.py')
- cls.w_resource = import_lib_pypy(cls.space, 'resource',
- 'No resource module available')
+def test_getrusage():
+ x = resource.getrusage(resource.RUSAGE_SELF)
+ assert len(x) == 16
+ assert x[0] == x[-16] == x.ru_utime
+ assert x[1] == x[-15] == x.ru_stime
+ assert x[2] == x[-14] == x.ru_maxrss
+ assert x[3] == x[-13] == x.ru_ixrss
+ assert x[4] == x[-12] == x.ru_idrss
+ assert x[5] == x[-11] == x.ru_isrss
+ assert x[6] == x[-10] == x.ru_minflt
+ assert x[7] == x[-9] == x.ru_majflt
+ assert x[8] == x[-8] == x.ru_nswap
+ assert x[9] == x[-7] == x.ru_inblock
+ assert x[10] == x[-6] == x.ru_oublock
+ assert x[11] == x[-5] == x.ru_msgsnd
+ assert x[12] == x[-4] == x.ru_msgrcv
+ assert x[13] == x[-3] == x.ru_nsignals
+ assert x[14] == x[-2] == x.ru_nvcsw
+ assert x[15] == x[-1] == x.ru_nivcsw
+ for i in range(16):
+ if i < 2:
+ expected_type = float
+ else:
+ expected_type = int
+ assert isinstance(x[i], expected_type)
- def test_resource(self):
- resource = self.resource
- x = resource.getrusage(resource.RUSAGE_SELF)
- assert len(x) == 16
- assert x[0] == x[-16] == x.ru_utime
- assert x[1] == x[-15] == x.ru_stime
- assert x[2] == x[-14] == x.ru_maxrss
- assert x[3] == x[-13] == x.ru_ixrss
- assert x[4] == x[-12] == x.ru_idrss
- assert x[5] == x[-11] == x.ru_isrss
- assert x[6] == x[-10] == x.ru_minflt
- assert x[7] == x[-9] == x.ru_majflt
- assert x[8] == x[-8] == x.ru_nswap
- assert x[9] == x[-7] == x.ru_inblock
- assert x[10] == x[-6] == x.ru_oublock
- assert x[11] == x[-5] == x.ru_msgsnd
- assert x[12] == x[-4] == x.ru_msgrcv
- assert x[13] == x[-3] == x.ru_nsignals
- assert x[14] == x[-2] == x.ru_nvcsw
- assert x[15] == x[-1] == x.ru_nivcsw
- for i in range(16):
- if i < 2:
- expected_type = float
- else:
- expected_type = int
- assert isinstance(x[i], expected_type)
+def test_getrlimit():
+ x = resource.getrlimit(resource.RLIMIT_CPU)
+ assert isinstance(x, tuple)
+ assert len(x) == 2
+ assert isinstance(x[0], int)
+ assert isinstance(x[1], int)
+
+def test_setrlimit():
+ # minimal "does not crash" test
+ x = resource.getrlimit(resource.RLIMIT_CPU)
+ resource.setrlimit(resource.RLIMIT_CPU, x)
diff --git a/pypy/tool/build_cffi_imports.py b/pypy/tool/build_cffi_imports.py
--- a/pypy/tool/build_cffi_imports.py
+++ b/pypy/tool/build_cffi_imports.py
@@ -13,6 +13,7 @@
"syslog": "_syslog_build.py" if sys.platform != "win32" else None,
"_gdbm": "_gdbm_build.py" if sys.platform != "win32" else None,
"pwdgrp": "_pwdgrp_build.py" if sys.platform != "win32" else None,
+ "resource": "_resource_build.py" if sys.platform != "win32" else None,
"lzma": "_lzma_build.py",
"_decimal": "_decimal_build.py",
"xx": None, # for testing: 'None' should be completely ignored
diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -172,6 +172,7 @@
# Careful: to copy lib_pypy, copying just the hg-tracked files
# would not be enough: there are also ctypes_config_cache/_*_cache.py.
+ # XXX ^^^ this is no longer true!
shutil.copytree(str(basedir.join('lib-python').join(STDLIB_VER)),
str(pypydir.join('lib-python').join(STDLIB_VER)),
ignore=ignore_patterns('.svn', 'py', '*.pyc', '*~'))
diff --git a/rpython/jit/backend/zarch/regalloc.py
b/rpython/jit/backend/zarch/regalloc.py
--- a/rpython/jit/backend/zarch/regalloc.py
+++ b/rpython/jit/backend/zarch/regalloc.py
@@ -182,9 +182,9 @@
"""
self._check_type(origvar)
prev_loc = self.loc(origvar, must_exist=must_exist)
- var2 = TempVar()
+ var2 = TempInt()
if bindvar is None:
- bindvar = TempVar()
+ bindvar = TempInt()
if bind_first:
loc, loc2 = self.force_allocate_reg_pair(bindvar, var2,
self.temp_boxes)
else:
@@ -310,20 +310,22 @@
# uff! in this case, we need to move a forbidden var to another
register
assert len(forbidden_vars) <= 8 # otherwise it is NOT possible to
complete
even, odd = r.r2, r.r3
- even_var = reverse_mapping.get(even, None)
- odd_var = reverse_mapping.get(odd, None)
- if even_var:
- if even_var in forbidden_vars:
- self._relocate_forbidden_variable(even, even_var,
reverse_mapping,
+ old_even_var = reverse_mapping.get(even, None)
+ old_odd_var = reverse_mapping.get(odd, None)
+ if old_even_var:
+ if old_even_var in forbidden_vars:
+ self._relocate_forbidden_variable(even, old_even_var,
reverse_mapping,
forbidden_vars, odd)
else:
- self._sync_var(even_var)
- if odd_var:
- if odd_var in forbidden_vars:
- self._relocate_forbidden_variable(odd, odd_var,
reverse_mapping,
+ self._sync_var(old_even_var)
+ del self.reg_bindings[old_even_var]
+ if old_odd_var:
+ if old_odd_var in forbidden_vars:
+ self._relocate_forbidden_variable(odd, old_odd_var,
reverse_mapping,
forbidden_vars, even)
else:
- self._sync_var(odd_var)
+ self._sync_var(old_odd_var)
+ del self.reg_bindings[old_odd_var]
self.free_regs = [fr for fr in self.free_regs \
if fr is not even and \
@@ -335,6 +337,12 @@
return even, odd
def _relocate_forbidden_variable(self, reg, var, reverse_mapping,
forbidden_vars, forbidden_reg):
+ if len(self.free_regs) > 0:
+ candidate = self.free_regs.pop()
+ self.assembler.regalloc_mov(reg, candidate)
+ self.reg_bindings[var] = candidate
+ reverse_mapping[candidate] = var
+
for candidate in r.MANAGED_REGS:
# move register of var to another register
# thus it is not allowed to bei either reg or forbidden_reg
@@ -345,9 +353,11 @@
if not candidate_var or candidate_var not in forbidden_vars:
if candidate_var is not None:
self._sync_var(candidate_var)
+ del self.reg_bindings[candidate_var]
self.assembler.regalloc_mov(reg, candidate)
+ assert var is not None
self.reg_bindings[var] = candidate
- reverse_mapping[reg] = var
+ reverse_mapping[candidate] = var
self.free_regs.append(reg)
break
else:
diff --git a/rpython/rlib/rposix_stat.py b/rpython/rlib/rposix_stat.py
--- a/rpython/rlib/rposix_stat.py
+++ b/rpython/rlib/rposix_stat.py
@@ -94,7 +94,8 @@
return self.__class__,
def getattr(self, s_attr):
- assert s_attr.is_constant(), "non-constant attr name in getattr()"
+ if not s_attr.is_constant():
+ raise annmodel.AnnotatorError("non-constant attr name in
getattr()")
attrname = s_attr.const
TYPE = STAT_FIELD_TYPES[attrname]
return lltype_to_annotation(TYPE)
diff --git a/rpython/rlib/test/test_rthread.py
b/rpython/rlib/test/test_rthread.py
--- a/rpython/rlib/test/test_rthread.py
+++ b/rpython/rlib/test/test_rthread.py
@@ -287,7 +287,12 @@
wr_from_thread.seen = False
start_new_thread(thread_entry_point, ())
wr1 = f()
- time.sleep(0.5)
+ count = 0
+ while True:
+ time.sleep(0.5)
+ if wr_from_thread.seen or count >= 50:
+ break
+ count += 1
assert wr_from_thread.seen is True
wr2 = wr_from_thread.wr
import gc; gc.collect() # wr2() should be collected here
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit