1
0
forked from 0ad/0ad
0ad/source/lib/lib.cpp
2004-05-13 13:52:48 +00:00

111 lines
2.8 KiB
C++
Executable File

// Copyright (c) 2003 Jan Wassenberg
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// Contact info:
// Jan.Wassenberg@stud.uni-karlsruhe.de
// http://www.stud.uni-karlsruhe.de/~urkt/
#include "precompiled.h"
#include "types.h"
#include "lib.h"
// more powerful atexit, with 0 or 1 parameters.
// callable before libc initialized, frees up the real atexit table,
// and often obviates a separate cleanup_everything function.
//
// problem: some of the functions registered here must be called after
// all other shutdown code (e.g. Winsock cleanup).
// we can't wedge ourselves between the regular atexit calls and
// process termination, so hooking exit isn't possible.
// need to use regular atexit, which must be called after _cinit.
// AFAIK, we can't interpose ourselves between libc init and constructors
// either, so constructors MUST NOT:
// - exit() (otherwise, some resources leak, because our atexit handler
// wouldn't have been registered yet - it's done from main())
// - call atexit (our exit handler would be called before its handler,
// so we may have shut down something important already).
const int MAX_EXIT_FUNCS = 64;
static struct ExitFunc
{
void* func;
uintptr_t arg;
CallConvention cc;
}
exit_funcs[MAX_EXIT_FUNCS];
static int num_exit_funcs;
// call all registered exit handlers in LIFO order.
// called from exit, so don't worry about thread safety.
static void call_exit_funcs(void)
{
ExitFunc* p = exit_funcs;
for(int i = num_exit_funcs-1; i >= 0; i--)
{
switch(p->cc)
{
case CC_CDECL_0:
((void(*)(void))p->func)();
break;
case CC_CDECL_1:
((void(*)(uintptr_t))p->func)(p->arg);
break;
#ifdef _WIN32
case CC_STDCALL_0:
((void(__stdcall*)(void))p->func)();
break;
case CC_STDCALL_1:
((void(__stdcall*)(uintptr_t))p->func)(p->arg);
break;
#endif
default:
debug_warn("call_exit_funcs: invalid calling convention in ExitFunc!");
}
p++;
}
num_exit_funcs = 0;
}
int atexit2(void* func, uintptr_t arg, CallConvention cc)
{
if(num_exit_funcs >= MAX_EXIT_FUNCS)
{
debug_warn("atexit2: too many functions registered. increase MAX_EXIT_FUNCS");
return -1;
}
ExitFunc* p = &exit_funcs[num_exit_funcs++];
p->func = func;
p->arg = arg;
p->cc = cc;
return 0;
}
int atexit2(void* func)
{
return atexit2(func, 0, CC_CDECL_0);
}
// call from main as early as possible.
void lib_init()
{
atexit(call_exit_funcs);
}