Commit 83f8b226 authored by Fabian Maurer's avatar Fabian Maurer Committed by Alexandre Julliard

msvcrt: Use already existent oneexit_table functions for _onexit and _c_exit.

parent 58c49279
......@@ -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,93 @@ static int MSVCRT_error_mode = MSVCRT__OUT_TO_DEFAULT;
void (*CDECL _aexit_rtn)(int) = MSVCRT__exit;
/* INTERNAL: call atexit functions */
static void __MSVCRT__call_atexit(void)
static int initialize_onexit_table(MSVCRT__onexit_table_t *table)
{
/* 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");
}
if (!table)
return -1;
if (table->_first == table->_end)
table->_last = table->_end = table->_first = NULL;
return 0;
}
static int 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;
}
static int 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));
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;
}
static void call_atexit(void)
{
/* Note: should only be called with the exit lock held */
if (tls_atexit_callback) tls_atexit_callback(NULL, DLL_PROCESS_DETACH, NULL);
execute_onexit_table(&MSVCRT_atexit_table);
}
/*********************************************************************
......@@ -277,7 +348,7 @@ void CDECL MSVCRT__cexit(void)
{
TRACE("(void)\n");
LOCK_EXIT;
__MSVCRT__call_atexit();
call_atexit();
UNLOCK_EXIT;
}
......@@ -292,25 +363,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++;
register_onexit_function(&MSVCRT_atexit_table, func);
UNLOCK_EXIT;
return func;
}
......@@ -359,7 +414,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 +421,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 initialize_onexit_table(table);
}
/*********************************************************************
......@@ -382,43 +431,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 register_onexit_function(table, func);
}
/*********************************************************************
......@@ -426,35 +439,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 execute_onexit_table(table);
}
/*********************************************************************
......
......@@ -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,52 @@ 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)
{
PROCESS_INFORMATION proc;
STARTUPINFOA startup = {0};
char path[MAX_PATH];
HANDLE exit_event;
DWORD ret;
exit_event = CreateEventA(NULL, FALSE, FALSE, "exit_event");
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_event, 0);
ok(ret == WAIT_OBJECT_0, "exit_event was not 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");
ok(exit_event != NULL, "CreateEvent failed: %d\n", GetLastError());
ok(atexit_called == 1, "atexit_called = %d\n", atexit_called);
atexit_called++;
SetEvent(exit_event);
CloseHandle(exit_event);
}
static void CDECL at_exit_func2(void)
{
ok(!atexit_called, "atexit_called = %d\n", atexit_called);
atexit_called++;
}
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 +825,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 +844,5 @@ START_TEST(misc)
test_isblank();
test_math_errors();
test_asctime();
test_exit(arg_v[0]);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment