diff --git a/include/criterion/criterion.h b/include/criterion/criterion.h index 48b3dcf..50c85b2 100644 --- a/include/criterion/criterion.h +++ b/include/criterion/criterion.h @@ -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), \ diff --git a/include/criterion/hooks.h b/include/criterion/hooks.h index a8b7bfa..c597467 100644 --- a/include/criterion/hooks.h +++ b/include/criterion/hooks.h @@ -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_ diff --git a/include/criterion/types.h b/include/criterion/types.h index 6e7dae2..f508174 100644 --- a/include/criterion/types.h +++ b/include/criterion/types.h @@ -26,6 +26,7 @@ # include # include +# include "common.h" struct criterion_test_extra_data { int sentinel_; diff --git a/src/posix-compat.c b/src/posix-compat.c index 020d61f..d756c9a 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -1,3 +1,4 @@ +#include #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 diff --git a/src/posix-compat.h b/src/posix-compat.h index 477361e..0ee7a57 100644 --- a/src/posix-compat.h +++ b/src/posix-compat.h @@ -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_ */ diff --git a/src/report.c b/src/report.c index 92852da..8f8bf39 100644 --- a/src/report.c +++ b/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); diff --git a/src/report.h b/src/report.h index 6a740c5..aab2a10 100644 --- a/src/report.h +++ b/src/report.h @@ -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); diff --git a/src/runner.c b/src/runner.c index 408554f..db95f9f 100644 --- a/src/runner.c +++ b/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; diff --git a/src/runner.h b/src/runner.h index 9cb4156..e78fd96 100644 --- a/src/runner.h +++ b/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_ */