Author: Manuel Jacob Branch: refactor-str-types Changeset: r66312:49e961a18a14 Date: 2013-08-25 14:07 +0100 http://bitbucket.org/pypy/pypy/changeset/49e961a18a14/
Log: hg merge default diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst --- a/pypy/doc/windows.rst +++ b/pypy/doc/windows.rst @@ -6,6 +6,10 @@ The following text gives some hints about how to translate the PyPy interpreter. +PyPy supports only being translated as a 32bit program, even on +64bit Windows. See at the end of this page for what is missing +for a full 64bit translation. + To build pypy-c you need a C compiler. Microsoft Visual Studio is preferred, but can also use the mingw32 port of gcc. @@ -63,7 +67,7 @@ INCLUDE, LIB and PATH (for DLLs) environment variables appropriately. Abridged method (for -Ojit builds using Visual Studio 2008) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Download the versions of all the external packages from https://bitbucket.org/pypy/pypy/downloads/local.zip @@ -112,13 +116,14 @@ nmake -f makefile.msc The sqlite3 database library -~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Download http://www.sqlite.org/2013/sqlite-amalgamation-3071601.zip and extract it into a directory under the base directory. Also get http://www.sqlite.org/2013/sqlite-dll-win32-x86-3071601.zip and extract the dll into the bin directory, and the sqlite3.def into the sources directory. Now build the import library so cffi can use the header and dll:: + lib /DEF:sqlite3.def" /OUT:sqlite3.lib" copy sqlite3.lib path\to\libs @@ -206,8 +211,86 @@ March 2012, --cc is not a valid option for pytest.py. However if you set an environment variable CC to the compliter exe, testing will use it. -.. _'mingw32 build': http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Automated%20Builds +.. _`mingw32 build`: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Automated%20Builds .. _`mingw64 build`: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Automated%20Builds .. _`msys for mingw`: http://sourceforge.net/projects/mingw-w64/files/External%20binary%20packages%20%28Win64%20hosted%29/MSYS%20%2832-bit%29 .. _`libffi source files`: http://sourceware.org/libffi/ .. _`RPython translation toolchain`: translation.html + + +What is missing for a full 64-bit translation +--------------------------------------------- + +The main blocker is that we assume that the integer type of RPython is +large enough to (occasionally) contain a pointer value cast to an +integer. The simplest fix is to make sure that it is so, but it will +give the following incompatibility between CPython and PyPy on Win64: + +CPython: ``sys.maxint == 2**32-1, sys.maxsize == 2**64-1`` + +PyPy: ``sys.maxint == sys.maxsize == 2**64-1`` + +...and, correspondingly, PyPy supports ints up to the larger value of +sys.maxint before they are converted to ``long``. The first decision +that someone needs to make is if this incompatibility is reasonable. + +Assuming that it is, the first thing to do is probably to hack *CPython* +until it fits this model: replace the field in PyIntObject with a ``long +long`` field, and change the value of ``sys.maxint``. This might just +work, even if half-brokenly: I'm sure you can crash it because of the +precision loss that undoubtedly occurs everywhere, but try not to. :-) + +Such a hacked CPython is what you'll use in the next steps. We'll call +it CPython64/64. + +It is probably not too much work if the goal is only to get a translated +PyPy executable, and to run all tests before transaction. But you need +to start somewhere, and you should start with some tests in +rpython/translator/c/test/, like ``test_standalone.py`` and +``test_newgc.py``: try to have them pass on top of CPython64/64. + +Keep in mind that this runs small translations, and some details may go +wrong. The most obvious one is to check that it produces C files that +use the integer type ``Signed`` --- but what is ``Signed`` defined to? +It should be equal to ``long`` on every other platforms, but on Win64 it +should be something like ``long long``. + +What is more generally needed is to review all the C files in +rpython/translator/c/src for the word ``long``, because this means a +32-bit integer even on Win64. Replace it with ``Signed`` most of the +times. You can replace one with the other without breaking anything on +any other platform, so feel free to. + +Then, these two C types have corresponding RPython types: ``rffi.LONG`` +and ``lltype.Signed`` respectively. The first should really correspond +to the C ``long``. Add tests that check that integers casted to one +type or the other really have 32 and 64 bits respectively, on Win64. + +Once these basic tests work, you need to review ``rpython/rlib/`` for +usages of ``rffi.LONG`` versus ``lltype.Signed``. The goal would be to +fix some more ``LONG-versus-Signed`` issues, by fixing the tests --- as +always run on top of CPython64/64. Note that there was some early work +done in ``rpython/rlib/rarithmetic`` with the goal of running all the +tests on Win64 on the regular CPython, but I think by now that it's a +bad idea. Look only at CPython64/64. + +The major intermediate goal is to get a translation of PyPy with ``-O2`` +with a minimal set of modules, starting with ``--no-allworkingmodules``; +you need to use CPython64/64 to run this translation too. Check +carefully the warnings of the C compiler at the end. I think that MSVC +is "nice" in the sense that by default a lot of mismatches of integer +sizes are reported as warnings. + +Then you need to review ``pypy/module/*/`` for ``LONG-versus-Signed`` +issues. At some time during this review, we get a working translated +PyPy on Windows 64 that includes all ``--translationmodules``, i.e. +everything needed to run translations. When we are there, the hacked +CPython64/64 becomes much less important, because we can run future +translations on top of this translated PyPy. As soon as we get there, +please *distribute* the translated PyPy. It's an essential component +for anyone else that wants to work on Win64! We end up with a strange +kind of dependency --- we need a translated PyPy in order to translate a +PyPy ---, but I believe it's ok here, as Windows executables are +supposed to never be broken by newer versions of Windows. + +Happy hacking :-) diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -685,7 +685,7 @@ name='string', char='S', w_box_type = space.gettypefor(interp_boxes.W_StringBox), - alternate_constructors=[space.w_str], + alternate_constructors=[space.w_str, space.gettypefor(interp_boxes.W_CharacterBox)], aliases=["str"], ) self.w_unicodedtype = W_Dtype( diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -781,7 +781,7 @@ def test_character_dtype(self): from numpypy import array, character x = array([["A", "B"], ["C", "D"]], character) - assert x == [["A", "B"], ["C", "D"]] + assert (x == [["A", "B"], ["C", "D"]]).all() class AppTestRecordDtypes(BaseNumpyAppTest): spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -272,7 +272,7 @@ assert rint(complex(inf, 1.5)) == complex(inf, 2.) assert rint(complex(0.5, inf)) == complex(0., inf) - assert rint(sys.maxint) == sys.maxint + assert rint(sys.maxint) > 0.0 def test_sign(self): from numpypy import array, sign, dtype diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -308,13 +308,6 @@ return min(v1, v2) @simple_unary_op - def rint(self, v): - if isfinite(float(v)): - return rfloat.round_double(float(v), 0, half_even=True) - else: - return v - - @simple_unary_op def ones_like(self, v): return 1 @@ -322,6 +315,10 @@ def zeros_like(self, v): return 0 + @raw_unary_op + def rint(self, v): + float64 = Float64() + return float64.rint(float64.box(v)) class NonNativePrimitive(Primitive): _mixin_ = True @@ -1036,6 +1033,25 @@ else: return v1 + v2 + @simple_unary_op + def rint(self, v): + x = float(v) + if isfinite(x): + import math + y = math.floor(x) + r = x - y + + if r > 0.5: + y += 1.0 + + if r == 0.5: + r = y - 2.0 * math.floor(0.5 * y) + if r == 1.0: + y += 1.0 + return y + else: + return x + class NonNativeFloat(NonNativePrimitive, Float): _mixin_ = True diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1277,10 +1277,7 @@ return _all_contained_in(space, self, w_other) return space.w_False - def descr_ne(self, space, w_other): - if not _is_set_like(w_other): - return space.w_NotImplemented - return space.not_(space.eq(self, w_other)) + descr_ne = negate(descr_eq) def descr_lt(self, space, w_other): if not _is_set_like(w_other): diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py --- a/pypy/objspace/std/intobject.py +++ b/pypy/objspace/std/intobject.py @@ -1,20 +1,22 @@ +"""The builtin int implementation + +In order to have the same behavior running on CPython, and after RPython +translation this module uses rarithmetic.ovfcheck to explicitly check +for overflows, something CPython does not do anymore. +""" + +from rpython.rlib import jit +from rpython.rlib.rarithmetic import LONG_BIT, is_valid_int, ovfcheck, r_uint +from rpython.rlib.rbigint import rbigint + from pypy.interpreter.error import OperationError from pypy.objspace.std import newformat from pypy.objspace.std.inttype import W_AbstractIntObject -from pypy.objspace.std.model import registerimplementation, W_Object +from pypy.objspace.std.model import W_Object, registerimplementation from pypy.objspace.std.multimethod import FailedToImplementArgs from pypy.objspace.std.noneobject import W_NoneObject from pypy.objspace.std.register_all import register_all -from rpython.rlib import jit -from rpython.rlib.rarithmetic import ovfcheck, LONG_BIT, r_uint, is_valid_int -from rpython.rlib.rbigint import rbigint -""" -In order to have the same behavior running -on CPython, and after RPython translation we use ovfcheck -from rarithmetic to explicitly check for overflows, -something CPython does not do anymore. -""" class W_IntObject(W_AbstractIntObject): __slots__ = 'intval' @@ -22,28 +24,29 @@ from pypy.objspace.std.inttype import int_typedef as typedef - def __init__(w_self, intval): + def __init__(self, intval): assert is_valid_int(intval) - w_self.intval = intval + self.intval = intval - def __repr__(w_self): - """ representation for debugging purposes """ - return "%s(%d)" % (w_self.__class__.__name__, w_self.intval) + def __repr__(self): + """representation for debugging purposes""" + return "%s(%d)" % (self.__class__.__name__, self.intval) - def unwrap(w_self, space): - return int(w_self.intval) + def unwrap(self, space): + return int(self.intval) int_w = unwrap - def uint_w(w_self, space): - intval = w_self.intval + def uint_w(self, space): + intval = self.intval if intval < 0: - raise OperationError(space.w_ValueError, - space.wrap("cannot convert negative integer to unsigned")) + raise OperationError( + space.w_ValueError, + space.wrap("cannot convert negative integer to unsigned")) else: return r_uint(intval) - def bigint_w(w_self, space): - return rbigint.fromint(w_self.intval) + def bigint_w(self, space): + return rbigint.fromint(self.intval) def float_w(self, space): return float(self.intval) @@ -144,7 +147,8 @@ x = float(w_int1.intval) y = float(w_int2.intval) if y == 0.0: - raise FailedToImplementArgs(space.w_ZeroDivisionError, space.wrap("float division")) + raise FailedToImplementArgs(space.w_ZeroDivisionError, + space.wrap("float division")) return space.wrap(x / y) def mod__Int_Int(space, w_int1, w_int2): diff --git a/pypy/objspace/std/longobject.py b/pypy/objspace/std/longobject.py --- a/pypy/objspace/std/longobject.py +++ b/pypy/objspace/std/longobject.py @@ -1,13 +1,17 @@ +"""The builtin long implementation""" + import sys + +from rpython.rlib.rbigint import rbigint + from pypy.interpreter.error import OperationError from pypy.objspace.std import model, newformat -from pypy.objspace.std.model import registerimplementation, W_Object +from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.longtype import W_AbstractLongObject, long_typedef +from pypy.objspace.std.model import W_Object, registerimplementation +from pypy.objspace.std.multimethod import FailedToImplementArgs +from pypy.objspace.std.noneobject import W_NoneObject from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplementArgs -from pypy.objspace.std.intobject import W_IntObject -from pypy.objspace.std.noneobject import W_NoneObject -from rpython.rlib.rbigint import rbigint -from pypy.objspace.std.longtype import long_typedef, W_AbstractLongObject class W_LongObject(W_AbstractLongObject): @@ -16,8 +20,8 @@ typedef = long_typedef - def __init__(w_self, l): - w_self.num = l # instance of rbigint + def __init__(self, l): + self.num = l # instance of rbigint def fromint(space, intval): return W_LongObject(rbigint.fromint(intval)) @@ -49,16 +53,16 @@ fromrarith_int._annspecialcase_ = "specialize:argtype(0)" fromrarith_int = staticmethod(fromrarith_int) - def int_w(w_self, space): + def int_w(self, space): try: - return w_self.num.toint() + return self.num.toint() except OverflowError: raise OperationError(space.w_OverflowError, space.wrap( "long int too large to convert to int")) - def uint_w(w_self, space): + def uint_w(self, space): try: - return w_self.num.touint() + return self.num.touint() except ValueError: raise OperationError(space.w_ValueError, space.wrap( "cannot convert negative integer to unsigned int")) @@ -66,8 +70,8 @@ raise OperationError(space.w_OverflowError, space.wrap( "long int too large to convert to unsigned int")) - def bigint_w(w_self, space): - return w_self.num + def bigint_w(self, space): + return self.num def float_w(self, space): return self.tofloat(space) @@ -324,7 +328,8 @@ sys.maxint == 2147483647) # binary ops -for opname in ['add', 'sub', 'mul', 'div', 'floordiv', 'truediv', 'mod', 'divmod', 'lshift']: +for opname in ['add', 'sub', 'mul', 'div', 'floordiv', 'truediv', 'mod', + 'divmod', 'lshift']: exec compile(""" def %(opname)s_ovr__Int_Int(space, w_int1, w_int2): if recover_with_smalllong(space) and %(opname)r != 'truediv': diff --git a/pypy/objspace/std/util.py b/pypy/objspace/std/util.py --- a/pypy/objspace/std/util.py +++ b/pypy/objspace/std/util.py @@ -9,10 +9,7 @@ tmp = f(self, space, w_other) if tmp is space.w_NotImplemented: return space.w_NotImplemented - elif tmp is space.w_False: - return space.w_True - else: - return space.w_False + return space.newbool(tmp is space.w_False) _negator.func_name = 'negate-%s' % f.func_name return _negator diff --git a/rpython/rlib/debug.py b/rpython/rlib/debug.py --- a/rpython/rlib/debug.py +++ b/rpython/rlib/debug.py @@ -196,6 +196,25 @@ return hop.genop('debug_flush', []) +def debug_forked(original_offset): + """ Call after a fork(), passing as argument the result of + debug_offset() called before the fork. + """ + pass + +class Entry(ExtRegistryEntry): + _about_ = debug_forked + + def compute_result_annotation(self, s_original_offset): + return None + + def specialize_call(self, hop): + from rpython.rtyper.lltypesystem import lltype + vlist = hop.inputargs(lltype.Signed) + hop.exception_cannot_occur() + return hop.genop('debug_forked', vlist) + + def llinterpcall(RESTYPE, pythonfunction, *args): """When running on the llinterp, this causes the llinterp to call to the provided Python function with the run-time value of the given args. diff --git a/rpython/rtyper/module/ll_os.py b/rpython/rtyper/module/ll_os.py --- a/rpython/rtyper/module/ll_os.py +++ b/rpython/rtyper/module/ll_os.py @@ -1566,7 +1566,7 @@ @registering_if(os, 'fork') def register_os_fork(self): - from rpython.rlib import rthread + from rpython.rlib import debug, rthread eci = self.gcc_profiling_bug_workaround('pid_t _noprof_fork(void)', 'return fork();') os_fork = self.llexternal('_noprof_fork', [], rffi.PID_T, @@ -1575,11 +1575,14 @@ def fork_llimpl(): # NB. keep forkpty() up-to-date, too + ofs = debug.debug_offset() opaqueaddr = rthread.gc_thread_before_fork() childpid = rffi.cast(lltype.Signed, os_fork()) rthread.gc_thread_after_fork(childpid, opaqueaddr) if childpid == -1: raise OSError(rposix.get_errno(), "os_fork failed") + if childpid == 0: + debug.debug_forked(ofs) return rffi.cast(lltype.Signed, childpid) return extdef([], int, llimpl=fork_llimpl, @@ -1610,7 +1613,7 @@ @registering_if(os, 'forkpty') def register_os_forkpty(self): - from rpython.rlib import rthread + from rpython.rlib import debug, rthread os_forkpty = self.llexternal( 'forkpty', [rffi.INTP, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP], @@ -1619,6 +1622,7 @@ def forkpty_llimpl(): master_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') master_p[0] = rffi.cast(rffi.INT, -1) + ofs = debug.debug_offset() opaqueaddr = rthread.gc_thread_before_fork() childpid = rffi.cast(lltype.Signed, os_forkpty(master_p, None, None, None)) @@ -1627,6 +1631,8 @@ lltype.free(master_p, flavor='raw') if childpid == -1: raise OSError(rposix.get_errno(), "os_forkpty failed") + if childpid == 0: + debug.debug_forked(ofs) return (rffi.cast(lltype.Signed, childpid), rffi.cast(lltype.Signed, master_fd)) diff --git a/rpython/translator/c/gcc/trackgcroot.py b/rpython/translator/c/gcc/trackgcroot.py --- a/rpython/translator/c/gcc/trackgcroot.py +++ b/rpython/translator/c/gcc/trackgcroot.py @@ -489,7 +489,7 @@ 'pabs', 'pack', 'padd', 'palign', 'pand', 'pavg', 'pcmp', 'pextr', 'phadd', 'phsub', 'pinsr', 'pmadd', 'pmax', 'pmin', 'pmovmsk', 'pmul', 'por', 'psadb', 'pshuf', 'psign', 'psll', 'psra', 'psrl', - 'psub', 'punpck', 'pxor', + 'psub', 'punpck', 'pxor', 'pmovzx', 'pmovsx', 'pblend', # all vectors don't produce pointers 'v', # sign-extending moves should not produce GC pointers diff --git a/rpython/translator/c/src/debug_print.c b/rpython/translator/c/src/debug_print.c --- a/rpython/translator/c/src/debug_print.c +++ b/rpython/translator/c/src/debug_print.c @@ -23,16 +23,12 @@ static char *debug_start_colors_2 = ""; static char *debug_stop_colors = ""; static char *debug_prefix = NULL; +static char *debug_filename = NULL; +static char *debug_filename_with_fork = NULL; static void pypy_debug_open(void) { char *filename = getenv("PYPYLOG"); - if (filename) -#ifndef _WIN32 - unsetenv("PYPYLOG"); /* don't pass it to subprocesses */ -#else - putenv("PYPYLOG="); /* don't pass it to subprocesses */ -#endif if (filename && filename[0]) { char *colon = strchr(filename, ':'); @@ -52,7 +48,10 @@ filename = colon + 1; } if (strcmp(filename, "-") != 0) - pypy_debug_file = fopen(filename, "w"); + { + debug_filename = strdup(filename); + pypy_debug_file = fopen(filename, "w"); + } } if (!pypy_debug_file) { @@ -64,6 +63,12 @@ debug_stop_colors = "\033[0m"; } } + if (filename) +#ifndef _WIN32 + unsetenv("PYPYLOG"); /* don't pass it to subprocesses */ +#else + putenv("PYPYLOG="); /* don't pass it to subprocesses */ +#endif debug_ready = 1; } @@ -73,6 +78,7 @@ return -1; // note that we deliberately ignore errno, since -1 is fine // in case this is not a real file + fflush(pypy_debug_file); return ftell(pypy_debug_file); } @@ -82,6 +88,26 @@ pypy_debug_open(); } +void pypy_debug_forked(long original_offset) +{ + if (debug_filename != NULL) + { + char *filename = malloc(strlen(debug_filename) + 32); + fclose(pypy_debug_file); + pypy_debug_file = NULL; + if (filename == NULL) + return; /* bah */ + sprintf(filename, "%s.fork%ld", debug_filename, (long)getpid()); + pypy_debug_file = fopen(filename, "w"); + if (pypy_debug_file) + fprintf(pypy_debug_file, "FORKED: %ld %s\n", original_offset, + debug_filename_with_fork ? debug_filename_with_fork + : debug_filename); + free(debug_filename_with_fork); + debug_filename_with_fork = filename; + } +} + #ifndef _WIN32 diff --git a/rpython/translator/c/src/debug_print.h b/rpython/translator/c/src/debug_print.h --- a/rpython/translator/c/src/debug_print.h +++ b/rpython/translator/c/src/debug_print.h @@ -29,6 +29,7 @@ #define PYPY_DEBUG_START(cat) pypy_debug_start(cat) #define PYPY_DEBUG_STOP(cat) pypy_debug_stop(cat) #define OP_DEBUG_OFFSET(res) res = pypy_debug_offset() +#define OP_DEBUG_FORKED(ofs, _) pypy_debug_forked(ofs) #define OP_HAVE_DEBUG_PRINTS(r) r = (pypy_have_debug_prints & 1) #define OP_DEBUG_FLUSH() fflush(pypy_debug_file) @@ -39,6 +40,7 @@ void pypy_debug_start(const char *category); void pypy_debug_stop(const char *category); long pypy_debug_offset(void); +void pypy_debug_forked(long original_offset); extern long pypy_have_debug_prints; extern FILE *pypy_debug_file; diff --git a/rpython/translator/c/test/test_standalone.py b/rpython/translator/c/test/test_standalone.py --- a/rpython/translator/c/test/test_standalone.py +++ b/rpython/translator/c/test/test_standalone.py @@ -447,6 +447,57 @@ assert 'bar' == lines[1] assert 'foo}' in lines[2] + def test_debug_print_fork(self): + if not hasattr(os, 'fork'): + py.test.skip("requires fork()") + + def entry_point(argv): + debug_start("foo") + debug_print("test line") + childpid = os.fork() + debug_print("childpid =", childpid) + if childpid == 0: + childpid2 = os.fork() # double-fork + debug_print("childpid2 =", childpid2) + debug_stop("foo") + return 0 + t, cbuilder = self.compile(entry_point) + path = udir.join('test_debug_print_fork.log') + out, err = cbuilder.cmdexec("", err=True, + env={'PYPYLOG': ':%s' % path}) + assert not err + # + f = open(str(path), 'r') + lines = f.readlines() + f.close() + assert '{foo' in lines[0] + assert lines[1] == "test line\n" + offset1 = len(lines[0]) + len(lines[1]) + assert lines[2].startswith('childpid = ') + childpid = int(lines[2][11:]) + assert childpid != 0 + assert 'foo}' in lines[3] + assert len(lines) == 4 + # + f = open('%s.fork%d' % (path, childpid), 'r') + lines = f.readlines() + f.close() + assert lines[0] == 'FORKED: %d %s\n' % (offset1, path) + assert lines[1] == 'childpid = 0\n' + offset2 = len(lines[0]) + len(lines[1]) + assert lines[2].startswith('childpid2 = ') + childpid2 = int(lines[2][11:]) + assert childpid2 != 0 + assert 'foo}' in lines[3] + assert len(lines) == 4 + # + f = open('%s.fork%d' % (path, childpid2), 'r') + lines = f.readlines() + f.close() + assert lines[0] == 'FORKED: %d %s.fork%d\n' % (offset2, path, childpid) + assert lines[1] == 'childpid2 = 0\n' + assert 'foo}' in lines[2] + assert len(lines) == 3 def test_fatal_error(self): def g(x): _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit