Callgrind: fix interactive control after fork()

This fixes bug 134316: when an program in callgrind does
a fork, callgrind_control does show both now, and they
can be controlled separately.

However, missing in this patch is zeroing of cost centers
directly after the clone syscall in the child.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@6082 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/callgrind/command.c b/callgrind/command.c
index 10ad909..edbd6d5 100644
--- a/callgrind/command.c
+++ b/callgrind/command.c
@@ -48,20 +48,35 @@
 static Char* info_file = 0;
 static Char* dump_base = 0;
 
-static Bool command_inited = False;
+static Int thisPID = 0;
 
-void CLG_(init_command)(Char* dir, Char* dumps)
+/**
+ * Setup for interactive control of a callgrind run
+ */
+static void setup_control(void)
 {
-  Int fd = -1, size;
+  Int fd, size;
   SysRes res;
+  Char* dir, *dump_filename;
 
-  dump_base = dumps;
+  CLG_ASSERT(thisPID != 0);
 
+  fd = -1;
+  dir = CLG_(get_base_directory)();
+  dump_base = CLG_(get_dump_file_base)();
+
+  /* base name of dump files with PID ending */
+  size = VG_(strlen)(dump_base) + 10;
+  dump_filename = (char*) CLG_MALLOC(size);
+  CLG_ASSERT(dump_filename != 0);
+  VG_(sprintf)(dump_filename, "%s.%d", dump_base, thisPID);
+
+  /* name of command file */
   size = VG_(strlen)(dir) + VG_(strlen)(DEFAULT_COMMANDNAME) +10;
   command_file = (char*) CLG_MALLOC(size);
   CLG_ASSERT(command_file != 0);
   VG_(sprintf)(command_file, "%s/%s.%d",
-	       dir, DEFAULT_COMMANDNAME, VG_(getpid)());
+	       dir, DEFAULT_COMMANDNAME, thisPID);
 
   /* This is for compatibility with the "Force Now" Button of current
    * KCachegrind releases, as it doesn't use ".pid" to distinguish
@@ -76,7 +91,7 @@
   result_file = (char*) CLG_MALLOC(size);
   CLG_ASSERT(result_file != 0);
   VG_(sprintf)(result_file, "%s/%s.%d",
-	       dir, DEFAULT_RESULTNAME, VG_(getpid)());
+	       dir, DEFAULT_RESULTNAME, thisPID);
 
   /* If we get a command from a command file without .pid, use
    * a result file without .pid suffix
@@ -88,9 +103,10 @@
 
   info_file = (char*) CLG_MALLOC(VG_(strlen)(DEFAULT_INFONAME) + 10);
   CLG_ASSERT(info_file != 0);
-  VG_(sprintf)(info_file, "%s.%d", DEFAULT_INFONAME, VG_(getpid)());
+  VG_(sprintf)(info_file, "%s.%d", DEFAULT_INFONAME, thisPID);
 
-  CLG_DEBUG(1, "  dump file base: '%s'\n", dump_base);
+  CLG_DEBUG(1, "Setup for interactive control (PID: %d):\n", thisPID);
+  CLG_DEBUG(1, "  dump file base: '%s'\n", dump_filename);
   CLG_DEBUG(1, "  command file:   '%s'\n", command_file);
   CLG_DEBUG(1, "  result file:    '%s'\n", result_file);
   CLG_DEBUG(1, "  info file:      '%s'\n", info_file);
@@ -128,7 +144,7 @@
     VG_(sprintf)(buf, "base: %s\n", dir);
     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
     
-    VG_(sprintf)(buf, "dumps: %s\n", dump_base);
+    VG_(sprintf)(buf, "dumps: %s\n", dump_filename);
     VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
     
     VG_(sprintf)(buf, "control: %s\n", command_file);
@@ -149,8 +165,12 @@
     VG_(write)(fd, "\n", 1);
     VG_(close)(fd);
   }
+}
 
-  command_inited = True;
+void CLG_(init_command)()
+{
+  thisPID = VG_(getpid)();
+  setup_control();
 }
 
 void CLG_(finish_command)()
@@ -355,14 +375,31 @@
     Char *cmdPos = 0, *cmdNextLine = 0;
     Int fd, bytesRead = 0, do_kill = 0;
     SysRes res;
+    Int currentPID;
+    static Int check_counter = 0;
 
-    if (!command_inited) return;
+    /* Check for PID change, i.e. whether we run as child after a fork.
+     * If yes, we setup interactive control for the new process
+     */
+    currentPID = VG_(getpid)();
+    if (thisPID != currentPID) {
+	thisPID = currentPID;
+	setup_control();
+    }
 
-    /* toggle between 2 command files, with/without ".pid" postfix */
-    current_command_file = (current_command_file == command_file2) ? 
-                           command_file : command_file2;
-    current_result_file  = (current_command_file == command_file2) ?
-                           result_file2 : result_file;    
+    /* Toggle between 2 command files, with/without ".pid" postfix
+     * (needed for compatibility with KCachegrind, which wants to trigger
+     *  a dump by writing into a command file without the ".pid" postfix)
+     */
+    check_counter++;
+    if (check_counter % 2) {
+	current_command_file = command_file;
+	current_result_file  = result_file;
+    }
+    else {
+	current_command_file = command_file2;
+	current_result_file  = result_file2;
+    }
     
     res = VG_(open)(current_command_file, VKI_O_RDONLY,0);
     if (!res.isError) {