Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r66304:9b31edfc3a5b Date: 2013-08-23 18:17 +0200 http://bitbucket.org/pypy/pypy/changeset/9b31edfc3a5b/
Log: (fijal, arigo) Using "PYPYLOG=..:filename", on any fork(), it will now create a new file "filename.forkCHILDPID", starting with FORKED: <position> <parent filename> 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 rthread, debug 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, @@ -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/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