[llvm-commits] [test-suite] r152983 - /test-suite/trunk/tools/timeit.c
Daniel Dunbar
daniel at zuster.org
Sat Mar 17 09:37:47 PDT 2012
Author: ddunbar
Date: Sat Mar 17 11:37:46 2012
New Revision: 152983
URL: http://llvm.org/viewvc/llvm-project?rev=152983&view=rev
Log:
[test-suite] tools/timeit: Add support for watch-dogging the monitored process,
in addition to timing it.
Modified:
test-suite/trunk/tools/timeit.c
Modified: test-suite/trunk/tools/timeit.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/tools/timeit.c?rev=152983&r1=152982&r2=152983&view=diff
==============================================================================
--- test-suite/trunk/tools/timeit.c (original)
+++ test-suite/trunk/tools/timeit.c Sat Mar 17 11:37:46 2012
@@ -8,12 +8,32 @@
\*===----------------------------------------------------------------------===*/
#include <stdio.h>
+#include <stdlib.h>
+
+#include <errno.h>
+#include <signal.h>
#include <unistd.h>
+
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/wait.h>
-int g_posix_mode = 0;
+/* \brief Record our own program name, for error messages. */
+static const char *g_program_name = 0;
+
+/* \brief Record the child command name, for error messages. */
+static const char *g_target_program = 0;
+
+/* \brief If given, report output in POSIX mode format. */
+static int g_posix_mode = 0;
+
+/* \brief If non-zero, execute the program with a timeout of the given number
+ * of seconds.
+ */
+static int g_timeout_in_seconds = 0;
+
+/* \brief If non-zero, the PID of the process being monitored. */
+static pid_t g_monitored_pid = 0;
static double sample_wall_time(void) {
struct timeval t;
@@ -21,28 +41,72 @@
return (double) t.tv_sec + t.tv_usec * 1.e-6;
}
-int execute(char * const argv[]) {
- double start_time = sample_wall_time();
- pid_t pid = fork();
+static void terminate_handler(int signal) {
+ /* If we are monitoring a process, kill its process group and assume we will
+ * complete normally.
+ */
+ if (g_monitored_pid) {
+ fprintf(stderr, ("%s: error: received signal %d. "
+ "Killing monitored process(es): %s\n"),
+ g_program_name, signal, g_target_program);
+
+ /* Kill the process group of monitored_pid. Since we called
+ setpgrp() for pid, this will not kill us, or any of our
+ ancestors */
+ kill(-g_monitored_pid, SIGKILL);
+ return;
+ }
+ fprintf(stderr, "%s: error: received signal %d. exiting.\n",
+ g_program_name, signal);
+ /* Otherwise, we received a signal we should treat as for ourselves, and exit
+ * quickly. */
+ _exit(69);
+}
+
+static void timeout_handler(int signal) {
+ fprintf(stderr, "%s: TIMING OUT PROCESS: %s\n", g_program_name,
+ g_target_program);
+ /* We should always be monitoring a process when we receive an alarm. Kill its
+ * process group and assume we will terminate normally.
+ */
+ kill(-g_monitored_pid, SIGKILL);
+}
+
+int monitor_child_process(pid_t pid, double start_time) {
double real_time, user_time, sys_time;
struct rusage usage;
int res, status;
- if (!pid) {
- execvp(argv[0], argv);
- perror("execvp");
- return 127;
+ /* Record the PID we are monitoring, for use in the signal handlers. */
+ g_monitored_pid = pid;
+
+ /* If we are running with a timeout, set up an alarm now. */
+ if (g_timeout_in_seconds) {
+ sigset_t masked;
+ sigemptyset(&masked);
+ sigaddset(&masked, SIGALRM);
+
+ alarm(g_timeout_in_seconds);
}
- res = waitpid(pid, &status, 0);
+ /* Wait for the process to terminate. */
+ do {
+ res = waitpid(pid, &status, 0);
+ } while (res < 0 && errno == EINTR);
if (res < 0) {
perror("waitpid");
- return 126;
+ return 68;
}
+ /* Record the real elapsed time as soon as we can. */
real_time = sample_wall_time() - start_time;
+ /* Just in case there was another error in waitpid, kill the child process
+ * group. */
+ kill(-pid, SIGKILL);
+
+ /* Collect the other resource data on the children. */
if (getrusage(RUSAGE_CHILDREN, &usage) < 0) {
perror("getrusage");
return 125;
@@ -61,6 +125,50 @@
return WEXITSTATUS(status);
}
+void execute_target_process(char * const argv[]) {
+ /* Create a new process group for pid, and the process tree it may spawn. We
+ * do this, because later on we might want to kill pid _and_ all processes
+ * spawned by it and its descendants.
+ */
+ setpgrp();
+
+ execv(argv[0], argv);
+ perror("execv");
+}
+
+int execute(char * const argv[]) {
+ double start_time;
+ pid_t pid;
+
+ /* Set up signal handlers so we can terminal the monitored process(es) on
+ * SIGINT or SIGTERM. */
+ signal(SIGINT, terminate_handler);
+ signal(SIGTERM, terminate_handler);
+
+ /* Set up a signal handler to terminate the process on timeout. */
+ signal(SIGALRM, timeout_handler);
+
+ start_time = sample_wall_time();
+
+ /* Fork the child process. */
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ return 66;
+ }
+
+ /* If we are in the context of the child process, spawn it. */
+ if (pid == 0) {
+ /* Setup and execute the target process. This never returns except on
+ * failure. */
+ execute_target_process(argv);
+ return 67;
+ }
+
+ /* Otherwise, we are in the context of the monitoring process. */
+ return monitor_child_process(pid, start_time);
+}
+
int main(int argc, char * const argv[]) {
int i;
@@ -73,11 +181,26 @@
g_posix_mode = 1;
continue;
+ case 't':
+ if (i + 1 == argc) {
+ fprintf(stderr, "error: -t argument requires an option\n");
+ return 1;
+ }
+ g_timeout_in_seconds = atoi(argv[++i]);
+ continue;
+
default:
fprintf(stderr, "error: invalid argument '%s'\n", argv[i]);
return 1;
}
}
+ if (i == argc) {
+ fprintf(stderr, "error: no command (or arguments) was given\n");
+ return 1;
+ }
+
+ g_program_name = argv[0];
+ g_target_program = argv[i];
return execute(&argv[i]);
}
More information about the llvm-commits
mailing list