diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8fead66..f1b18bf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -75,6 +75,18 @@ find_package(PCRE)
# List sources and headers
set(SOURCE_FILES
+ src/compat/internal.h
+ src/compat/pipe.c
+ src/compat/pipe.h
+ src/compat/section.c
+ src/compat/section.h
+ src/compat/process.c
+ src/compat/process.h
+ src/compat/basename.c
+ src/compat/basename.h
+ src/compat/mockfile.c
+ src/compat/posix.h
+ src/redirect.c
src/abort.c
src/abort.h
src/event.c
@@ -83,8 +95,8 @@ set(SOURCE_FILES
src/report.h
src/runner.c
src/runner.h
- src/process.c
- src/process.h
+ src/worker.c
+ src/worker.h
src/stats.c
src/stats.h
src/log/logging.c
@@ -96,7 +108,6 @@ set(SOURCE_FILES
src/i18n.c
src/i18n.h
src/ordered-set.c
- src/posix-compat.c
src/theories.c
src/asprintf.c
src/file.c
diff --git a/src/compat/basename.c b/src/compat/basename.c
new file mode 100644
index 0000000..ed388ba
--- /dev/null
+++ b/src/compat/basename.c
@@ -0,0 +1,32 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "basename.h"
+
+const char *basename_compat(const char *str) {
+ const char *start = str;
+ for (const char *c = str; *c; ++c)
+ if ((*c == '/' || *c == '\\') && c[1])
+ start = c + 1;
+ return start;
+}
diff --git a/src/compat/basename.h b/src/compat/basename.h
new file mode 100644
index 0000000..5a1521b
--- /dev/null
+++ b/src/compat/basename.h
@@ -0,0 +1,29 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef BASENAME_H_
+# define BASENAME_H_
+
+const char *basename_compat(const char *str);
+
+#endif /* !BASENAME_H_ */
diff --git a/src/compat/internal.h b/src/compat/internal.h
new file mode 100644
index 0000000..04f257e
--- /dev/null
+++ b/src/compat/internal.h
@@ -0,0 +1,47 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef INTERNAL_H_
+# define INTERNAL_H_
+
+# include "posix.h"
+
+# ifdef VANILLA_WIN32
+# define VC_EXTRALEAN
+# define WIN32_LEAN_AND_MEAN
+# undef _WIN32_WINNT
+# define _WIN32_WINNT 0x0502
+# include
+# include
+# include
+# include
+# include
+# include
+# else
+# include
+# include
+# include
+# include
+# endif
+
+#endif /* !INTERNAL_H_ */
diff --git a/src/compat/mockfile.c b/src/compat/mockfile.c
new file mode 100644
index 0000000..983d6d7
--- /dev/null
+++ b/src/compat/mockfile.c
@@ -0,0 +1,181 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#define _GNU_SOURCE 1
+#include "internal.h"
+#include
+#include
+#include
+#include
+#include
+
+#if defined(BSD) || defined(__unix__)
+
+# ifdef BSD
+typedef int cr_count;
+typedef int cr_retcount;
+typedef fpos_t cr_off;
+# else
+typedef size_t cr_count;
+typedef ssize_t cr_retcount;
+typedef off64_t cr_off;
+# endif
+
+struct memfile {
+ size_t size;
+ size_t region_size;
+ size_t cur;
+ size_t max_size;
+ char *mem;
+};
+
+static inline size_t size_safe_add(size_t size, size_t cur, cr_off off) {
+ cur = cur < SIZE_MAX - off ? cur + off : SIZE_MAX;
+ return cur < size ? cur : size;
+}
+
+static inline size_t off_safe_add(size_t size, size_t cur, cr_off off) {
+ if (off >= 0)
+ cur = cur < SIZE_MAX - off ? cur + off : SIZE_MAX;
+ else
+ cur = cur > (size_t) -off ? cur + off : 0;
+ return cur < size ? cur : size;
+}
+
+# define errno_return(Errno, Val) \
+ do { \
+ errno = (Errno); \
+ return (Val); \
+ } while (0)
+
+static cr_retcount mock_file_read(void *cookie, char *buf, cr_count count) {
+ struct memfile *mf = cookie;
+# ifdef BSD
+ if (count < 0)
+ errno_return(EINVAL, (cr_retcount) -1);
+# endif
+ if (mf->cur >= mf->size || count == 0)
+ return 0;
+
+ size_t end = size_safe_add(mf->size, mf->cur, count);
+ count = end - mf->cur;
+ memcpy(buf, mf->mem + mf->cur, count);
+ mf->cur = end;
+ return count;
+}
+
+static cr_retcount mock_file_write(void *cookie, const char *buf, cr_count count) {
+ struct memfile *mf = cookie;
+# ifdef BSD
+ if (count < 0)
+ errno_return(EINVAL, (cr_retcount) -1);
+# endif
+ if (count == 0)
+ return 0;
+
+ if (mf->cur >= mf->max_size)
+ errno_return(EIO, (cr_retcount) -1);
+
+ size_t end = size_safe_add(mf->max_size, mf->cur, count);
+ if (mf->size < end)
+ mf->size = end;
+ count = end - mf->cur;
+
+ if (mf->size > mf->region_size) {
+ while (mf->size > mf->region_size)
+ mf->region_size = mf->region_size * 3 / 2;
+ char *newptr = realloc(mf->mem, mf->region_size);
+ if (!newptr)
+ errno_return(EIO, (cr_retcount) -1);
+ mf->mem = newptr;
+ }
+ memcpy(mf->mem + mf->cur, buf, count);
+ mf->cur = end;
+ return count;
+}
+
+# ifdef BSD
+static cr_off mock_file_seek(void *cookie, cr_off off, int whence) {
+ struct memfile *mf = cookie;
+ switch (whence) {
+ case SEEK_SET: return (mf->cur = off);
+ case SEEK_CUR: return (mf->cur = off_safe_add(mf->size, mf->cur, off));
+ case SEEK_END: return (mf->cur = off_safe_add(mf->size, mf->size, off));
+ default: break;
+ }
+ errno = EINVAL;
+ return (off_t) -1;
+}
+# else
+static int mock_file_seek(void *cookie, cr_off *off, int whence) {
+ struct memfile *mf = cookie;
+ switch (whence) {
+ case SEEK_SET: mf->cur = *off; break;
+ case SEEK_CUR: *off = (mf->cur = off_safe_add(mf->size, mf->cur, *off)); break;
+ case SEEK_END: *off = (mf->cur = off_safe_add(mf->size, mf->size, *off)); break;
+ default: errno = EINVAL; return -1;
+ }
+ return 0;
+}
+# endif
+
+static int mock_file_close(void *cookie) {
+ struct memfile *mf = cookie;
+ free(mf->mem);
+ free(cookie);
+ return 0;
+}
+#endif
+
+FILE *cr_mock_file_size(size_t max_size) {
+#if defined(__unix__) || defined(BSD)
+ struct memfile *cookie = malloc(sizeof (struct memfile));
+ *cookie = (struct memfile) {
+ .max_size = max_size,
+ .region_size = 4096,
+ .mem = malloc(4096),
+ };
+
+ FILE *f;
+# ifdef __unix__
+ f = fopencookie(cookie, "w+", (cookie_io_functions_t) {
+ .read = mock_file_read,
+ .write = mock_file_write,
+ .seek = mock_file_seek,
+ .close = mock_file_close,
+ });
+# else
+ f = funopen(cookie,
+ mock_file_read,
+ mock_file_write,
+ mock_file_seek,
+ mock_file_close);
+# endif
+ return f;
+#else
+ (void) max_size;
+
+ // fallback to tmpfile()
+ return tmpfile();
+#endif
+}
diff --git a/src/compat/pipe.c b/src/compat/pipe.c
new file mode 100644
index 0000000..626071d
--- /dev/null
+++ b/src/compat/pipe.c
@@ -0,0 +1,189 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include
+#include
+
+#include "pipe.h"
+#include "internal.h"
+
+struct pipe_handle {
+#ifdef VANILLA_WIN32
+ HANDLE fhs[2];
+#else
+ int fds[2];
+#endif
+};
+
+FILE *pipe_in(s_pipe_handle *p, int do_close) {
+#ifdef VANILLA_WIN32
+ if (do_close)
+ CloseHandle(p->fhs[1]);
+ int fd = _open_osfhandle((intptr_t) p->fhs[0], _O_RDONLY);
+ if (fd == -1)
+ return NULL;
+ FILE *in = _fdopen(fd, "r");
+#else
+ if (do_close)
+ close(p->fds[1]);
+ FILE *in = fdopen(p->fds[0], "r");
+#endif
+ if (!in)
+ return NULL;
+
+ setvbuf(in, NULL, _IONBF, 0);
+ return in;
+}
+
+FILE *pipe_out(s_pipe_handle *p, int do_close) {
+#ifdef VANILLA_WIN32
+ if (do_close)
+ CloseHandle(p->fhs[0]);
+ int fd = _open_osfhandle((intptr_t) p->fhs[1], _O_WRONLY);
+ if (fd == -1)
+ return NULL;
+ FILE *out = _fdopen(fd, "w");
+#else
+ if (do_close)
+ close(p->fds[0]);
+ FILE *out = fdopen(p->fds[1], "w");
+#endif
+ if (!out)
+ return NULL;
+
+ setvbuf(out, NULL, _IONBF, 0);
+ return out;
+}
+
+int stdpipe_stack(s_pipe_handle *out) {
+#ifdef VANILLA_WIN32
+ HANDLE fhs[2];
+ SECURITY_ATTRIBUTES attr = {
+ .nLength = sizeof (SECURITY_ATTRIBUTES),
+ .bInheritHandle = TRUE
+ };
+ if (!CreatePipe(fhs, fhs + 1, &attr, 0))
+ return -1;
+ *out = (s_pipe_handle) {{ fhs[0], fhs[1] }};
+#else
+ int fds[2] = { -1, -1 };
+ if (pipe(fds) == -1)
+ return -1;
+ *out = (s_pipe_handle) {{ fds[0], fds[1] }};
+#endif
+ return 0;
+}
+
+s_pipe_handle *stdpipe() {
+ s_pipe_handle *handle = smalloc(sizeof (s_pipe_handle));
+ if (stdpipe_stack(handle) < 0)
+ return NULL;
+ return handle;
+}
+
+int stdpipe_options(s_pipe_handle *handle, int id, int noblock) {
+#ifdef VANILLA_WIN32
+ HANDLE fhs[2];
+ SECURITY_ATTRIBUTES attr = {
+ .nLength = sizeof (SECURITY_ATTRIBUTES),
+ .bInheritHandle = TRUE
+ };
+ char pipe_name[256] = {0};
+ snprintf(pipe_name, sizeof (pipe_name),
+ "\\\\.\\pipe\\criterion_%lu_%d", GetCurrentProcessId(), id);
+ fhs[0] = CreateNamedPipe(pipe_name,
+ PIPE_ACCESS_INBOUND,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE
+ | (noblock ? PIPE_NOWAIT : PIPE_WAIT),
+ 1,
+ 4096 * 4,
+ 4096 * 4,
+ 0,
+ &attr);
+
+ if (fhs[0] == INVALID_HANDLE_VALUE)
+ return 0;
+
+ fhs[1] = CreateFile(pipe_name,
+ GENERIC_WRITE,
+ 0,
+ &attr,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+
+ if (fhs[1] == INVALID_HANDLE_VALUE) {
+ CloseHandle(fhs[0]);
+ return 0;
+ }
+
+ *handle = (s_pipe_handle) {{ fhs[0], fhs[1] }};
+#else
+ (void) id;
+
+ int fds[2] = { -1, -1 };
+ if (pipe(fds) == -1)
+ return 0;
+
+ if (noblock)
+ for (int i = 0; i < 2; ++i)
+ fcntl(fds[i], F_SETFL, fcntl(fds[i], F_GETFL) | O_NONBLOCK);
+
+ *handle = (s_pipe_handle) {{ fds[0], fds[1] }};
+#endif
+ return 1;
+}
+
+void pipe_std_redirect(s_pipe_handle *pipe, enum criterion_std_fd fd) {
+ enum pipe_end end = fd == CR_STDIN ? PIPE_READ : PIPE_WRITE;
+#ifdef VANILLA_WIN32
+ int stdfd = _open_osfhandle((intptr_t) pipe->fhs[end], end == PIPE_READ ? _O_RDONLY : _O_WRONLY);
+ if (stdfd == -1)
+ cr_assert_fail("Could not redirect standard file descriptor.");
+
+ _close(fd);
+ _dup2(stdfd, fd);
+ _close(stdfd);
+
+ setvbuf(get_std_file(fd), NULL, _IONBF, 0);
+
+ static int handles[] = {
+ [CR_STDIN] = STD_INPUT_HANDLE,
+ [CR_STDOUT] = STD_OUTPUT_HANDLE,
+ [CR_STDERR] = STD_ERROR_HANDLE,
+ };
+ SetStdHandle(handles[fd], pipe->fhs[end]);
+#else
+ close(fd);
+ dup2(pipe->fds[end], fd);
+ close(pipe->fds[end]);
+#endif
+}
+
+static s_pipe_handle stdout_redir_;
+static s_pipe_handle stderr_redir_;
+static s_pipe_handle stdin_redir_;
+
+s_pipe_handle *stdout_redir = &stdout_redir_;
+s_pipe_handle *stderr_redir = &stderr_redir_;
+s_pipe_handle *stdin_redir = &stdin_redir_;
diff --git a/src/compat/pipe.h b/src/compat/pipe.h
new file mode 100644
index 0000000..2aa9d8d
--- /dev/null
+++ b/src/compat/pipe.h
@@ -0,0 +1,63 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef PIPE_H_
+# define PIPE_H_
+
+# include "common.h"
+
+struct pipe_handle;
+typedef struct pipe_handle s_pipe_handle;
+
+enum pipe_end {
+ PIPE_READ = 0,
+ PIPE_WRITE = 1,
+};
+
+enum criterion_std_fd {
+ CR_STDIN = 0,
+ CR_STDOUT = 1,
+ CR_STDERR = 2,
+};
+
+s_pipe_handle *stdpipe();
+FILE *pipe_in(s_pipe_handle *p, int do_close);
+FILE *pipe_out(s_pipe_handle *p, int do_close);
+
+int stdpipe_options(s_pipe_handle *pipe, int id, int noblock);
+void pipe_std_redirect(s_pipe_handle *pipe, enum criterion_std_fd fd);
+
+INLINE FILE* get_std_file(int fd_kind) {
+ switch (fd_kind) {
+ case CR_STDIN: return stdin;
+ case CR_STDOUT: return stdout;
+ case CR_STDERR: return stderr;
+ }
+ return NULL;
+}
+
+extern s_pipe_handle *stdout_redir;
+extern s_pipe_handle *stderr_redir;
+extern s_pipe_handle *stdin_redir;
+
+#endif /* !PIPE_H_ */
diff --git a/src/compat/posix.h b/src/compat/posix.h
new file mode 100644
index 0000000..a001bbb
--- /dev/null
+++ b/src/compat/posix.h
@@ -0,0 +1,59 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef POSIX_COMPAT_H_
+# define POSIX_COMPAT_H_
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# define VANILLA_WIN32
+#endif
+
+# if !defined(_POSIX_SOURCE)
+# define _POSIX_SOURCE 1
+# define TMP_POSIX
+# endif
+# include
+# ifdef TMP_POSIX
+# undef _POSIX_SOURCE
+# undef TMP_POSIX
+# endif
+
+# ifdef VANILLA_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)
+
+# define SIGPROF 27
+# define CR_EXCEPTION_TIMEOUT 0xC0001042
+# else
+# include
+# include
+# endif
+
+# include "compat/pipe.h"
+# include "compat/section.h"
+# include "compat/process.h"
+# include "compat/basename.h"
+
+#endif /* !POSIX_COMPAT_H_ */
diff --git a/src/compat/process.c b/src/compat/process.c
new file mode 100644
index 0000000..cf53bcd
--- /dev/null
+++ b/src/compat/process.c
@@ -0,0 +1,250 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include
+#include "process.h"
+#include "internal.h"
+
+#ifdef VANILLA_WIN32
+# define CREATE_SUSPENDED_(Filename, CmdLine, StartupInfo, Info) \
+ CreateProcessW(Filename, \
+ CmdLine, \
+ NULL, \
+ NULL, \
+ TRUE, \
+ CREATE_SUSPENDED, \
+ NULL, \
+ NULL, \
+ &(StartupInfo), \
+ &(Info))
+
+# define WRITE_PROCESS_(Proc, What, Size) \
+ WriteProcessMemory(Proc, &What, &What, Size, NULL);
+#endif
+
+struct proc_handle {
+#ifdef VANILLA_WIN32
+ HANDLE handle;
+#else
+ pid_t pid;
+#endif
+};
+
+struct worker_context g_worker_context = {.test = NULL};
+
+#ifdef VANILLA_WIN32
+struct full_context {
+ struct criterion_test test;
+ struct criterion_test_extra_data test_data;
+ struct criterion_suite suite;
+ struct criterion_test_extra_data suite_data;
+ f_worker_func func;
+ struct pipe_handle pipe;
+ volatile int resumed;
+};
+
+static TCHAR g_mapping_name[] = TEXT("WinCriterionWorker");
+#define MAPPING_SIZE sizeof (struct full_context)
+
+static struct full_context local_ctx;
+#endif
+
+int resume_child(void) {
+#ifdef VANILLA_WIN32
+ HANDLE sharedMem = OpenFileMapping(
+ FILE_MAP_ALL_ACCESS,
+ FALSE,
+ g_mapping_name);
+
+ if (sharedMem == NULL)
+ return 0;
+
+ struct full_context *ctx = (struct full_context *) MapViewOfFile(sharedMem,
+ FILE_MAP_ALL_ACCESS,
+ 0,
+ 0,
+ MAPPING_SIZE);
+
+ if (ctx == NULL)
+ exit(-1);
+
+ local_ctx = *ctx;
+ g_worker_context = (struct worker_context) {
+ &local_ctx.test,
+ &local_ctx.suite,
+ local_ctx.func,
+ &local_ctx.pipe
+ };
+
+ local_ctx.test.data = &local_ctx.test_data;
+ local_ctx.suite.data = &local_ctx.suite_data;
+
+ ctx->resumed = 1;
+
+ UnmapViewOfFile(ctx);
+ CloseHandle(sharedMem);
+
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+
+ run_worker(&g_worker_context);
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+s_proc_handle *fork_process() {
+#ifdef VANILLA_WIN32
+ PROCESS_INFORMATION info;
+ STARTUPINFOW si = { .cb = sizeof (STARTUPINFOW) };
+
+ ZeroMemory(&info, sizeof (info));
+
+ // Create the suspended child process
+ wchar_t filename[MAX_PATH];
+ GetModuleFileNameW(NULL, filename, MAX_PATH);
+
+ if (!CREATE_SUSPENDED_(filename, GetCommandLineW(), si, info))
+ return (void *) -1;
+
+ // Copy context over
+ HANDLE sharedMem = CreateFileMapping(
+ INVALID_HANDLE_VALUE,
+ NULL,
+ PAGE_READWRITE,
+ 0,
+ MAPPING_SIZE,
+ g_mapping_name);
+
+ if (sharedMem == NULL)
+ return (void *) -1;
+
+ struct full_context *ctx = (struct full_context *) MapViewOfFile(sharedMem,
+ FILE_MAP_ALL_ACCESS,
+ 0,
+ 0,
+ MAPPING_SIZE);
+
+ if (ctx == NULL) {
+ CloseHandle(sharedMem);
+ return (void *) -1;
+ }
+
+ *ctx = (struct full_context) {
+ .test = *g_worker_context.test,
+ .test_data = *g_worker_context.test->data,
+ .suite = *g_worker_context.suite,
+ .func = g_worker_context.func,
+ .pipe = *g_worker_context.pipe,
+ .resumed = 0,
+ };
+
+ if (g_worker_context.suite->data)
+ ctx->suite_data = *g_worker_context.suite->data;
+
+ ResumeThread(info.hThread);
+ CloseHandle(info.hThread);
+
+ while (!ctx->resumed); // wait until the child has initialized itself
+
+ UnmapViewOfFile(ctx);
+ CloseHandle(sharedMem);
+
+ s_proc_handle *handle = smalloc(sizeof (s_proc_handle));
+ *handle = (s_proc_handle) { info.hProcess };
+ return handle;
+#else
+ pid_t pid = fork();
+ if (pid == -1)
+ return (void *) -1;
+ if (pid == 0)
+ return NULL;
+
+ s_proc_handle *handle = smalloc(sizeof (s_proc_handle));
+ *handle = (s_proc_handle) { pid };
+ return handle;
+#endif
+}
+
+void wait_process(s_proc_handle *handle, int *status) {
+#ifdef VANILLA_WIN32
+ WaitForSingleObject(handle->handle, INFINITE);
+ DWORD exit_code;
+ GetExitCodeProcess(handle->handle, &exit_code);
+ CloseHandle(handle->handle);
+
+ unsigned int sig = 0;
+ switch (exit_code) {
+ case STATUS_FLOAT_DENORMAL_OPERAND:
+ case STATUS_FLOAT_DIVIDE_BY_ZERO:
+ case STATUS_FLOAT_INEXACT_RESULT:
+ case STATUS_FLOAT_INVALID_OPERATION:
+ case STATUS_FLOAT_OVERFLOW:
+ case STATUS_FLOAT_STACK_CHECK:
+ case STATUS_FLOAT_UNDERFLOW:
+ case STATUS_INTEGER_DIVIDE_BY_ZERO:
+ case STATUS_INTEGER_OVERFLOW: sig = SIGFPE; break;
+
+ case STATUS_ILLEGAL_INSTRUCTION:
+ case STATUS_PRIVILEGED_INSTRUCTION:
+ case STATUS_NONCONTINUABLE_EXCEPTION: sig = SIGILL; break;
+
+ case CR_EXCEPTION_TIMEOUT: sig = SIGPROF; break;
+
+ case STATUS_ACCESS_VIOLATION:
+ case STATUS_DATATYPE_MISALIGNMENT:
+ case STATUS_ARRAY_BOUNDS_EXCEEDED:
+ case STATUS_GUARD_PAGE_VIOLATION:
+ case STATUS_IN_PAGE_ERROR:
+ case STATUS_NO_MEMORY:
+ case STATUS_INVALID_DISPOSITION:
+ case STATUS_STACK_OVERFLOW: sig = SIGSEGV; break;
+
+ case STATUS_CONTROL_C_EXIT: sig = SIGINT; break;
+
+ default: break;
+ }
+
+ *status = sig ? sig : exit_code << 8;
+#else
+ waitpid(handle->pid, status, 0);
+#endif
+}
+
+s_proc_handle *get_current_process() {
+ s_proc_handle *handle = smalloc(sizeof (s_proc_handle));
+#ifdef VANILLA_WIN32
+ *handle = (s_proc_handle) { GetCurrentProcess() };
+#else
+ *handle = (s_proc_handle) { getpid() };
+#endif
+ return handle;
+}
+
+bool is_current_process(s_proc_handle *proc) {
+#ifdef VANILLA_WIN32
+ return GetProcessId(proc->handle) == GetProcessId(GetCurrentProcess());
+#else
+ return proc->pid == getpid();
+#endif
+}
diff --git a/src/compat/process.h b/src/compat/process.h
new file mode 100644
index 0000000..2d5d2ef
--- /dev/null
+++ b/src/compat/process.h
@@ -0,0 +1,49 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef COMPAT_PROCESS_H_
+# define COMPAT_PROCESS_H_
+
+# include "criterion/types.h"
+
+struct proc_handle;
+typedef struct proc_handle s_proc_handle;
+
+struct worker_context {
+ struct criterion_test *test;
+ struct criterion_suite *suite;
+ f_worker_func func;
+ struct pipe_handle *pipe;
+};
+
+extern struct worker_context g_worker_context;
+
+int resume_child(void);
+
+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 /* !COMPAT_PROCESS_H_ */
diff --git a/src/compat/section.c b/src/compat/section.c
new file mode 100644
index 0000000..0c6c895
--- /dev/null
+++ b/src/compat/section.c
@@ -0,0 +1,87 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "section.h"
+#include "internal.h"
+
+#ifdef _WIN32
+void *get_win_section_start(const char *section) {
+ PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) GetModuleHandle(NULL);
+ PIMAGE_NT_HEADERS ntHeader = ntHeader = (PIMAGE_NT_HEADERS) ((DWORD)(dosHeader) + (dosHeader->e_lfanew));
+
+ assert(dosHeader->e_magic == IMAGE_DOS_SIGNATURE);
+ assert(ntHeader->Signature == IMAGE_NT_SIGNATURE);
+
+ PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(ntHeader);
+ for(int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, pSecHeader++) {
+ if (!strncmp((char*) pSecHeader->Name, section, 8)) {
+ return (char*) dosHeader + pSecHeader->VirtualAddress;
+ }
+ }
+ return NULL;
+}
+
+void *get_win_section_end(const char *section) {
+ PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) GetModuleHandle(NULL);
+ PIMAGE_NT_HEADERS ntHeader = ntHeader = (PIMAGE_NT_HEADERS) ((DWORD)(dosHeader) + (dosHeader->e_lfanew));
+
+ assert(dosHeader->e_magic == IMAGE_DOS_SIGNATURE);
+ assert(ntHeader->Signature == IMAGE_NT_SIGNATURE);
+
+ PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(ntHeader);
+ for(int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, pSecHeader++) {
+ if (!strncmp((char*) pSecHeader->Name, section, 8)) {
+ return (char*) dosHeader + (size_t) pSecHeader->VirtualAddress + pSecHeader->SizeOfRawData;
+ }
+ }
+ return NULL;
+}
+#endif
+
+#ifdef __APPLE__
+# include
+# include
+
+# define BASE_IMAGE_INDEX 0
+
+static inline void *get_real_address(void *addr) {
+ if (!addr)
+ return NULL;
+
+ // We need to slide the section address to get a valid pointer
+ // because ASLR will shift the image by a random offset
+ return addr + _dyld_get_image_vmaddr_slide(BASE_IMAGE_INDEX);
+}
+
+void *get_osx_section_start(const char *section) {
+ unsigned long secsize;
+ return get_real_address(getsectdata("__DATA", section, &secsize));
+}
+
+void *get_osx_section_end(const char *section) {
+ unsigned long secsize;
+ char *section_start = getsectdata("__DATA", section, &secsize);
+ return get_real_address(section_start) + secsize;
+}
+#endif
+
diff --git a/src/posix-compat.h b/src/compat/section.h
similarity index 58%
rename from src/posix-compat.h
rename to src/compat/section.h
index a0c86e7..9f6359e 100644
--- a/src/posix-compat.h
+++ b/src/compat/section.h
@@ -21,64 +21,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef POSIX_COMPAT_H_
-# define POSIX_COMPAT_H_
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-# define VANILLA_WIN32
-#endif
-
-# if !defined(_POSIX_SOURCE)
-# define _POSIX_SOURCE 1
-# define TMP_POSIX
-# endif
-# include
-# ifdef TMP_POSIX
-# undef _POSIX_SOURCE
-# undef TMP_POSIX
-# endif
-
-# ifdef VANILLA_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)
-
-# define SIGPROF 27
-# define CR_EXCEPTION_TIMEOUT 0xC0001042
-# else
-# include
-# include
-# endif
-
-#include
-
-struct proc_handle;
-typedef struct proc_handle s_proc_handle;
-
-struct pipe_handle;
-typedef struct pipe_handle s_pipe_handle;
-
-struct worker_context {
- struct criterion_test *test;
- struct criterion_suite *suite;
- f_worker_func func;
- struct pipe_handle *pipe;
-};
-
-extern struct worker_context g_worker_context;
-
-int resume_child(void);
-
-s_pipe_handle *stdpipe();
-FILE *pipe_in(s_pipe_handle *p, int do_close);
-FILE *pipe_out(s_pipe_handle *p, int do_close);
-
-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);
+#ifndef SECTION_H_
+# define SECTION_H_
# ifdef _WIN32
void *get_win_section_start(const char *section);
@@ -99,6 +43,4 @@ void *get_osx_section_end(const char *section);
# define GET_SECTION_END(Name) SECTION_END(Name)
# endif
-const char *basename_compat(const char *str);
-
-#endif /* !POSIX_COMPAT_H_ */
+#endif /* !SECTION_H_ */
diff --git a/src/log/normal.c b/src/log/normal.c
index 6e3b1db..43ffbba 100644
--- a/src/log/normal.c
+++ b/src/log/normal.c
@@ -30,10 +30,10 @@
#include "criterion/logging.h"
#include "criterion/options.h"
#include "criterion/ordered-set.h"
+#include "compat/basename.h"
#include "timer.h"
#include "config.h"
#include "i18n.h"
-#include "posix-compat.h"
#include "common.h"
#ifdef VANILLA_WIN32
diff --git a/src/log/tap.c b/src/log/tap.c
index 9a87b78..662c658 100644
--- a/src/log/tap.c
+++ b/src/log/tap.c
@@ -29,9 +29,9 @@
#include "criterion/logging.h"
#include "criterion/options.h"
#include "criterion/ordered-set.h"
+#include "compat/basename.h"
#include "timer.h"
#include "config.h"
-#include "posix-compat.h"
#include "common.h"
#ifdef _MSC_VER
diff --git a/src/posix-compat.c b/src/posix-compat.c
deleted file mode 100644
index a8061da..0000000
--- a/src/posix-compat.c
+++ /dev/null
@@ -1,737 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright © 2015 Franklin "Snaipe" Mathieu
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#define _GNU_SOURCE 1
-#include
-#include
-#include
-#include "posix-compat.h"
-#include "process.h"
-#include "criterion/assert.h"
-#include "criterion/redirect.h"
-
-#ifdef VANILLA_WIN32
-# define VC_EXTRALEAN
-# define WIN32_LEAN_AND_MEAN
-# undef _WIN32_WINNT
-# define _WIN32_WINNT 0x0502
-# include
-# include
-# include
-# include
-# include
-
-# define CREATE_SUSPENDED_(Filename, CmdLine, StartupInfo, Info) \
- CreateProcessW(Filename, \
- CmdLine, \
- NULL, \
- NULL, \
- TRUE, \
- CREATE_SUSPENDED, \
- NULL, \
- NULL, \
- &(StartupInfo), \
- &(Info))
-
-# define WRITE_PROCESS_(Proc, What, Size) \
- WriteProcessMemory(Proc, &What, &What, Size, NULL);
-
-# include
-
-#else
-# include
-# include
-# include
-# include
-#endif
-
-#include
-
-struct proc_handle {
-#ifdef VANILLA_WIN32
- HANDLE handle;
-#else
- pid_t pid;
-#endif
-};
-
-struct pipe_handle {
-#ifdef VANILLA_WIN32
- HANDLE fhs[2];
-#else
- int fds[2];
-#endif
-};
-
-struct worker_context g_worker_context = {.test = NULL};
-
-#ifdef VANILLA_WIN32
-struct full_context {
- struct criterion_test test;
- struct criterion_test_extra_data test_data;
- struct criterion_suite suite;
- struct criterion_test_extra_data suite_data;
- f_worker_func func;
- struct pipe_handle pipe;
- volatile int resumed;
-};
-
-static TCHAR g_mapping_name[] = TEXT("WinCriterionWorker");
-#define MAPPING_SIZE sizeof (struct full_context)
-
-static struct full_context local_ctx;
-#endif
-
-int resume_child(void) {
-#ifdef VANILLA_WIN32
- HANDLE sharedMem = OpenFileMapping(
- FILE_MAP_ALL_ACCESS,
- FALSE,
- g_mapping_name);
-
- if (sharedMem == NULL)
- return 0;
-
- struct full_context *ctx = (struct full_context *) MapViewOfFile(sharedMem,
- FILE_MAP_ALL_ACCESS,
- 0,
- 0,
- MAPPING_SIZE);
-
- if (ctx == NULL)
- exit(-1);
-
- local_ctx = *ctx;
- g_worker_context = (struct worker_context) {
- &local_ctx.test,
- &local_ctx.suite,
- local_ctx.func,
- &local_ctx.pipe
- };
-
- local_ctx.test.data = &local_ctx.test_data;
- local_ctx.suite.data = &local_ctx.suite_data;
-
- ctx->resumed = 1;
-
- UnmapViewOfFile(ctx);
- CloseHandle(sharedMem);
-
- SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
-
- run_worker(&g_worker_context);
- return 1;
-#else
- return 0;
-#endif
-}
-
-s_proc_handle *fork_process() {
-#ifdef VANILLA_WIN32
- PROCESS_INFORMATION info;
- STARTUPINFOW si = { .cb = sizeof (STARTUPINFOW) };
-
- ZeroMemory(&info, sizeof (info));
-
- // Create the suspended child process
- wchar_t filename[MAX_PATH];
- GetModuleFileNameW(NULL, filename, MAX_PATH);
-
- if (!CREATE_SUSPENDED_(filename, GetCommandLineW(), si, info))
- return (void *) -1;
-
- // Copy context over
- HANDLE sharedMem = CreateFileMapping(
- INVALID_HANDLE_VALUE,
- NULL,
- PAGE_READWRITE,
- 0,
- MAPPING_SIZE,
- g_mapping_name);
-
- if (sharedMem == NULL)
- return (void *) -1;
-
- struct full_context *ctx = (struct full_context *) MapViewOfFile(sharedMem,
- FILE_MAP_ALL_ACCESS,
- 0,
- 0,
- MAPPING_SIZE);
-
- if (ctx == NULL) {
- CloseHandle(sharedMem);
- return (void *) -1;
- }
-
- *ctx = (struct full_context) {
- .test = *g_worker_context.test,
- .test_data = *g_worker_context.test->data,
- .suite = *g_worker_context.suite,
- .func = g_worker_context.func,
- .pipe = *g_worker_context.pipe,
- .resumed = 0,
- };
-
- if (g_worker_context.suite->data)
- ctx->suite_data = *g_worker_context.suite->data;
-
- ResumeThread(info.hThread);
- CloseHandle(info.hThread);
-
- while (!ctx->resumed); // wait until the child has initialized itself
-
- UnmapViewOfFile(ctx);
- CloseHandle(sharedMem);
-
- s_proc_handle *handle = smalloc(sizeof (s_proc_handle));
- *handle = (s_proc_handle) { info.hProcess };
- return handle;
-#else
- pid_t pid = fork();
- if (pid == -1)
- return (void *) -1;
- if (pid == 0)
- return NULL;
-
- s_proc_handle *handle = smalloc(sizeof (s_proc_handle));
- *handle = (s_proc_handle) { pid };
- return handle;
-#endif
-}
-
-void wait_process(s_proc_handle *handle, int *status) {
-#ifdef VANILLA_WIN32
- WaitForSingleObject(handle->handle, INFINITE);
- DWORD exit_code;
- GetExitCodeProcess(handle->handle, &exit_code);
- CloseHandle(handle->handle);
-
- unsigned int sig = 0;
- switch (exit_code) {
- case STATUS_FLOAT_DENORMAL_OPERAND:
- case STATUS_FLOAT_DIVIDE_BY_ZERO:
- case STATUS_FLOAT_INEXACT_RESULT:
- case STATUS_FLOAT_INVALID_OPERATION:
- case STATUS_FLOAT_OVERFLOW:
- case STATUS_FLOAT_STACK_CHECK:
- case STATUS_FLOAT_UNDERFLOW:
- case STATUS_INTEGER_DIVIDE_BY_ZERO:
- case STATUS_INTEGER_OVERFLOW: sig = SIGFPE; break;
-
- case STATUS_ILLEGAL_INSTRUCTION:
- case STATUS_PRIVILEGED_INSTRUCTION:
- case STATUS_NONCONTINUABLE_EXCEPTION: sig = SIGILL; break;
-
- case CR_EXCEPTION_TIMEOUT: sig = SIGPROF; break;
-
- case STATUS_ACCESS_VIOLATION:
- case STATUS_DATATYPE_MISALIGNMENT:
- case STATUS_ARRAY_BOUNDS_EXCEEDED:
- case STATUS_GUARD_PAGE_VIOLATION:
- case STATUS_IN_PAGE_ERROR:
- case STATUS_NO_MEMORY:
- case STATUS_INVALID_DISPOSITION:
- case STATUS_STACK_OVERFLOW: sig = SIGSEGV; break;
-
- case STATUS_CONTROL_C_EXIT: sig = SIGINT; break;
-
- default: break;
- }
-
- *status = sig ? sig : exit_code << 8;
-#else
- waitpid(handle->pid, status, 0);
-#endif
-}
-
-FILE *pipe_in(s_pipe_handle *p, int do_close) {
-#ifdef VANILLA_WIN32
- if (do_close)
- CloseHandle(p->fhs[1]);
- int fd = _open_osfhandle((intptr_t) p->fhs[0], _O_RDONLY);
- if (fd == -1)
- return NULL;
- FILE *in = _fdopen(fd, "r");
-#else
- if (do_close)
- close(p->fds[1]);
- FILE *in = fdopen(p->fds[0], "r");
-#endif
- if (!in)
- return NULL;
-
- setvbuf(in, NULL, _IONBF, 0);
- return in;
-}
-
-FILE *pipe_out(s_pipe_handle *p, int do_close) {
-#ifdef VANILLA_WIN32
- if (do_close)
- CloseHandle(p->fhs[0]);
- int fd = _open_osfhandle((intptr_t) p->fhs[1], _O_WRONLY);
- if (fd == -1)
- return NULL;
- FILE *out = _fdopen(fd, "w");
-#else
- if (do_close)
- close(p->fds[0]);
- FILE *out = fdopen(p->fds[1], "w");
-#endif
- if (!out)
- return NULL;
-
- setvbuf(out, NULL, _IONBF, 0);
- return out;
-}
-
-int stdpipe_stack(s_pipe_handle *out) {
-#ifdef VANILLA_WIN32
- HANDLE fhs[2];
- SECURITY_ATTRIBUTES attr = {
- .nLength = sizeof (SECURITY_ATTRIBUTES),
- .bInheritHandle = TRUE
- };
- if (!CreatePipe(fhs, fhs + 1, &attr, 0))
- return -1;
- *out = (s_pipe_handle) {{ fhs[0], fhs[1] }};
-#else
- int fds[2] = { -1, -1 };
- if (pipe(fds) == -1)
- return -1;
- *out = (s_pipe_handle) {{ fds[0], fds[1] }};
-#endif
- return 0;
-}
-
-s_pipe_handle *stdpipe() {
- s_pipe_handle *handle = smalloc(sizeof (s_pipe_handle));
- if (stdpipe_stack(handle) < 0)
- return NULL;
- return handle;
-}
-
-s_proc_handle *get_current_process() {
- s_proc_handle *handle = smalloc(sizeof (s_proc_handle));
-#ifdef VANILLA_WIN32
- *handle = (s_proc_handle) { GetCurrentProcess() };
-#else
- *handle = (s_proc_handle) { getpid() };
-#endif
- return handle;
-}
-
-bool is_current_process(s_proc_handle *proc) {
-#ifdef VANILLA_WIN32
- return GetProcessId(proc->handle) == GetProcessId(GetCurrentProcess());
-#else
- return proc->pid == getpid();
-#endif
-}
-
-#ifdef _WIN32
-void *get_win_section_start(const char *section) {
- PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) GetModuleHandle(NULL);
- PIMAGE_NT_HEADERS ntHeader = ntHeader = (PIMAGE_NT_HEADERS) ((DWORD)(dosHeader) + (dosHeader->e_lfanew));
-
- assert(dosHeader->e_magic == IMAGE_DOS_SIGNATURE);
- assert(ntHeader->Signature == IMAGE_NT_SIGNATURE);
-
- PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(ntHeader);
- for(int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, pSecHeader++) {
- if (!strncmp((char*) pSecHeader->Name, section, 8)) {
- return (char*) dosHeader + pSecHeader->VirtualAddress;
- }
- }
- return NULL;
-}
-
-void *get_win_section_end(const char *section) {
- PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) GetModuleHandle(NULL);
- PIMAGE_NT_HEADERS ntHeader = ntHeader = (PIMAGE_NT_HEADERS) ((DWORD)(dosHeader) + (dosHeader->e_lfanew));
-
- assert(dosHeader->e_magic == IMAGE_DOS_SIGNATURE);
- assert(ntHeader->Signature == IMAGE_NT_SIGNATURE);
-
- PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(ntHeader);
- for(int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, pSecHeader++) {
- if (!strncmp((char*) pSecHeader->Name, section, 8)) {
- return (char*) dosHeader + (size_t) pSecHeader->VirtualAddress + pSecHeader->SizeOfRawData;
- }
- }
- return NULL;
-}
-#endif
-
-#ifdef __APPLE__
-# include
-# include
-
-# define BASE_IMAGE_INDEX 0
-
-static inline void *get_real_address(void *addr) {
- if (!addr)
- return NULL;
-
- // We need to slide the section address to get a valid pointer
- // because ASLR will shift the image by a random offset
- return addr + _dyld_get_image_vmaddr_slide(BASE_IMAGE_INDEX);
-}
-
-void *get_osx_section_start(const char *section) {
- unsigned long secsize;
- return get_real_address(getsectdata("__DATA", section, &secsize));
-}
-
-void *get_osx_section_end(const char *section) {
- unsigned long secsize;
- char *section_start = getsectdata("__DATA", section, &secsize);
- return get_real_address(section_start) + secsize;
-}
-#endif
-
-const char *basename_compat(const char *str) {
- const char *start = str;
- for (const char *c = str; *c; ++c)
- if ((*c == '/' || *c == '\\') && c[1])
- start = c + 1;
- return start;
-}
-
-#ifdef VANILLA_WIN32
-typedef DWORD cr_std_fd;
-#else
-typedef int cr_std_fd;
-#endif
-
-static s_pipe_handle stdout_redir;
-static s_pipe_handle stderr_redir;
-static s_pipe_handle stdin_redir;
-
-enum criterion_std_fd {
- CR_STDIN = 0,
- CR_STDOUT = 1,
- CR_STDERR = 2,
-};
-
-enum criterion_pipe_end {
- PIPE_READ = 0,
- PIPE_WRITE = 1,
-};
-
-cr_std_fd get_std_fd(int fd_kind) {
- static int kinds[] = {
-#ifdef VANILLA_WIN32
- [CR_STDIN] = STD_INPUT_HANDLE,
- [CR_STDOUT] = STD_OUTPUT_HANDLE,
- [CR_STDERR] = STD_ERROR_HANDLE,
-#else
- [CR_STDIN] = STDIN_FILENO,
- [CR_STDOUT] = STDOUT_FILENO,
- [CR_STDERR] = STDERR_FILENO,
-#endif
- };
-
- return kinds[fd_kind];
-}
-
-FILE* get_std_file(int fd_kind) {
- switch (fd_kind) {
- case CR_STDIN: return stdin;
- case CR_STDOUT: return stdout;
- case CR_STDERR: return stderr;
- }
- return NULL;
-}
-
-int make_redirect_pipe(s_pipe_handle *handle, int id, int noblock) {
-#ifdef VANILLA_WIN32
- HANDLE fhs[2];
- SECURITY_ATTRIBUTES attr = {
- .nLength = sizeof (SECURITY_ATTRIBUTES),
- .bInheritHandle = TRUE
- };
- char pipe_name[256] = {0};
- snprintf(pipe_name, sizeof (pipe_name),
- "\\\\.\\pipe\\criterion_%lu_%d", GetCurrentProcessId(), id);
- fhs[0] = CreateNamedPipe(pipe_name,
- PIPE_ACCESS_INBOUND,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE
- | (noblock ? PIPE_NOWAIT : PIPE_WAIT),
- 1,
- 4096 * 4,
- 4096 * 4,
- 0,
- &attr);
-
- if (fhs[0] == INVALID_HANDLE_VALUE)
- return 0;
-
- fhs[1] = CreateFile(pipe_name,
- GENERIC_WRITE,
- 0,
- &attr,
- OPEN_EXISTING,
- 0,
- NULL);
-
- if (fhs[1] == INVALID_HANDLE_VALUE) {
- CloseHandle(fhs[0]);
- return 0;
- }
-
- *handle = (s_pipe_handle) {{ fhs[0], fhs[1] }};
-#else
- (void) id;
-
- int fds[2] = { -1, -1 };
- if (pipe(fds) == -1)
- return 0;
-
- if (noblock)
- for (int i = 0; i < 2; ++i)
- fcntl(fds[i], F_SETFL, fcntl(fds[i], F_GETFL) | O_NONBLOCK);
-
- *handle = (s_pipe_handle) {{ fds[0], fds[1] }};
-#endif
- return 1;
-}
-
-void cr_redirect(int fd_kind, s_pipe_handle *pipe, int fd_index, int noblock) {
- fflush(get_std_file(fd_kind));
- if (!make_redirect_pipe(pipe, fd_kind, noblock))
- cr_assert_fail("Could not redirect standard file descriptor.");
-
- cr_std_fd fd = get_std_fd(fd_kind);
-#ifdef VANILLA_WIN32
- int stdfd = _open_osfhandle((intptr_t) pipe->fhs[fd_index], fd_kind == 0 ? _O_RDONLY : _O_WRONLY);
- if (stdfd == -1)
- cr_assert_fail("Could not redirect standard file descriptor.");
-
- fflush(get_std_file(fd_kind));
-
- _close(fd_kind);
- SetStdHandle(fd, pipe->fhs[fd_index]);
-
- _dup2(stdfd, fd_kind);
- _close(stdfd);
-
- setvbuf(get_std_file(fd_kind), NULL, _IONBF, 0);
-#else
- close(fd);
- dup2(pipe->fds[fd_index], fd);
- close(pipe->fds[fd_index]);
-#endif
-}
-
-void cr_redirect_stdout(void) {
- cr_redirect(CR_STDOUT, &stdout_redir, PIPE_WRITE, 1);
-}
-
-void cr_redirect_stderr(void) {
- cr_redirect(CR_STDERR, &stderr_redir, PIPE_WRITE, 1);
-}
-
-void cr_redirect_stdin(void) {
- cr_redirect(CR_STDIN, &stdin_redir, PIPE_READ, 0);
-}
-
-FILE* cr_get_redirected_stdout(void) {
- static FILE *f;
- if (!f) {
- f = pipe_in(&stdout_redir, 0);
- if (!f)
- cr_assert_fail("Could not get redirected stdout read end.");
- }
- return f;
-}
-
-FILE* cr_get_redirected_stderr(void) {
- static FILE *f;
- if (!f) {
- f = pipe_in(&stderr_redir, 0);
- if (!f)
- cr_assert_fail("Could not get redirected stderr read end.");
- }
- return f;
-}
-
-FILE* cr_get_redirected_stdin(void) {
- static FILE *f;
- if (!f) {
- f = pipe_out(&stdin_redir, 0);
- if (!f)
- cr_assert_fail("Could not get redirected stdin write end.");
- }
- return f;
-}
-
-#if defined(BSD) || defined(__unix__)
-
-# ifdef BSD
-typedef int cr_count;
-typedef int cr_retcount;
-typedef fpos_t cr_off;
-# else
-typedef size_t cr_count;
-typedef ssize_t cr_retcount;
-typedef off64_t cr_off;
-# endif
-
-struct memfile {
- size_t size;
- size_t region_size;
- size_t cur;
- size_t max_size;
- char *mem;
-};
-
-static inline size_t size_safe_add(size_t size, size_t cur, cr_off off) {
- cur = cur < SIZE_MAX - off ? cur + off : SIZE_MAX;
- return cur < size ? cur : size;
-}
-
-static inline size_t off_safe_add(size_t size, size_t cur, cr_off off) {
- if (off >= 0)
- cur = cur < SIZE_MAX - off ? cur + off : SIZE_MAX;
- else
- cur = cur > (size_t) -off ? cur + off : 0;
- return cur < size ? cur : size;
-}
-
-# define errno_return(Errno, Val) \
- do { \
- errno = (Errno); \
- return (Val); \
- } while (0)
-
-static cr_retcount mock_file_read(void *cookie, char *buf, cr_count count) {
- struct memfile *mf = cookie;
-# ifdef BSD
- if (count < 0)
- errno_return(EINVAL, (cr_retcount) -1);
-# endif
- if (mf->cur >= mf->size || count == 0)
- return 0;
-
- size_t end = size_safe_add(mf->size, mf->cur, count);
- count = end - mf->cur;
- memcpy(buf, mf->mem + mf->cur, count);
- mf->cur = end;
- return count;
-}
-
-static cr_retcount mock_file_write(void *cookie, const char *buf, cr_count count) {
- struct memfile *mf = cookie;
-# ifdef BSD
- if (count < 0)
- errno_return(EINVAL, (cr_retcount) -1);
-# endif
- if (count == 0)
- return 0;
-
- if (mf->cur >= mf->max_size)
- errno_return(EIO, (cr_retcount) -1);
-
- size_t end = size_safe_add(mf->max_size, mf->cur, count);
- if (mf->size < end)
- mf->size = end;
- count = end - mf->cur;
-
- if (mf->size > mf->region_size) {
- while (mf->size > mf->region_size)
- mf->region_size = mf->region_size * 3 / 2;
- char *newptr = realloc(mf->mem, mf->region_size);
- if (!newptr)
- errno_return(EIO, (cr_retcount) -1);
- mf->mem = newptr;
- }
- memcpy(mf->mem + mf->cur, buf, count);
- mf->cur = end;
- return count;
-}
-
-# ifdef BSD
-static cr_off mock_file_seek(void *cookie, cr_off off, int whence) {
- struct memfile *mf = cookie;
- switch (whence) {
- case SEEK_SET: return (mf->cur = off);
- case SEEK_CUR: return (mf->cur = off_safe_add(mf->size, mf->cur, off));
- case SEEK_END: return (mf->cur = off_safe_add(mf->size, mf->size, off));
- default: break;
- }
- errno = EINVAL;
- return (off_t) -1;
-}
-# else
-static int mock_file_seek(void *cookie, cr_off *off, int whence) {
- struct memfile *mf = cookie;
- switch (whence) {
- case SEEK_SET: mf->cur = *off; break;
- case SEEK_CUR: *off = (mf->cur = off_safe_add(mf->size, mf->cur, *off)); break;
- case SEEK_END: *off = (mf->cur = off_safe_add(mf->size, mf->size, *off)); break;
- default: errno = EINVAL; return -1;
- }
- return 0;
-}
-# endif
-
-static int mock_file_close(void *cookie) {
- struct memfile *mf = cookie;
- free(mf->mem);
- free(cookie);
- return 0;
-}
-#endif
-
-FILE *cr_mock_file_size(size_t max_size) {
-#if defined(__unix__) || defined(BSD)
- struct memfile *cookie = malloc(sizeof (struct memfile));
- *cookie = (struct memfile) {
- .max_size = max_size,
- .region_size = 4096,
- .mem = malloc(4096),
- };
-
- FILE *f;
-# ifdef __unix__
- f = fopencookie(cookie, "w+", (cookie_io_functions_t) {
- .read = mock_file_read,
- .write = mock_file_write,
- .seek = mock_file_seek,
- .close = mock_file_close,
- });
-# else
- f = funopen(cookie,
- mock_file_read,
- mock_file_write,
- mock_file_seek,
- mock_file_close);
-# endif
- return f;
-#else
- (void) max_size;
-
- // fallback to tmpfile()
- return tmpfile();
-#endif
-}
diff --git a/src/redirect.c b/src/redirect.c
new file mode 100644
index 0000000..a9d80d0
--- /dev/null
+++ b/src/redirect.c
@@ -0,0 +1,77 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include
+#include "criterion/assert.h"
+#include "criterion/redirect.h"
+#include "compat/pipe.h"
+
+void cr_redirect(enum criterion_std_fd fd_kind, s_pipe_handle *pipe) {
+ fflush(get_std_file(fd_kind));
+ if (!stdpipe_options(pipe, fd_kind, fd_kind == CR_STDIN ? 0 : 1))
+ cr_assert_fail("Could not redirect standard file descriptor.");
+
+ pipe_std_redirect(pipe, fd_kind);
+}
+
+void cr_redirect_stdout(void) {
+ cr_redirect(CR_STDOUT, stdout_redir);
+}
+
+void cr_redirect_stderr(void) {
+ cr_redirect(CR_STDERR, stderr_redir);
+}
+
+void cr_redirect_stdin(void) {
+ cr_redirect(CR_STDIN, stdin_redir);
+}
+
+FILE* cr_get_redirected_stdout(void) {
+ static FILE *f;
+ if (!f) {
+ f = pipe_in(stdout_redir, 0);
+ if (!f)
+ cr_assert_fail("Could not get redirected stdout read end.");
+ }
+ return f;
+}
+
+FILE* cr_get_redirected_stderr(void) {
+ static FILE *f;
+ if (!f) {
+ f = pipe_in(stderr_redir, 0);
+ if (!f)
+ cr_assert_fail("Could not get redirected stderr read end.");
+ }
+ return f;
+}
+
+FILE* cr_get_redirected_stdin(void) {
+ static FILE *f;
+ if (!f) {
+ f = pipe_out(stdin_redir, 0);
+ if (!f)
+ cr_assert_fail("Could not get redirected stdin write end.");
+ }
+ return f;
+}
diff --git a/src/report.c b/src/report.c
index 9a6f80e..025d484 100644
--- a/src/report.c
+++ b/src/report.c
@@ -31,7 +31,7 @@
#include "criterion/ordered-set.h"
#include "report.h"
#include "config.h"
-#include "posix-compat.h"
+#include "compat/posix.h"
static inline void nothing() {}
diff --git a/src/runner.c b/src/runner.c
index c752d86..60a5978 100644
--- a/src/runner.c
+++ b/src/runner.c
@@ -32,9 +32,9 @@
#include "runner.h"
#include "report.h"
#include "event.h"
-#include "process.h"
+#include "worker.h"
#include "timer.h"
-#include "posix-compat.h"
+#include "compat/posix.h"
#include "abort.h"
#include "config.h"
#include "i18n.h"
diff --git a/src/runner.h b/src/runner.h
index e78fd96..75e12dc 100644
--- a/src/runner.h
+++ b/src/runner.h
@@ -25,7 +25,6 @@
# define CRITERION_RUNNER_H_
# include "criterion/types.h"
-# include "posix-compat.h"
DECL_SECTION_LIMITS(struct criterion_test, cr_tst);
DECL_SECTION_LIMITS(struct criterion_suite, cr_sts);
diff --git a/src/timer.c b/src/timer.c
index 8007afa..bfcfb35 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -3,7 +3,7 @@
#include
#include "timer.h"
#include "criterion/common.h"
-#include "posix-compat.h"
+#include "compat/posix.h"
#define GIGA 1000000000
diff --git a/src/process.c b/src/worker.c
similarity index 98%
rename from src/process.c
rename to src/worker.c
index 561665c..9cf38fe 100644
--- a/src/process.c
+++ b/src/worker.c
@@ -28,9 +28,9 @@
#include "criterion/types.h"
#include "criterion/options.h"
#include "criterion/redirect.h"
-#include "process.h"
+#include "worker.h"
#include "event.h"
-#include "posix-compat.h"
+#include "compat/posix.h"
struct process {
s_proc_handle *proc;
diff --git a/src/process.h b/src/worker.h
similarity index 98%
rename from src/process.h
rename to src/worker.h
index 5e0a6c3..2f63406 100644
--- a/src/process.h
+++ b/src/worker.h
@@ -25,7 +25,7 @@
# define PROCESS_H_
# include
-# include "posix-compat.h"
+# include "compat/process.h"
struct process;