[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