Refactored code to prepare for windows integration

This commit is contained in:
Snaipe 2015-03-15 16:00:21 +01:00
parent 818243902a
commit 70a3c91dc5
9 changed files with 162 additions and 36 deletions

View file

@ -52,6 +52,7 @@ libcriterion_la_SOURCES = \
src/timer.c \
src/timer.h \
src/ordered-set.c \
src/posix-compat.c \
src/main.c
TARGET = $(PACKAGE)-$(VERSION)

View file

@ -25,8 +25,9 @@
# define CRITERION_EVENT_H_
# include <stddef.h>
# include <stdio.h>
extern int EVENT_PIPE;
extern FILE *g_event_pipe;
void send_event(int kind, void *data, size_t size);

View file

@ -22,36 +22,37 @@
* THE SOFTWARE.
*/
#include <unistd.h>
#include <stdio.h>
#include <csptr/smart_ptr.h>
#include "criterion/stats.h"
#include "criterion/common.h"
#include "criterion/hooks.h"
#include "event.h"
int EVENT_PIPE = -1;
FILE *g_event_pipe = NULL;
void destroy_event(void *ptr, UNUSED void *meta) {
struct event *ev = ptr;
free(ev->data);
}
struct event *read_event(int fd) {
struct event *read_event(FILE *f) {
unsigned kind;
if (read(fd, &kind, sizeof (unsigned)) < (ssize_t) sizeof (unsigned))
if (fread(&kind, sizeof (unsigned), 1, f) == 0)
return NULL;
switch (kind) {
case ASSERT: {
const size_t assert_size = sizeof (struct criterion_assert_stats);
unsigned char *buf = malloc(assert_size);
if (read(fd, buf, assert_size) < (ssize_t) assert_size)
if (fread(buf, assert_size, 1, f) == 0)
return NULL;
return unique_ptr(struct event, { .kind = kind, .data = buf }, destroy_event);
}
case POST_TEST: {
double *elapsed_time = malloc(sizeof (double));
if (read(fd, elapsed_time, sizeof (double)) < (ssize_t) sizeof (double))
if (fread(elapsed_time, sizeof (double), 1, f) == 0)
return NULL;
return unique_ptr(struct event, { .kind = kind, .data = elapsed_time }, destroy_event);
@ -65,5 +66,6 @@ void send_event(int kind, void *data, size_t size) {
unsigned char buf[sizeof (int) + size];
memcpy(buf, &kind, sizeof (int));
memcpy(buf + sizeof (int), data, size);
write(EVENT_PIPE, buf, sizeof (int) + size);
if (fwrite(buf, sizeof (int) + size, 1, g_event_pipe) == 0)
abort();
}

View file

@ -31,6 +31,6 @@ struct event {
void *data;
};
struct event *read_event(int fd);
struct event *read_event(FILE *f);
#endif /* !EVENT_H_ */

82
src/posix-compat.c Normal file
View file

@ -0,0 +1,82 @@
#include "posix-compat.h"
#ifdef _WIN32
# include <windows.h>
#else
# include <unistd.h>
# include <sys/wait.h>
# include <sys/signal.h>
# include <sys/fcntl.h>
#endif
#include <csptr/smart_ptr.h>
struct proc_handle {
#ifdef _WIN32
// TODO
#else
pid_t pid;
#endif
};
struct pipe_handle {
#ifdef _WIN32
// TODO
#else
int fds[2];
#endif
};
s_proc_handle *fork_process() {
#ifdef _WIN32
// TODO
#else
pid_t pid = fork();
if (pid == -1)
return (void *) -1;
if (pid == 0)
return NULL;
return unique_ptr(s_proc_handle, { pid });
#endif
}
void wait_process(s_proc_handle *handle, int *status) {
#ifdef _WIN32
// TODO
#else
waitpid(handle->pid, status, 0);
#endif
}
FILE *pipe_in(s_pipe_handle *p) {
close(p->fds[1]);
FILE *in = fdopen(p->fds[0], "r");
setvbuf(in, NULL, _IONBF, 0);
return in;
}
FILE *pipe_out(s_pipe_handle *p) {
close(p->fds[0]);
FILE *out = fdopen(p->fds[1], "w");
setvbuf(out, NULL, _IONBF, 0);
return out;
}
s_pipe_handle *stdpipe() {
#ifdef _WIN32
// TODO
#else
int fds[2] = { -1, -1 };
if (pipe(fds) == -1)
return NULL;
return unique_ptr(s_pipe_handle, {{ fds[0], fds[1] }});
#endif
}
s_proc_handle *get_current_process() {
return unique_ptr(s_proc_handle, { getpid() });
}
bool is_current_process(s_proc_handle *proc) {
return proc->pid == getpid();
}

35
src/posix-compat.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef POSIX_COMPAT_H_
# define POSIX_COMPAT_H_
# define _POSIX_SOURCE 1
# include <stdio.h>
# undef _POSIX_SOURCE
# ifdef _WIN32
# define WEXITSTATUS(Status) (((Status) & 0xFF00) >> 8)
# define WTERMSIG(Status) ((Status) & 0x7F)
# define WIFEXITED(Status) (WTERMSIG(Status) == 0)
# define WIFSIGNALED(Status) (((signed char) (WTERMSIG(Status) + 1) >> 1) > 0)
# else
# include <sys/wait.h>
# endif
#include <stdbool.h>
struct proc_handle;
typedef struct proc_handle s_proc_handle;
struct pipe_handle;
typedef struct pipe_handle s_pipe_handle;
s_pipe_handle *stdpipe();
FILE *pipe_in(s_pipe_handle *p);
FILE *pipe_out(s_pipe_handle *p);
s_proc_handle *fork_process();
void wait_process(s_proc_handle *handle, int *status);
s_proc_handle *get_current_process();
bool is_current_process(s_proc_handle *proc);
#endif /* !POSIX_COMPAT_H_ */

View file

@ -22,33 +22,38 @@
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdbool.h>
#include <csptr/smart_ptr.h>
#include "criterion/types.h"
#include "criterion/options.h"
#include "process.h"
#include "event.h"
#include "posix-compat.h"
struct process {
pid_t pid;
int in;
s_proc_handle *proc;
FILE *in;
};
static pid_t g_runner_pid;
static s_proc_handle *g_current_proc;
void set_runner_pid(void) {
g_runner_pid = getpid();
void set_runner_process(void) {
g_current_proc = get_current_process();
}
void unset_runner_process(void) {
sfree(g_current_proc);
}
bool is_runner(void) {
return g_runner_pid == getpid();
return is_current_process(g_current_proc);
}
static void close_process(void *ptr, UNUSED void *meta) {
close(((struct process *) ptr)->in);
struct process *proc = ptr;
fclose(proc->in);
sfree(proc->proc);
}
struct event *worker_read_event(struct process *proc) {
@ -58,35 +63,33 @@ struct event *worker_read_event(struct process *proc) {
struct process *spawn_test_worker(struct criterion_test *test,
struct criterion_suite *suite,
void (*func)(struct criterion_test *, struct criterion_suite *)) {
int fds[2];
if (pipe(fds) == -1)
smart s_pipe_handle *pipe = stdpipe();
if (pipe == NULL)
abort();
pid_t pid = fork();
if (pid == -1) {
s_proc_handle *proc = fork_process();
if (proc == (void *) -1) {
return NULL;
} else if (!pid) {
close(STDIN_FILENO);
close(fds[0]);
EVENT_PIPE = fds[1];
} else if (proc == NULL) {
fclose(stdin);
g_event_pipe = pipe_out(pipe);
func(test, suite);
close(fds[1]);
fclose(g_event_pipe);
fflush(NULL); // flush all opened streams
if (criterion_options.no_early_exit)
return NULL;
else
_exit(0);
_Exit(0);
}
close(fds[1]);
return unique_ptr(struct process, { .pid = pid, .in = fds[0] }, close_process);
return unique_ptr(struct process, { .proc = proc, .in = pipe_in(pipe) }, close_process);
}
struct process_status wait_proc(struct process *proc) {
int status;
waitpid(proc->pid, &status, 0);
wait_process(proc->proc, &status);
if (WIFEXITED(status))
return (struct process_status) { .kind = EXIT_STATUS, .status = WEXITSTATUS(status) };

View file

@ -39,7 +39,8 @@ struct process_status {
int status;
};
void set_runner_pid(void);
void set_runner_process(void);
void unset_runner_process(void);
bool is_runner(void);
struct process_status wait_proc(struct process *proc);
struct process *spawn_test_worker(struct criterion_test *test,

View file

@ -23,7 +23,6 @@
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <csptr/smart_ptr.h>
#include "criterion/criterion.h"
#include "criterion/options.h"
@ -203,7 +202,6 @@ static int criterion_run_all_tests_impl(void) {
smart struct criterion_test_set *set = criterion_init();
report(PRE_ALL, set);
set_runner_pid();
smart struct criterion_global_stats *stats = stats_init();
map_tests(set, stats, run_test);
@ -216,9 +214,12 @@ static int criterion_run_all_tests_impl(void) {
}
int criterion_run_all_tests(void) {
set_runner_process();
int res = criterion_run_all_tests_impl();
unset_runner_process();
if (res == -1) // if this is the test worker terminating
_exit(0);
_Exit(0);
return criterion_options.always_succeed || res;
}