staticint num_processors(void)
{ long nproc = sysconf(_SC_NPROCESSORS_CONF); if (nproc < 0) {
perror("Unable to read number of processors\n"); exit(EXIT_FAILURE);
}
return nproc;
}
staticvoid start_thread(struct child_data *child, int id)
{ int ret, pipefd[2], i; struct epoll_event ev;
ret = pipe(pipefd); if (ret != 0)
ksft_exit_fail_msg("Failed to create stdout pipe: %s (%d)\n",
strerror(errno), errno);
if (WIFEXITED(status)) {
child->exit_status = WEXITSTATUS(status);
child->exited = true;
}
if (WIFSIGNALED(status)) {
child->exit_signal = WTERMSIG(status);
ksft_print_msg("%s: Exited due to signal %d\n",
child->name, child->exit_signal);
fail = true;
child->exited = true;
}
} while (!child->exited);
}
if (!child->output_seen) {
ksft_print_msg("%s no output seen\n", child->name);
fail = true;
}
if (child->exit_status != 0) {
ksft_print_msg("%s exited with error code %d\n",
child->name, child->exit_status);
fail = true;
}
ksft_test_result(!fail, "%s\n", child->name);
}
staticvoid handle_child_signal(int sig, siginfo_t *info, void *context)
{ int i; bool found = false;
for (i = 0; i < num_children; i++) { if (children[i].pid == info->si_pid) {
children[i].exited = true;
children[i].exit_status = info->si_status;
found = true; break;
}
}
if (!found)
ksft_print_msg("SIGCHLD for unknown PID %d with status %d\n",
info->si_pid, info->si_status);
}
staticvoid handle_exit_signal(int sig, siginfo_t *info, void *context)
{ int i;
/* If we're already exiting then don't signal again */ if (terminate) return;
ksft_print_msg("Got signal, exiting...\n");
terminate = true;
/* *Thisshouldberedundant,themainloopshouldcleanup *afterus,butforsafetystopeverythingwecanhere.
*/ for (i = 0; i < num_children; i++)
child_stop(&children[i]);
}
/* Handle any pending output without blocking */ staticvoid drain_output(bool flush)
{ int ret = 1; int i;
while (ret > 0) {
ret = epoll_wait(epoll_fd, evs, tests, 0); if (ret < 0) { if (errno == EINTR) continue;
ksft_print_msg("epoll_wait() failed: %s (%d)\n",
strerror(errno), errno);
}
for (i = 0; i < ret; i++)
child_output(evs[i].data.ptr, evs[i].events, flush);
}
}
int main(int argc, char **argv)
{ int seen_children; bool all_children_started = false; int gcs_threads; int timeout = 10; int ret, cpus, i, c; struct sigaction sa;
while ((c = getopt_long(argc, argv, "t:", options, NULL)) != -1) { switch (c) { case't':
ret = sscanf(optarg, "%d", &timeout); if (ret != 1)
ksft_exit_fail_msg("Failed to parse timeout %s\n",
optarg); break; default:
ksft_exit_fail_msg("Unknown argument\n");
}
}
cpus = num_processors();
tests = 0;
if (getauxval(AT_HWCAP) & HWCAP_GCS) { /* One extra thread, trying to trigger migrations */
gcs_threads = cpus + 1;
tests += gcs_threads;
} else {
gcs_threads = 0;
}
if (!tests)
ksft_exit_skip("No tests scheduled\n");
if (timeout > 0)
ksft_print_msg("Will run for %ds\n", timeout); else
ksft_print_msg("Will run until terminated\n");
children = calloc(sizeof(*children), tests); if (!children)
ksft_exit_fail_msg("Unable to allocate child data\n");
ret = epoll_create1(EPOLL_CLOEXEC); if (ret < 0)
ksft_exit_fail_msg("epoll_create1() failed: %s (%d)\n",
strerror(errno), ret);
epoll_fd = ret;
/* Create a pipe which children will block on before execing */
ret = pipe(startup_pipe); if (ret != 0)
ksft_exit_fail_msg("Failed to create startup pipe: %s (%d)\n",
strerror(errno), errno);
/* Get signal handers ready before we start any children */
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = handle_exit_signal;
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sigemptyset(&sa.sa_mask);
ret = sigaction(SIGINT, &sa, NULL); if (ret < 0)
ksft_print_msg("Failed to install SIGINT handler: %s (%d)\n",
strerror(errno), errno);
ret = sigaction(SIGTERM, &sa, NULL); if (ret < 0)
ksft_print_msg("Failed to install SIGTERM handler: %s (%d)\n",
strerror(errno), errno);
sa.sa_sigaction = handle_child_signal;
ret = sigaction(SIGCHLD, &sa, NULL); if (ret < 0)
ksft_print_msg("Failed to install SIGCHLD handler: %s (%d)\n",
strerror(errno), errno);
evs = calloc(tests, sizeof(*evs)); if (!evs)
ksft_exit_fail_msg("Failed to allocated %d epoll events\n",
tests);
for (i = 0; i < gcs_threads; i++)
start_thread(&children[i], i);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.