Module: wine Branch: master Commit: 89b8f3d712777e8b36b026e3e71ec54a862cc8be URL: https://source.winehq.org/git/wine.git/?a=commit;h=89b8f3d712777e8b36b026e3e...
Author: Fabian Maurer dark.shadow4@web.de Date: Mon Jul 9 18:04:09 2018 +0200
ucrtbase: Implement quick_exit and _crt_at_quick_exit.
Signed-off-by: Fabian Maurer dark.shadow4@web.de Signed-off-by: Piotr Caban piotr@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/msvcrt/exit.c | 12 +++++-- dlls/ucrtbase/tests/misc.c | 85 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 4 deletions(-)
diff --git a/dlls/msvcrt/exit.c b/dlls/msvcrt/exit.c index 90efb76..b84c50a 100644 --- a/dlls/msvcrt/exit.c +++ b/dlls/msvcrt/exit.c @@ -40,6 +40,10 @@ typedef struct MSVCRT__onexit_table_t
static MSVCRT__onexit_table_t MSVCRT_atexit_table;
+#if _MSVCR_VER>=140 +static MSVCRT__onexit_table_t MSVCRT_quick_exit_table; +#endif + typedef void (__stdcall *_tls_callback_type)(void*,ULONG,void*); static _tls_callback_type tls_atexit_callback;
@@ -410,8 +414,8 @@ int CDECL MSVCRT_atexit(void (__cdecl *func)(void)) */ int CDECL MSVCRT__crt_at_quick_exit(void (__cdecl *func)(void)) { - FIXME("(%p) stub\n", func); - return -1; + TRACE("(%p)\n", func); + return register_onexit_function(&MSVCRT_quick_exit_table, (MSVCRT__onexit_t)func); }
/********************************************************************* @@ -419,7 +423,9 @@ int CDECL MSVCRT__crt_at_quick_exit(void (__cdecl *func)(void)) */ void CDECL MSVCRT_quick_exit(int exitcode) { - FIXME("(%d) semi-stub\n", exitcode); + TRACE("(%d)\n", exitcode); + + execute_onexit_table(&MSVCRT_quick_exit_table); MSVCRT__exit(exitcode); }
diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c index fad9311..555dc2d 100644 --- a/dlls/ucrtbase/tests/misc.c +++ b/dlls/ucrtbase/tests/misc.c @@ -127,6 +127,8 @@ static int* (CDECL *p_errno)(void); static char* (CDECL *p_asctime)(const struct tm *); static void (CDECL *p_exit)(int); static int (CDECL *p__crt_atexit)(void (CDECL*)(void)); +static int (__cdecl *p_crt_at_quick_exit)(void (__cdecl *func)(void)); +static void (__cdecl *p_quick_exit)(int exitcode);
static void test__initialize_onexit_table(void) { @@ -433,6 +435,8 @@ static BOOL init(void) p_asctime = (void*)GetProcAddress(module, "asctime"); p__crt_atexit = (void*)GetProcAddress(module, "_crt_atexit"); p_exit = (void*)GetProcAddress(module, "exit"); + p_crt_at_quick_exit = (void*)GetProcAddress(module, "_crt_at_quick_exit"); + p_quick_exit = (void*)GetProcAddress(module, "quick_exit");
return TRUE; } @@ -797,11 +801,12 @@ static void test_exit(const char *argv0) PROCESS_INFORMATION proc; STARTUPINFOA startup = {0}; char path[MAX_PATH]; - HANDLE failures_map, exit_event; + HANDLE failures_map, exit_event, quick_exit_event; LONG *failures; DWORD ret;
exit_event = CreateEventA(NULL, FALSE, FALSE, "exit_event"); + quick_exit_event = CreateEventA(NULL, FALSE, FALSE, "quick_exit_event");
failures = get_failures_counter(&failures_map); sprintf(path, "%s misc exit", argv0); @@ -819,11 +824,15 @@ static void test_exit(const char *argv0)
ret = WaitForSingleObject(exit_event, 0); ok(ret == WAIT_OBJECT_0, "exit_event was not set (%x)\n", ret); + ret = WaitForSingleObject(quick_exit_event, 0); + ok(ret == WAIT_TIMEOUT, "quick_exit_event should not have be set (%x)\n", ret);
CloseHandle(exit_event); + CloseHandle(quick_exit_event); }
static int atexit_called; + static void CDECL at_exit_func1(void) { HANDLE exit_event = CreateEventA(NULL, FALSE, FALSE, "exit_event"); @@ -843,14 +852,85 @@ static void CDECL at_exit_func2(void) set_failures_counter(winetest_get_failures()); }
+static int atquick_exit_called; + +static void CDECL at_quick_exit_func1(void) +{ + HANDLE quick_exit_event = CreateEventA(NULL, FALSE, FALSE, "quick_exit_event"); + + ok(quick_exit_event != NULL, "CreateEvent failed: %d\n", GetLastError()); + ok(atquick_exit_called == 1, "atquick_exit_called = %d\n", atquick_exit_called); + atquick_exit_called++; + SetEvent(quick_exit_event); + CloseHandle(quick_exit_event); + set_failures_counter(winetest_get_failures()); +} + +static void CDECL at_quick_exit_func2(void) +{ + ok(!atquick_exit_called, "atquick_exit_called = %d\n", atquick_exit_called); + atquick_exit_called++; + set_failures_counter(winetest_get_failures()); +} + static void test_call_exit(void) { ok(!p__crt_atexit(at_exit_func1), "_crt_atexit failed\n"); ok(!p__crt_atexit(at_exit_func2), "_crt_atexit failed\n"); + + ok(!p_crt_at_quick_exit(at_quick_exit_func1), "_crt_at_quick_exit failed\n"); + ok(!p_crt_at_quick_exit(at_quick_exit_func2), "_crt_at_quick_exit failed\n"); + set_failures_counter(winetest_get_failures()); p_exit(1); }
+static void test_call_quick_exit(void) +{ + ok(!p__crt_atexit(at_exit_func1), "_crt_atexit failed\n"); + ok(!p__crt_atexit(at_exit_func2), "_crt_atexit failed\n"); + + ok(!p_crt_at_quick_exit(at_quick_exit_func1), "_crt_at_quick_exit failed\n"); + ok(!p_crt_at_quick_exit(at_quick_exit_func2), "_crt_at_quick_exit failed\n"); + + set_failures_counter(winetest_get_failures()); + p_quick_exit(2); +} + +static void test_quick_exit(const char *argv0) +{ + PROCESS_INFORMATION proc; + STARTUPINFOA startup = {0}; + char path[MAX_PATH]; + HANDLE failures_map, exit_event, quick_exit_event; + LONG *failures; + DWORD ret; + + exit_event = CreateEventA(NULL, FALSE, FALSE, "exit_event"); + quick_exit_event = CreateEventA(NULL, FALSE, FALSE, "quick_exit_event"); + + failures = get_failures_counter(&failures_map); + sprintf(path, "%s misc quick_exit", argv0); + startup.cb = sizeof(startup); + CreateProcessA(NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &proc); + ret = WaitForSingleObject(proc.hProcess, INFINITE); + ok(ret == WAIT_OBJECT_0, "child process wait failed\n"); + GetExitCodeProcess(proc.hProcess, &ret); + ok(ret == 2, "child process exited with code %d\n", ret); + CloseHandle(proc.hProcess); + CloseHandle(proc.hThread); + ok(!*failures, "%d tests failed in child process\n", *failures); + free_failures_counter(failures, failures_map); + + ret = WaitForSingleObject(quick_exit_event, 0); + ok(ret == WAIT_OBJECT_0, "quick_exit_event was not set (%x)\n", ret); + ret = WaitForSingleObject(exit_event, 0); + ok(ret == WAIT_TIMEOUT, "exit_event should not have be set (%x)\n", ret); + + CloseHandle(exit_event); + CloseHandle(quick_exit_event); +} + START_TEST(misc) { int arg_c; @@ -865,6 +945,8 @@ START_TEST(misc) test__get_narrow_winmain_command_line(NULL); else if(!strcmp(arg_v[2], "exit")) test_call_exit(); + else if(!strcmp(arg_v[2], "quick_exit")) + test_call_quick_exit(); return; }
@@ -881,4 +963,5 @@ START_TEST(misc) test_math_errors(); test_asctime(); test_exit(arg_v[0]); + test_quick_exit(arg_v[0]); }