[PATCH v3] msvcrt: Use already existent oneexit_table functions for _onexit and _c_exit

Fabian Maurer dark.shadow4 at web.de
Fri Jun 22 14:04:34 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

v3:
Keep exitlock
Keep _MSVCR_VER>=140 functions _MSVCR_VER>=140

Signed-off-by: Fabian Maurer <dark.shadow4 at web.de>
---
 dlls/msvcrt/exit.c         | 195 ++++++++++++++++++-------------------
 dlls/ucrtbase/tests/misc.c |  74 +++++++++++++-
 2 files changed, 166 insertions(+), 103 deletions(-)

diff --git a/dlls/msvcrt/exit.c b/dlls/msvcrt/exit.c
index 7e1805569c4..602a80a0513 100644
--- a/dlls/msvcrt/exit.c
+++ b/dlls/msvcrt/exit.c
@@ -29,9 +29,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
 #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 +38,8 @@ typedef struct MSVCRT__onexit_table_t
     MSVCRT__onexit_t *_end;
 } MSVCRT__onexit_table_t;
 
+static MSVCRT__onexit_table_t MSVCRT_atexit_table;
+
 typedef void (__stdcall *_tls_callback_type)(void*,ULONG,void*);
 static _tls_callback_type tls_atexit_callback;
 
@@ -61,21 +60,97 @@ static int MSVCRT_error_mode = MSVCRT__OUT_TO_DEFAULT;
 
 void (*CDECL _aexit_rtn)(int) = MSVCRT__exit;
 
+static int __MSVCRT__initialize_onexit_table(MSVCRT__onexit_table_t *table)
+{
+    if (!table)
+        return -1;
+
+    if (table->_first == table->_end)
+        table->_last = table->_end = table->_first = NULL;
+    return 0;
+}
+
+
+/* INTERNAL: register onexit function */
+static int __MSVCRT__register_onexit_function(MSVCRT__onexit_table_t *table, MSVCRT__onexit_t func)
+{
+    if (!table)
+        return -1;
+
+    EnterCriticalSection(&MSVCRT_onexit_cs);
+    if (!table->_first)
+    {
+        table->_first = MSVCRT_calloc(32, sizeof(void *));
+        if (!table->_first)
+        {
+            WARN("failed to allocate initial table.\n");
+            LeaveCriticalSection(&MSVCRT_onexit_cs);
+            return -1;
+        }
+        table->_last = table->_first;
+        table->_end = table->_first + 32;
+    }
+
+    /* grow if full */
+    if (table->_last == table->_end)
+    {
+        int len = table->_end - table->_first;
+        MSVCRT__onexit_t *tmp = MSVCRT_realloc(table->_first, 2 * len * sizeof(void *));
+        if (!tmp)
+        {
+            WARN("failed to grow table.\n");
+            LeaveCriticalSection(&MSVCRT_onexit_cs);
+            return -1;
+        }
+        table->_first = tmp;
+        table->_end = table->_first + 2 * len;
+        table->_last = table->_first + len;
+    }
+
+    *table->_last = func;
+    table->_last++;
+    LeaveCriticalSection(&MSVCRT_onexit_cs);
+    return 0;
+}
+
+/* INTERNAL: call onexit functions */
+static int __MSVCRT__execute_onexit_table(MSVCRT__onexit_table_t *table)
+{
+    MSVCRT__onexit_t *func;
+    MSVCRT__onexit_table_t copy;
+
+    if (!table)
+        return -1;
+
+    EnterCriticalSection(&MSVCRT_onexit_cs);
+    if (!table->_first || table->_first >= table->_last)
+    {
+        LeaveCriticalSection(&MSVCRT_onexit_cs);
+        return 0;
+    }
+    copy._first = table->_first;
+    copy._last  = table->_last;
+    copy._end   = table->_end;
+    memset(table, 0, sizeof(*table));
+    __MSVCRT__initialize_onexit_table(table);
+    LeaveCriticalSection(&MSVCRT_onexit_cs);
+
+    for (func = copy._last - 1; func >= copy._first; func--)
+    {
+        if (*func)
+           (*func)();
+    }
+
+    MSVCRT_free(copy._first);
+    return 0;
+}
+
 /* INTERNAL: call atexit functions */
 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);
 }
 
 /*********************************************************************
@@ -292,25 +367,9 @@ MSVCRT__onexit_t CDECL MSVCRT__onexit(MSVCRT__onexit_t 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++;
+  __MSVCRT__register_onexit_function(&MSVCRT_atexit_table, func);
   UNLOCK_EXIT;
+
   return func;
 }
 
@@ -359,7 +418,6 @@ int CDECL MSVCRT__crt_atexit(void (*func)(void))
   return MSVCRT__onexit((MSVCRT__onexit_t)func) == (MSVCRT__onexit_t)func ? 0 : -1;
 }
 
-
 /*********************************************************************
  *		_initialize_onexit_table (UCRTBASE.@)
  */
@@ -367,12 +425,7 @@ int CDECL MSVCRT__initialize_onexit_table(MSVCRT__onexit_table_t *table)
 {
     TRACE("(%p)\n", table);
 
-    if (!table)
-        return -1;
-
-    if (table->_first == table->_end)
-        table->_last = table->_end = table->_first = NULL;
-    return 0;
+    return __MSVCRT__initialize_onexit_table(table);
 }
 
 /*********************************************************************
@@ -382,43 +435,7 @@ int CDECL MSVCRT__register_onexit_function(MSVCRT__onexit_table_t *table, MSVCRT
 {
     TRACE("(%p %p)\n", table, func);
 
-    if (!table)
-        return -1;
-
-    EnterCriticalSection(&MSVCRT_onexit_cs);
-    if (!table->_first)
-    {
-        table->_first = MSVCRT_calloc(32, sizeof(void *));
-        if (!table->_first)
-        {
-            WARN("failed to allocate initial table.\n");
-            LeaveCriticalSection(&MSVCRT_onexit_cs);
-            return -1;
-        }
-        table->_last = table->_first;
-        table->_end = table->_first + 32;
-    }
-
-    /* grow if full */
-    if (table->_last == table->_end)
-    {
-        int len = table->_end - table->_first;
-        MSVCRT__onexit_t *tmp = MSVCRT_realloc(table->_first, 2 * len * sizeof(void *));
-        if (!tmp)
-        {
-            WARN("failed to grow table.\n");
-            LeaveCriticalSection(&MSVCRT_onexit_cs);
-            return -1;
-        }
-        table->_first = tmp;
-        table->_end = table->_first + 2 * len;
-        table->_last = table->_first + len;
-    }
-
-    *table->_last = func;
-    table->_last++;
-    LeaveCriticalSection(&MSVCRT_onexit_cs);
-    return 0;
+    return __MSVCRT__register_onexit_function(table, func);
 }
 
 /*********************************************************************
@@ -426,35 +443,9 @@ int CDECL MSVCRT__register_onexit_function(MSVCRT__onexit_table_t *table, MSVCRT
  */
 int CDECL MSVCRT__execute_onexit_table(MSVCRT__onexit_table_t *table)
 {
-    MSVCRT__onexit_t *func;
-    MSVCRT__onexit_table_t copy;
-
     TRACE("(%p)\n", table);
 
-    if (!table)
-        return -1;
-
-    EnterCriticalSection(&MSVCRT_onexit_cs);
-    if (!table->_first || table->_first >= table->_last)
-    {
-        LeaveCriticalSection(&MSVCRT_onexit_cs);
-        return 0;
-    }
-    copy._first = table->_first;
-    copy._last  = table->_last;
-    copy._end   = table->_end;
-    memset(table, 0, sizeof(*table));
-    MSVCRT__initialize_onexit_table(table);
-    LeaveCriticalSection(&MSVCRT_onexit_cs);
-
-    for (func = copy._last - 1; func >= copy._first; func--)
-    {
-        if (*func)
-           (*func)();
-    }
-
-    MSVCRT_free(copy._first);
-    return 0;
+    return __MSVCRT__execute_onexit_table(table);
 }
 
 /*********************************************************************
diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c
index 354fab1e940..ed5bb0589c8 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.18.0




More information about the wine-devel mailing list