[PATCH v2] msvcrt: Use already existent oneexit_table functions for _onexit and _c_exit
Fabian Maurer
dark.shadow4 at web.de
Sun Jun 17 12:48:19 CDT 2018
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 <dark.shadow4 at web.de>
---
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
More information about the wine-devel
mailing list