Refactored code to prepare for windows integration
This commit is contained in:
parent
818243902a
commit
70a3c91dc5
9 changed files with 162 additions and 36 deletions
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
16
src/event.c
16
src/event.c
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
82
src/posix-compat.c
Normal 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
35
src/posix-compat.h
Normal 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_ */
|
|
@ -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) };
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue