Merge branch 'features/windows-compat' into bleeding

This commit is contained in:
Snaipe 2015-08-04 13:34:59 +02:00
commit ea5a074ff4
9 changed files with 178 additions and 52 deletions

View file

@ -22,7 +22,7 @@
.line_ = __LINE__, \
__VA_ARGS__ \
}; \
SECTION_("criterion_tests") \
SECTION_("cr_tst") \
const struct criterion_test IDENTIFIER_(Category, Name, meta) = { \
.name = #Name, \
.category = #Category, \
@ -38,7 +38,7 @@
.line_ = 0, \
__VA_ARGS__ \
}; \
SECTION_("crit_suites") \
SECTION_("cr_sts") \
const struct criterion_suite SUITE_IDENTIFIER_(Name, meta) = { \
.name = #Name, \
.data = &SUITE_IDENTIFIER_(Name, extra), \

View file

@ -48,9 +48,27 @@ typedef void (*f_report_hook)();
# define HOOK_PROTOTYPE_ \
void HOOK_IDENTIFIER_(impl)
// Section abbreviations
# define HOOK_SECTION_PRE_ALL cr_pra
# define HOOK_SECTION_PRE_SUITE cr_prs
# define HOOK_SECTION_PRE_INIT cr_pri
# define HOOK_SECTION_PRE_TEST cr_prt
# define HOOK_SECTION_ASSERT cr_ast
# define HOOK_SECTION_TEST_CRASH cr_tsc
# define HOOK_SECTION_POST_TEST cr_pot
# define HOOK_SECTION_POST_FINI cr_pof
# define HOOK_SECTION_POST_SUITE cr_pos
# define HOOK_SECTION_POST_ALL cr_poa
# define HOOK_SECTION(Kind) HOOK_SECTION_ ## Kind
# define HOOK_SECTION_STRINGIFY__(Sec) #Sec
# define HOOK_SECTION_STRINGIFY_(Sec) HOOK_SECTION_STRINGIFY__(Sec)
# define HOOK_SECTION_STRINGIFY(Kind) HOOK_SECTION_STRINGIFY_(HOOK_SECTION(Kind))
# define ReportHook(Kind) \
HOOK_PROTOTYPE_(); \
SECTION_("crit_" #Kind) \
SECTION_(HOOK_SECTION_STRINGIFY(Kind)) \
const f_report_hook HOOK_IDENTIFIER_(func) = HOOK_IDENTIFIER_(impl); \
HOOK_PROTOTYPE_

View file

@ -26,6 +26,7 @@
# include <stdbool.h>
# include <stddef.h>
# include "common.h"
struct criterion_test_extra_data {
int sentinel_;

View file

@ -1,3 +1,4 @@
#include <assert.h>
#include "posix-compat.h"
#include "process.h"
@ -55,19 +56,62 @@ struct pipe_handle {
struct worker_context g_worker_context = {.test = NULL};
#ifdef VANILLA_WIN32
static struct criterion_test child_test;
static struct criterion_test_extra_data child_test_data;
static struct criterion_suite child_suite;
static struct criterion_test_extra_data child_suite_data;
static struct pipe_handle child_pipe;
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;
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) {
if (g_worker_context.test) {
run_worker(&g_worker_context);
return 1;
}
#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);
run_worker(&g_worker_context);
return 1;
#else
return 0;
#endif
}
s_proc_handle *fork_process() {
@ -85,37 +129,48 @@ s_proc_handle *fork_process() {
return (void *) -1;
// Copy context over
f_worker_func child_func = g_worker_context.func;
HANDLE sharedMem = CreateFileMapping(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
MAPPING_SIZE,
g_mapping_name);
child_test = *g_worker_context.test;
child_test_data = *g_worker_context.test->data;
child_suite = *g_worker_context.suite;
child_pipe = *g_worker_context.pipe;
if (sharedMem == NULL)
return (void *) -1;
g_worker_context = (struct worker_context) {
&child_test,
&child_suite,
child_func,
&child_pipe
};
struct full_context *ctx = (struct full_context *) MapViewOfFile(sharedMem,
FILE_MAP_ALL_ACCESS,
0,
0,
MAPPING_SIZE);
child_test.data = &child_test_data;
if (g_worker_context.suite->data) {
child_suite_data = *g_worker_context.suite->data;
child_suite.data = &child_suite_data;
WRITE_PROCESS_(info.hProcess, child_suite_data, sizeof (child_suite_data));
if (ctx == NULL) {
CloseHandle(sharedMem);
return (void *) -1;
}
WRITE_PROCESS_(info.hProcess, child_test, sizeof (child_test));
WRITE_PROCESS_(info.hProcess, child_test_data, sizeof (child_test_data));
WRITE_PROCESS_(info.hProcess, child_suite, sizeof (child_suite));
WRITE_PROCESS_(info.hProcess, child_pipe, sizeof (child_pipe));
WRITE_PROCESS_(info.hProcess, g_worker_context, sizeof (struct worker_context));
*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);
return unique_ptr(s_proc_handle, { info.hProcess });
#else
pid_t pid = fork();
@ -208,3 +263,37 @@ bool is_current_process(s_proc_handle *proc) {
return proc->pid == getpid();
#endif
}
#ifdef VANILLA_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

View file

@ -53,4 +53,14 @@ void wait_process(s_proc_handle *handle, int *status);
s_proc_handle *get_current_process();
bool is_current_process(s_proc_handle *proc);
# ifdef VANILLA_WIN32
void *get_win_section_start(const char *section);
void *get_win_section_end(const char *section);
# define GET_SECTION_START(Name) get_win_section_start(#Name)
# define GET_SECTION_END(Name) get_win_section_end(#Name)
# else
# define GET_SECTION_START(Name) SECTION_START(Name)
# define GET_SECTION_END(Name) SECTION_END(Name)
# endif
#endif /* !POSIX_COMPAT_H_ */

View file

@ -31,15 +31,16 @@
#include "criterion/ordered-set.h"
#include "report.h"
#include "config.h"
#include "posix-compat.h"
#define IMPL_CALL_REPORT_HOOKS(Kind) \
IMPL_SECTION_LIMITS(f_report_hook, crit_ ## Kind); \
void call_report_hooks_##Kind(void *data) { \
for (f_report_hook *hook = SECTION_START(crit_ ## Kind); \
hook < SECTION_END(crit_ ## Kind); \
++hook) { \
(*hook)(data); \
} \
#define IMPL_CALL_REPORT_HOOKS(Kind) \
IMPL_SECTION_LIMITS(f_report_hook, HOOK_SECTION(Kind)); \
void call_report_hooks_##Kind(void *data) { \
for (f_report_hook *hook = GET_SECTION_START(HOOK_SECTION(Kind)); \
hook < (f_report_hook*) GET_SECTION_END(HOOK_SECTION(Kind)); \
++hook) { \
(*hook)(data); \
} \
}
IMPL_CALL_REPORT_HOOKS(PRE_ALL);

View file

@ -28,8 +28,8 @@
# define report(Kind, Data) call_report_hooks_##Kind(Data)
# define DECL_CALL_REPORT_HOOKS(Kind) \
DECL_SECTION_LIMITS(f_report_hook, crit_ ## Kind); \
# define DECL_CALL_REPORT_HOOKS(Kind) \
DECL_SECTION_LIMITS(f_report_hook, HOOK_SECTION(Kind)); \
void call_report_hooks_##Kind(void *data)
DECL_CALL_REPORT_HOOKS(PRE_ALL);

View file

@ -41,8 +41,8 @@
#include "extmatch.h"
#endif
IMPL_SECTION_LIMITS(struct criterion_test, criterion_tests);
IMPL_SECTION_LIMITS(struct criterion_suite, crit_suites);
IMPL_SECTION_LIMITS(struct criterion_test, cr_tst);
IMPL_SECTION_LIMITS(struct criterion_suite, cr_sts);
// This is here to make the test suite & test sections non-empty
TestSuite();
@ -75,6 +75,9 @@ struct criterion_test_set *criterion_init(void) {
struct criterion_ordered_set *suites = new_ordered_set(cmp_suite, dtor_suite_set);
FOREACH_SUITE_SEC(s) {
if (!s->name)
break;
struct criterion_suite_set css = {
.suite = *s,
};
@ -83,6 +86,9 @@ struct criterion_test_set *criterion_init(void) {
size_t nb_tests = 0;
FOREACH_TEST_SEC(test) {
if (!test->category)
break;
if (!*test->category)
continue;

View file

@ -25,20 +25,21 @@
# define CRITERION_RUNNER_H_
# include "criterion/types.h"
# include "posix-compat.h"
DECL_SECTION_LIMITS(struct criterion_test, criterion_tests);
DECL_SECTION_LIMITS(struct criterion_suite, crit_suites);
DECL_SECTION_LIMITS(struct criterion_test, cr_tst);
DECL_SECTION_LIMITS(struct criterion_suite, cr_sts);
struct criterion_test_set *criterion_init(void);
# define FOREACH_TEST_SEC(Test) \
for (struct criterion_test *Test = SECTION_START(criterion_tests); \
Test < SECTION_END(criterion_tests); \
for (struct criterion_test *Test = GET_SECTION_START(cr_tst); \
Test < (struct criterion_test*) GET_SECTION_END(cr_tst); \
++Test)
# define FOREACH_SUITE_SEC(Suite) \
for (struct criterion_suite *Suite = SECTION_START(crit_suites); \
Suite < SECTION_END(crit_suites); \
for (struct criterion_suite *Suite = GET_SECTION_START(cr_sts); \
Suite < (struct criterion_suite*) GET_SECTION_END(cr_sts); \
++Suite)
#endif /* !CRITERION_RUNNER_H_ */