Merge branch 'features/windows-compat' into bleeding
This commit is contained in:
commit
ea5a074ff4
9 changed files with 178 additions and 52 deletions
|
@ -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), \
|
||||
|
|
|
@ -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_
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include "common.h"
|
||||
|
||||
struct criterion_test_extra_data {
|
||||
int sentinel_;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
||||
|
|
17
src/report.c
17
src/report.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
10
src/runner.c
10
src/runner.c
|
@ -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;
|
||||
|
||||
|
|
13
src/runner.h
13
src/runner.h
|
@ -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_ */
|
||||
|
|
Loading…
Add table
Reference in a new issue