msvcrt: Use already existent oneexit_table functions for _onexit and _c_exit.
Signed-off-by: Fabian Maurer <dark.shadow4@web.de> Signed-off-by: Piotr Caban <piotr@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
58c49279f5
commit
83f8b22694
|
@ -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]);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue