From: Fabian Maurer Subject: [PATCH v2 4/4] msvcrt: Implement quick_exit and _crt_at_quick_exit Message-Id: <20180704202758.26877-4-dark.shadow4@web.de> Date: Wed, 4 Jul 2018 22:27:58 +0200 In-Reply-To: <20180704202758.26877-1-dark.shadow4@web.de> References: <20180704202758.26877-1-dark.shadow4@web.de> Signed-off-by: Fabian Maurer --- dlls/msvcrt/exit.c | 19 +++++++++-- dlls/ucrtbase/tests/misc.c | 67 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/dlls/msvcrt/exit.c b/dlls/msvcrt/exit.c index 6dcf0db2731..4165cf66bb9 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,14 @@ int CDECL MSVCRT_atexit(void (__cdecl *func)(void)) */ int CDECL MSVCRT__crt_at_quick_exit(void (__cdecl *func)(void)) { - FIXME("stub: (%p)\n", func); - return -1; + TRACE("(%p)\n", func); + + if (!func) + return -1; + + register_onexit_function(&MSVCRT_quick_exit_table, (MSVCRT__onexit_t)func); + + return 0; } /********************************************************************* @@ -419,7 +429,10 @@ int CDECL MSVCRT__crt_at_quick_exit(void (__cdecl *func)(void)) */ void CDECL MSVCRT_quick_exit(int exitcode) { - FIXME("partial stub: (%d)\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 54ae4e94714..09df67535ff 100644 --- a/dlls/ucrtbase/tests/misc.c +++ b/dlls/ucrtbase/tests/misc.c @@ -778,10 +778,11 @@ static void test_exit(const char *argv0) PROCESS_INFORMATION proc; STARTUPINFOA startup = {0}; char path[MAX_PATH]; - HANDLE exit_event; + HANDLE exit_event, quick_exit_event; DWORD ret; exit_event = CreateEventA(NULL, FALSE, FALSE, "exit_event"); + quick_exit_event = CreateEventA(NULL, FALSE, FALSE, "quick_exit_event"); sprintf(path, "%s misc exit", argv0); startup.cb = sizeof(startup); @@ -790,11 +791,14 @@ 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); } static int atexit_called; + static void CDECL at_exit_func1(void) { HANDLE exit_event = CreateEventA(NULL, FALSE, FALSE, "exit_event"); @@ -819,10 +823,65 @@ static void test_call_exit(void) p_exit(0); } -static void test_quick_exit(void) +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); +} + +static void CDECL at_quick_exit_func2(void) { + ok(!atquick_exit_called, "atquick_exit_called = %d\n", atquick_exit_called); + atquick_exit_called++; +} + +static void test_call_quick_exit(void) +{ + 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"); + p_quick_exit(0); +} + +static void test_quick_exit(const char *argv0) +{ + PROCESS_INFORMATION proc; + STARTUPINFOA startup = {0}; + char path[MAX_PATH]; + HANDLE exit_event, quick_exit_event; + DWORD ret; + int result; + ok(p_crt_at_quick_exit != NULL, "_crt_at_quick_exit should exist in this version\n"); ok(p_quick_exit != NULL, "quick_exit should exist in this version\n"); + + result = p_crt_at_quick_exit(at_quick_exit_func2); + ok(result == 0, "Expected success."); + + result = p_crt_at_quick_exit(NULL); + ok(result == -1, "Expected failure."); + + + exit_event = CreateEventA(NULL, FALSE, FALSE, "exit_event"); + quick_exit_event = CreateEventA(NULL, FALSE, FALSE, "quick_exit_event"); + + sprintf(path, "%s misc quick_exit", argv0); + startup.cb = sizeof(startup); + CreateProcessA(NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &proc); + winetest_wait_child_process(proc.hProcess); + + 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); } START_TEST(misc) @@ -839,6 +898,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; } @@ -855,5 +916,5 @@ START_TEST(misc) test_math_errors(); test_asctime(); test_exit(arg_v[0]); - test_quick_exit(); + test_quick_exit(arg_v[0]); } -- 2.18.0