[PATCH v2 4/4] msvcrt: Implement quick_exit and _crt_at_quick_exit
Fabian Maurer
dark.shadow4 at web.de
Wed Jul 4 15:27:58 CDT 2018
Signed-off-by: Fabian Maurer <dark.shadow4 at web.de>
---
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
More information about the wine-devel
mailing list