From: Fabian Maurer Subject: [PATCH v2] msvcrt: Use already existent oneexit_table functions for _onexit and _c_exit Message-Id: <20180617174819.17166-1-dark.shadow4@web.de> Date: Sun, 17 Jun 2018 19:48:19 +0200 For that to work, MSVCRT__register_onexit_function and MSVCRT__execute_onexit_table have to available all the time, not only when _MSVCR_VER>=140 tests based on code by Piotr Caban v2: Create exit_event2 in test function, so it exists in child process Signed-off-by: Fabian Maurer --- dlls/msvcrt/exit.c | 68 ++++++++++------------------------- dlls/ucrtbase/tests/misc.c | 74 +++++++++++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 51 deletions(-) diff --git a/dlls/msvcrt/exit.c b/dlls/msvcrt/exit.c index 7e1805569c..c90f7df953 100644 --- a/dlls/msvcrt/exit.c +++ b/dlls/msvcrt/exit.c @@ -25,13 +25,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); -/* MT */ -#define LOCK_EXIT _mlock(_EXIT_LOCK1) -#define UNLOCK_EXIT _munlock(_EXIT_LOCK1) - -static MSVCRT__onexit_t *MSVCRT_atexit_table = NULL; -static int MSVCRT_atexit_table_size = 0; -static int MSVCRT_atexit_registered = 0; /* Points to free slot */ static MSVCRT_purecall_handler purecall_handler = NULL; typedef struct MSVCRT__onexit_table_t @@ -41,6 +34,11 @@ typedef struct MSVCRT__onexit_table_t MSVCRT__onexit_t *_end; } MSVCRT__onexit_table_t; +static MSVCRT__onexit_table_t MSVCRT_atexit_table; + +int CDECL MSVCRT__register_onexit_function(MSVCRT__onexit_table_t *table, MSVCRT__onexit_t func); +int CDECL MSVCRT__execute_onexit_table(MSVCRT__onexit_table_t *table); + typedef void (__stdcall *_tls_callback_type)(void*,ULONG,void*); static _tls_callback_type tls_atexit_callback; @@ -65,17 +63,8 @@ void (*CDECL _aexit_rtn)(int) = MSVCRT__exit; static void __MSVCRT__call_atexit(void) { /* Note: should only be called with the exit lock held */ - TRACE("%d atext functions to call\n", MSVCRT_atexit_registered); if (tls_atexit_callback) tls_atexit_callback(NULL, DLL_PROCESS_DETACH, NULL); - /* Last registered gets executed first */ - while (MSVCRT_atexit_registered > 0) - { - MSVCRT_atexit_registered--; - TRACE("next is %p\n",MSVCRT_atexit_table[MSVCRT_atexit_registered]); - if (MSVCRT_atexit_table[MSVCRT_atexit_registered]) - (*MSVCRT_atexit_table[MSVCRT_atexit_registered])(); - TRACE("returned\n"); - } + MSVCRT__execute_onexit_table(&MSVCRT_atexit_table); } /********************************************************************* @@ -276,9 +265,7 @@ void CDECL MSVCRT__c_exit(void) void CDECL MSVCRT__cexit(void) { TRACE("(void)\n"); - LOCK_EXIT; __MSVCRT__call_atexit(); - UNLOCK_EXIT; } /********************************************************************* @@ -291,26 +278,8 @@ MSVCRT__onexit_t CDECL MSVCRT__onexit(MSVCRT__onexit_t func) if (!func) return NULL; - LOCK_EXIT; - if (MSVCRT_atexit_registered > MSVCRT_atexit_table_size - 1) - { - MSVCRT__onexit_t *newtable; - TRACE("expanding table\n"); - newtable = MSVCRT_calloc(MSVCRT_atexit_table_size + 32, sizeof(void *)); - if (!newtable) - { - TRACE("failed!\n"); - UNLOCK_EXIT; - return NULL; - } - memcpy (newtable, MSVCRT_atexit_table, MSVCRT_atexit_table_size*sizeof(void *)); - MSVCRT_atexit_table_size += 32; - MSVCRT_free (MSVCRT_atexit_table); - MSVCRT_atexit_table = newtable; - } - MSVCRT_atexit_table[MSVCRT_atexit_registered] = func; - MSVCRT_atexit_registered++; - UNLOCK_EXIT; + MSVCRT__register_onexit_function(&MSVCRT_atexit_table, func); + return func; } @@ -359,6 +328,16 @@ int CDECL MSVCRT__crt_atexit(void (*func)(void)) return MSVCRT__onexit((MSVCRT__onexit_t)func) == (MSVCRT__onexit_t)func ? 0 : -1; } +/********************************************************************* + * _register_thread_local_exe_atexit_callback (UCRTBASE.@) + */ +void CDECL _register_thread_local_exe_atexit_callback(_tls_callback_type callback) +{ + TRACE("(%p)\n", callback); + tls_atexit_callback = callback; +} + +#endif /* _MSVCR_VER>=140 */ /********************************************************************* * _initialize_onexit_table (UCRTBASE.@) @@ -457,17 +436,6 @@ int CDECL MSVCRT__execute_onexit_table(MSVCRT__onexit_table_t *table) return 0; } -/********************************************************************* - * _register_thread_local_exe_atexit_callback (UCRTBASE.@) - */ -void CDECL _register_thread_local_exe_atexit_callback(_tls_callback_type callback) -{ - TRACE("(%p)\n", callback); - tls_atexit_callback = callback; -} - -#endif /* _MSVCR_VER>=140 */ - #if _MSVCR_VER>=71 /********************************************************************* * _set_purecall_handler (MSVCR71.@) diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c index 354fab1e94..ed5bb0589c 100644 --- a/dlls/ucrtbase/tests/misc.c +++ b/dlls/ucrtbase/tests/misc.c @@ -125,6 +125,8 @@ static int (CDECL *p_fesetround)(int); static void (CDECL *p___setusermatherr)(MSVCRT_matherr_func); 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 void test__initialize_onexit_table(void) { @@ -429,6 +431,8 @@ static BOOL init(void) p___setusermatherr = (void*)GetProcAddress(module, "__setusermatherr"); p_errno = (void*)GetProcAddress(module, "_errno"); p_asctime = (void*)GetProcAddress(module, "asctime"); + p__crt_atexit = (void*)GetProcAddress(module, "_crt_atexit"); + p_exit = (void*)GetProcAddress(module, "exit"); return TRUE; } @@ -765,6 +769,70 @@ static void test_asctime(void) ok(!strcmp(ret, "Thu Jan 1 00:00:00 1970\n"), "asctime returned %s\n", ret); } +static void test_exit(const char *argv0) +{ + HANDLE exit_event1, exit_event2; + PROCESS_INFORMATION proc; + STARTUPINFOA startup = {0}; + char path[MAX_PATH]; + DWORD ret; + + exit_event1 = CreateEventA(NULL, FALSE, FALSE, "exit_event1"); + exit_event2 = CreateEventA(NULL, FALSE, FALSE, "exit_event2"); + + sprintf(path, "%s misc 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(exit_event1, 0); + ok(ret == WAIT_OBJECT_0, "exit_event1 was not set (%x)\n", ret); + + CloseHandle(exit_event1); + CloseHandle(exit_event2); +} + +static void CDECL at_exit_func1(void) +{ + HANDLE exit_event1 = CreateEventA(NULL, FALSE, FALSE, "exit_event1"); + HANDLE exit_event2 = CreateEventA(NULL, FALSE, FALSE, "exit_event2"); + DWORD ret; + + ok(exit_event1 != NULL, "CreateEvent failed: %d\n", GetLastError()); + ok(exit_event2 != NULL, "CreateEvent failed: %d\n", GetLastError()); + + ret = WaitForSingleObject(exit_event2, 0); + ok(ret == WAIT_OBJECT_0, "exit_event2 was not set (%x)\n", ret); + + SetEvent(exit_event1); + CloseHandle(exit_event1); + CloseHandle(exit_event2); +} + +static void CDECL at_exit_func2(void) +{ + HANDLE exit_event1 = CreateEventA(NULL, FALSE, FALSE, "exit_event1"); + HANDLE exit_event2 = CreateEventA(NULL, FALSE, FALSE, "exit_event2"); + DWORD ret; + + ok(exit_event1 != NULL, "CreateEvent failed: %d\n", GetLastError()); + ok(exit_event2 != NULL, "CreateEvent failed: %d\n", GetLastError()); + + ret = WaitForSingleObject(exit_event1, 0); + ok(ret == WAIT_TIMEOUT, "exit_event1 should not be set (%x)\n", ret); + + SetEvent(exit_event2); + CloseHandle(exit_event1); + CloseHandle(exit_event2); +} + +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"); + p_exit(0); +} + START_TEST(misc) { int arg_c; @@ -775,7 +843,10 @@ START_TEST(misc) arg_c = winetest_get_mainargs(&arg_v); if(arg_c == 3) { - test__get_narrow_winmain_command_line(NULL); + if(!strcmp(arg_v[2], "cmd")) + test__get_narrow_winmain_command_line(NULL); + else if(!strcmp(arg_v[2], "exit")) + test_call_exit(); return; } @@ -791,4 +862,5 @@ START_TEST(misc) test_isblank(); test_math_errors(); test_asctime(); + test_exit(arg_v[0]); } -- 2.17.1