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

Reply via email to