Armin Rigo avatar Armin Rigo committed 9b31edf

(fijal, arigo)

Using "PYPYLOG=..:filename", on any fork(), it will now create a new
file "filename.forkCHILDPID", starting with

FORKED: <position> <parent filename>

Comments (0)

Files changed (5)

rpython/rlib/debug.py

         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.

rpython/rtyper/module/ll_os.py

 
     @registering_if(os, 'fork')
     def register_os_fork(self):
-        from rpython.rlib import rthread
+        from rpython.rlib import rthread, debug
         eci = self.gcc_profiling_bug_workaround('pid_t _noprof_fork(void)',
                                                 'return fork();')
         os_fork = self.llexternal('_noprof_fork', [], rffi.PID_T,
 
         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,
         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))
             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))
 

rpython/translator/c/src/debug_print.c

 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, ':');
           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)
     {
           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;
 }
 
     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);
 }
 
     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
 

rpython/translator/c/src/debug_print.h

 #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)
 
 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;

rpython/translator/c/test/test_standalone.py

         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):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.