For consistency and deduplication, use run_program in start_mpstat. Add
the ability to pass a path to run_program, which will be opened in the
spawned process and used as stdout, in order to capture mpstat output.
This fixes a tricky descriptor leak in start_mpstat which could have
caused a race condition if it was fixed with close().
Some output formatting tweaks have also been added and a bug from a
previous patch, where tracers were killed immediately when -p wasn't
specified, has been fixed.
Signed-off-by: Andrew Price <anprice@redhat.com>
- err = run_program(argc, argv, 1, NULL);
+ err = run_program(argc, argv, 1, NULL, NULL);
if (err)
fprintf(stderr, "%s exited with %d, expected 0\n", argv[0], err);
free(argv);
if (err)
fprintf(stderr, "%s exited with %d, expected 0\n", argv[0], err);
free(argv);
#include <getopt.h>
#include <limits.h>
#include <float.h>
#include <getopt.h>
#include <limits.h>
#include <float.h>
#include "plot.h"
#include "blkparse.h"
#include "plot.h"
#include "blkparse.h"
}
if (num_blktrace_devices) {
}
if (num_blktrace_devices) {
+ char *path = join_path(blktrace_dest_dir, blktrace_outfile);
dest_mkdir(blktrace_dest_dir);
dest_mkdir(blktrace_dest_dir);
- if (num_blktrace_devices > 1) {
- snprintf(line, line_len, "%s/%s", blktrace_dest_dir,
- blktrace_outfile);
- dest_mkdir(line);
- }
-
- path = join_path(blktrace_dest_dir, blktrace_outfile);
snprintf(line, line_len, "%s.dump", path);
unlink(line);
snprintf(line, line_len, "%s.dump", path);
unlink(line);
ret = start_blktrace(blktrace_devices, num_blktrace_devices,
blktrace_outfile, blktrace_dest_dir);
if (ret) {
ret = start_blktrace(blktrace_devices, num_blktrace_devices,
blktrace_outfile, blktrace_dest_dir);
if (ret) {
- fprintf(stderr, "exiting due to blktrace failure\n");
- exit(1);
+ perror("Exiting due to blktrace failure");
+ exit(ret);
+ snprintf(line, line_len, "%s.mpstat", path);
+ ret = start_mpstat(line);
+ if (ret) {
+ perror("Exiting due to mpstat failure");
+ exit(ret);
+ }
if (prog_argv && prog_argc) {
if (prog_argv && prog_argc) {
- ret = run_program(prog_argc, prog_argv, 1, NULL);
- if (ret != 127)
- printf("%s exited with %d\n", prog_argv[0], ret);
+ run_program(prog_argc, prog_argv, 1, NULL, NULL);
+ wait_for_tracers(SIGINT);
+ } else {
+ printf("Tracing until interrupted...\n");
+ wait_for_tracers(0);
-static int line_len = 1024;
-static char line[1024];
-
static pid_t blktrace_pid = 0;
static pid_t mpstat_pid = 0;
static pid_t blktrace_pid = 0;
static pid_t mpstat_pid = 0;
-char *mpstat_args[] = {
- "mpstat",
- "-P", "ALL", "1",
- NULL,
-};
-
-int stop_tracer(pid_t *tracer_pid)
-{
- int ret;
- pid_t pid = *tracer_pid;
- pid_t pid_ret;
- int status = 0;
-
- if (pid == 0)
- return 0;
-
- *tracer_pid = 0;
- ret = kill(pid, SIGTERM);
- if (ret) {
- fprintf(stderr, "failed to stop tracer pid %lu error %s\n",
- (unsigned long)pid, strerror(errno));
- return -errno;
- }
- pid_ret = waitpid(pid, &status, WUNTRACED);
- if (pid_ret == pid && WIFEXITED(status) == 0) {
- fprintf(stderr, "blktrace returns error %d\n", WEXITSTATUS(status));
- }
- return 0;
-}
-
static void sig_handler_for_quit(int val)
{
fprintf(stderr, "Received signal %d. Terminating tracers.\n", val);
static void sig_handler_for_quit(int val)
{
fprintf(stderr, "Received signal %d. Terminating tracers.\n", val);
- if (blktrace_pid) {
- wait_program(blktrace_pid, "blktrace", SIGTERM);
- blktrace_pid = 0;
- }
- stop_tracer(&mpstat_pid);
+ wait_for_tracers(SIGTERM);
}
int start_blktrace(char **devices, int num_devices, char *trace_name, char *dest)
}
int start_blktrace(char **devices, int num_devices, char *trace_name, char *dest)
argv[argc] = NULL;
signal(SIGTERM, sig_handler_for_quit);
signal(SIGINT, sig_handler_for_quit);
argv[argc] = NULL;
signal(SIGTERM, sig_handler_for_quit);
signal(SIGINT, sig_handler_for_quit);
- ret = run_program(argc, argv, 0, &blktrace_pid);
+ ret = run_program(argc, argv, 0, &blktrace_pid, NULL);
ret = WEXITSTATUS(status);
if (ret == 127) /* spawnp failed after forking */
fprintf(stderr, "Failed to run '%s'\n", pname);
ret = WEXITSTATUS(status);
if (ret == 127) /* spawnp failed after forking */
fprintf(stderr, "Failed to run '%s'\n", pname);
+ else
+ fprintf(stderr, "Exit (%d): %s\n", ret, pname);
} else if (WIFSIGNALED(status) && sig && WTERMSIG(status) != sig) {
fprintf(stderr, "'%s' killed by signal %d\n", pname, WTERMSIG(status));
ret = -1;
} else if (WIFSIGNALED(status) && sig && WTERMSIG(status) != sig) {
fprintf(stderr, "'%s' killed by signal %d\n", pname, WTERMSIG(status));
ret = -1;
-int run_program(int argc, char **argv, int wait, pid_t *pid)
+int run_program(int argc, char **argv, int wait, pid_t *pid, char *outpath)
{
int i;
int err;
pid_t _pid;
{
int i;
int err;
pid_t _pid;
+ posix_spawn_file_actions_t facts;
+ posix_spawn_file_actions_t *factp = NULL;
- fprintf(stderr, "running");
+ if (outpath != NULL) {
+ posix_spawn_file_actions_init(&facts);
+ posix_spawn_file_actions_addopen(&facts, 1, outpath, O_WRONLY|O_CREAT|O_TRUNC, 0600);
+ factp = &facts;
+ }
+
+ fprintf(stderr, "Start");
for (i = 0; i < argc; i++)
for (i = 0; i < argc; i++)
- fprintf(stderr, " '%s'", argv[i]);
+ fprintf(stderr, " %s", argv[i]);
- err = posix_spawnp(&_pid, argv[0], NULL, NULL, argv, environ);
+ err = posix_spawnp(&_pid, argv[0], factp, NULL, argv, environ);
if (err != 0) {
fprintf(stderr, "Could not run '%s': %s\n", argv[0], strerror(err));
} else if (wait) {
if (err != 0) {
fprintf(stderr, "Could not run '%s': %s\n", argv[0], strerror(err));
} else if (wait) {
-int wait_for_tracers(void)
+int wait_for_tracers(int sig)
- int err = wait_program(blktrace_pid, "blktrace", SIGINT);
+ err = wait_program(blktrace_pid, "blktrace", sig);
if (err)
exit(1);
blktrace_pid = 0;
}
if (mpstat_pid != 0) {
if (err)
exit(1);
blktrace_pid = 0;
}
if (mpstat_pid != 0) {
- int status = 0;
- stop_tracer(&mpstat_pid);
- waitpid(mpstat_pid, &status, WUNTRACED);
+ err = wait_program(mpstat_pid, "mpstat", sig);
+ if (err)
+ exit(1);
mpstat_pid = 0;
}
return 0;
}
mpstat_pid = 0;
}
return 0;
}
-int start_mpstat(char *trace_name)
+int start_mpstat(char *path)
- int fd;
- pid_t pid;
-
- snprintf(line, line_len, "%s.mpstat", trace_name);
-
- fd = open(line, O_WRONLY | O_CREAT | O_TRUNC, 0600);
- if (fd < 0) {
- fprintf(stderr, "unable to open %s for writing err %s\n",
- line, strerror(errno));
- exit(1);
- }
- pid = fork();
- if (pid == 0) {
- int ret;
-
- close(1);
- ret = dup2(fd, 1);
- if (ret < 0) {
- fprintf(stderr, "failed to setup output file for mpstat\n");
- exit(1);
- }
- ret = execvp("mpstat", mpstat_args);
- if (ret < 0) {
- fprintf(stderr, "failed to exec mpstat err %s\n",
- strerror(ret));
- exit(1);
- }
- }
- mpstat_pid = pid;
- return 0;
+ int ret;
+ int argc = 4;
+ char *argv[] = {
+ "mpstat",
+ "-P", "ALL", "1",
+ NULL,
+ };
+
+ ret = run_program(argc, argv, 0, &mpstat_pid, path);
+ return ret;
*/
#ifndef __IOWATCH_TRACERS
#define __IOWATCH_TRACERS
*/
#ifndef __IOWATCH_TRACERS
#define __IOWATCH_TRACERS
-int run_program(int argc, char **argv, int wait, pid_t *pid);
+int run_program(int argc, char **argv, int wait, pid_t *pid, char *stdoutpath);
int wait_program(pid_t pid, const char *pname, int signal);
int stop_blktrace(void);
int start_blktrace(char **devices, int num_devices, char *trace_name, char *dest);
int start_mpstat(char *trace_name);
int wait_program(pid_t pid, const char *pname, int signal);
int stop_blktrace(void);
int start_blktrace(char **devices, int num_devices, char *trace_name, char *dest);
int start_mpstat(char *trace_name);
-int wait_for_tracers(void);
+int wait_for_tracers(int sig);