HelenOS sources
This source file includes following definitions.
- before_test_start
- kill_child_on_alarm
- read_all
- convert_wait_status_to_outcome
- pcut_run_test_forking
- pcut_hook_before_test
#define _POSIX_SOURCE
#define _BSD_SOURCE
#define _DEFAULT_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
#include <assert.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include "../internal.h"
#define OUTPUT_BUFFER_SIZE 8192
static char error_message_buffer[OUTPUT_BUFFER_SIZE];
static char extra_output_buffer[OUTPUT_BUFFER_SIZE];
static void before_test_start(pcut_item_t *test) {
pcut_report_test_start(test);
memset(error_message_buffer, 0, OUTPUT_BUFFER_SIZE);
memset(extra_output_buffer, 0, OUTPUT_BUFFER_SIZE);
}
static pid_t child_pid;
static void kill_child_on_alarm(int sig) {
PCUT_UNUSED(sig);
kill(child_pid, SIGKILL);
}
static size_t read_all(int fd, char *buffer, size_t buffer_size) {
ssize_t actually_read;
char *buffer_start = buffer;
do {
actually_read = read(fd, buffer, buffer_size);
if (actually_read > 0) {
buffer += actually_read;
buffer_size -= actually_read;
if (buffer_size == 0) {
break;
}
}
} while (actually_read > 0);
if (buffer_start != buffer) {
if (*(buffer - 1) == 10) {
*(buffer - 1) = 0;
buffer--;
}
}
return buffer - buffer_start;
}
static int convert_wait_status_to_outcome(int status) {
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0) {
return PCUT_OUTCOME_FAIL;
} else {
return PCUT_OUTCOME_PASS;
}
}
if (WIFSIGNALED(status)) {
return PCUT_OUTCOME_INTERNAL_ERROR;
}
return status;
}
int pcut_run_test_forking(const char *self_path, pcut_item_t *test) {
int link_stdout[2], link_stderr[2];
int rc, status, outcome;
size_t stderr_size;
PCUT_UNUSED(self_path);
before_test_start(test);
rc = pipe(link_stdout);
if (rc == -1) {
pcut_snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
"pipe() failed: %s.", strerror(rc));
pcut_report_test_done(test, PCUT_OUTCOME_INTERNAL_ERROR, error_message_buffer, NULL, NULL);
return PCUT_OUTCOME_INTERNAL_ERROR;
}
rc = pipe(link_stderr);
if (rc == -1) {
pcut_snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
"pipe() failed: %s.", strerror(rc));
pcut_report_test_done(test, PCUT_OUTCOME_INTERNAL_ERROR, error_message_buffer, NULL, NULL);
return PCUT_OUTCOME_INTERNAL_ERROR;
}
child_pid = fork();
if (child_pid == (pid_t)-1) {
pcut_snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
"fork() failed: %s.", strerror(rc));
outcome = PCUT_OUTCOME_INTERNAL_ERROR;
goto leave_close_pipes;
}
if (child_pid == 0) {
dup2(link_stdout[1], STDOUT_FILENO);
close(link_stdout[0]);
dup2(link_stderr[1], STDERR_FILENO);
close(link_stderr[0]);
outcome = pcut_run_test_forked(test);
exit(outcome);
}
close(link_stdout[1]);
close(link_stderr[1]);
signal(SIGALRM, kill_child_on_alarm);
alarm(pcut_get_test_timeout(test));
stderr_size = read_all(link_stderr[0], extra_output_buffer, OUTPUT_BUFFER_SIZE - 1);
read_all(link_stdout[0], extra_output_buffer, OUTPUT_BUFFER_SIZE - 1 - stderr_size);
wait(&status);
alarm(0);
outcome = convert_wait_status_to_outcome(status);
goto leave_close_parent_pipe;
leave_close_pipes:
close(link_stdout[1]);
close(link_stderr[1]);
leave_close_parent_pipe:
close(link_stdout[0]);
close(link_stderr[0]);
pcut_report_test_done_unparsed(test, outcome, extra_output_buffer, OUTPUT_BUFFER_SIZE);
return outcome;
}
void pcut_hook_before_test(pcut_item_t *test) {
PCUT_UNUSED(test);
}
HelenOS homepage, sources at GitHub