#
# Have wrappers for the test tools, so that they run.
#
+# We have a hardcoded maximum execution time of 30 seconds
+# If your test takes > 30 seconds to run, you're doing
+# something wrong.
+#
TEST_BIN_DIR = ./$(BUILD_DIR)/bin/local
-TEST_BIN = $(JLIBTOOL) $(if ${VERBOSE},--debug,--silent) --mode=execute $(TEST_BIN_DIR)
+TEST_BIN = $(JLIBTOOL) $(if ${VERBOSE},--debug,--silent) --timeout=30 --mode=execute $(TEST_BIN_DIR)
#
# For creating documentation via doc/all.mk
# define TARGET_RANLIB "ranlib"
#endif
+/*
+ * Set to true when an exec times out
+ */
+static bool timeout = false;
+
static const toolset_t toolset_host = {
.cc = BUILD_CC,
.cxx = HOST_CXX,
char const *version_info;
char const *undefined_flag;
+
+ unsigned int timeout;
} command_t;
static void add_rpath(count_chars *cc, char const *path);
kill(spawn_pid, signo); /* Forward the signal to the process we're executing */
}
+void external_spawn_timeout(int pid)
+{
+ timeout = true;
+}
+
static int external_spawn(command_t *cmd, __attribute__((unused)) char const *file, char const **argv)
{
if (!cmd->options.silent) {
SIGNAL_FORWARD(SIGUSR1);
SIGNAL_FORWARD(SIGUSR2);
+ /*
+ * Deliver's SIGALRM after N seconds
+ */
+ if (cmd->timeout > 0) {
+ /*
+ * Seems like SA_RESTART is set
+ * implicitly when signal() is
+ * used, which is NOT what we want.
+ */
+ sigaction(SIGALRM,
+ &(struct sigaction){
+ .sa_handler = external_spawn_timeout,
+ .sa_flags = SA_RESETHAND
+ }, NULL);
+ alarm(cmd->timeout);
+ }
+
waitpid(spawn_pid, &status, 0);
+ if (cmd->timeout > 0) {
+ signal(SIGALRM, NULL);
+ alarm(0);
+ }
+
SIGNAL_RESET(SIGHUP);
SIGNAL_RESET(SIGINT);
SIGNAL_RESET(SIGQUIT);
SIGNAL_RESET(SIGUSR1);
SIGNAL_RESET(SIGUSR2);
+ /*
+ * We're assuming waitpid was delivered
+ * because of the alarm we set.
+ *
+ * Kill the child and clean it up.
+ */
+ if (timeout) {
+ NOTICE("exec timeout\n");
+ kill(spawn_pid, SIGKILL);
+
+ waitpid(spawn_pid, &status, 0); /* Cleanup child state */
+ timeout = false; /* reset */
+ }
+
/*
* Exited via exit(status)
*/
exit(0);
} else if (strcmp(var, "tag") == 0) {
DEBUG("discard --tag=%s\n", value);
+
+ } else if (strcmp(var, "timeout") == 0) {
+ cmd->timeout = strtoul(value, NULL, 10);
+ NOTICE("Timeout %u\n", cmd->timeout);
} else {
return 0;
}
} else if (!strcmp(arg + 1, "undefined")) {
cmd->undefined_flag = argv[++a];
arg_used = 1;
+
/*
* Add dir to runtime library search path.
*/