[pypy-commit] pypy vmprof: disable vmprof around fork(), and re-enable it only in the parent process

antocuni noreply at buildbot.pypy.org
Tue Mar 24 19:01:50 CET 2015


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: vmprof
Changeset: r76540:78914547f680
Date: 2015-03-24 19:01 +0100
http://bitbucket.org/pypy/pypy/changeset/78914547f680/

Log:	disable vmprof around fork(), and re-enable it only in the parent
	process

diff --git a/pypy/module/_vmprof/src/vmprof.c b/pypy/module/_vmprof/src/vmprof.c
--- a/pypy/module/_vmprof/src/vmprof.c
+++ b/pypy/module/_vmprof/src/vmprof.c
@@ -26,6 +26,7 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <errno.h>
+#include <pthread.h>
 
 #define UNW_LOCAL_ONLY
 #include <libunwind.h>
@@ -44,6 +45,8 @@
 void* vmprof_mainloop_func;
 static ptrdiff_t mainloop_sp_offset;
 static vmprof_get_virtual_ip_t mainloop_get_virtual_ip;
+static long last_period_usec = 0;
+static int atfork_hook_installed = 0;
 
 
 /* *************************************************************
@@ -275,6 +278,7 @@
 
 static int install_sigprof_timer(long period_usec) {
     static struct itimerval timer;
+    last_period_usec = period_usec;
     timer.it_interval.tv_sec = 0;
     timer.it_interval.tv_usec = period_usec;
     timer.it_value = timer.it_interval;
@@ -295,6 +299,34 @@
 	return 0;
 }
 
+static void atfork_disable_timer(void) {
+    remove_sigprof_timer();
+}
+
+static void atfork_enable_timer(void) {
+    install_sigprof_timer(last_period_usec);
+}
+
+static int install_pthread_atfork_hooks(void) {
+    /* this is needed to prevent the problems described there:
+         - http://code.google.com/p/gperftools/issues/detail?id=278
+         - http://lists.debian.org/debian-glibc/2010/03/msg00161.html
+
+        TL;DR: if the RSS of the process is large enough, the clone() syscall
+        will be interrupted by the SIGPROF before it can complete, then
+        retried, interrupted again and so on, in an endless loop.  The
+        solution is to disable the timer around the fork, and re-enable it
+        only inside the parent.
+    */
+    if (atfork_hook_installed)
+        return 0;
+    int ret = pthread_atfork(atfork_disable_timer, atfork_enable_timer, NULL);
+    if (ret != 0)
+        return -1;
+    atfork_hook_installed = 1;
+    return 0;
+}
+
 /* *************************************************************
  * public API
  * *************************************************************
@@ -321,6 +353,9 @@
     if (install_sigprof_timer(period_usec) == -1) {
 		return -1;
 	}
+    if (install_pthread_atfork_hooks() == -1) {
+        return -1;
+    }
 	return 0;
 }
 


More information about the pypy-commit mailing list