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;
+
+ CLG_ASSERT(thisPID != 0);
+
+ fd = -1;
+ dir = CLG_(get_base_directory)();
+ dump_base = CLG_(get_dump_file_base)();
- dump_base = dumps;
+ /* 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
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
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);
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);
VG_(write)(fd, "\n", 1);
VG_(close)(fd);
}
+}
- command_inited = True;
+void CLG_(init_command)()
+{
+ thisPID = VG_(getpid)();
+ setup_control();
}
void CLG_(finish_command)()
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) {
#include <pub_tool_threadstate.h>
#include <pub_tool_libcfile.h>
-/*------------------------------------------------------------*/
-/*--- Support for signal handlers and multi-threading ---*/
-/*------------------------------------------------------------*/
/* Dump Part Counter */
static Int out_counter = 0;
static Char* dump_file_base = 0;
static Char* base_directory = 0;
+static Bool dumps_initialized = False;
/* Command */
static Char cmdbuf[BUF_LEN];
Char* CLG_(get_dump_file_base)()
{
- return dump_file_base;
+ CLG_ASSERT(dumps_initialized);
+ return dump_file_base;
+}
+
+Char* CLG_(get_base_directory)()
+{
+ CLG_ASSERT(dumps_initialized);
+ return base_directory;
}
/*------------------------------------------------------------*/
FullCost sum = 0;
SysRes res;
+ CLG_ASSERT(dumps_initialized);
CLG_ASSERT(filename != 0);
if (!CLG_(clo).combine_dumps) {
cmdbuf[size] = 0;
}
-void CLG_(init_files)(Char** dir, Char** file)
+/*
+ * Set up file names for dump output: base_directory, dump_file_base
+ * The final filename of a dump is constructed at dump time from
+ * the PID, thread ID and dump counter.
+ *
+ * These always will contain a full absolute path.
+ * If no prefix is given (via option "--base=<prefix>"), the current
+ * working directory at program start is used, otherwise <prefix> can
+ * be relative to cwd or absolute.
+ */
+void CLG_(init_dumps)()
{
- Int size;
- SysRes res;
+ Int size;
+ SysRes res;
if (!CLG_(clo).filename_base)
CLG_(clo).filename_base = DEFAULT_DUMPNAME;
}
if (!res.isError) VG_(close)( (Int)res.val );
- *dir = base_directory;
- *file = filename;
-
init_cmdbuf();
+
+ dumps_initialized = True;
}