# fixes for overzealous vc8 optimization and housekeeping
these are required by thesis and improve 0ad code. - sysdep/win init/shutdown mechanism is now better documented and survives clever vc8 optimization - moved some extern declarations from win_internal into separate headers main: remove debug_filter_add("LOADER") - was for my debugging convenience This was SVN commit r4752.
This commit is contained in:
parent
ecb83f12f4
commit
95f8aa126f
@ -52,6 +52,10 @@ AT_STARTUP(\
|
||||
# pragma comment(lib, "zlib1d.lib")
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
// several switch statements are going to have all cases removed.
|
||||
// squelch the corresponding warning.
|
||||
# pragma warning(disable: 4065)
|
||||
#endif
|
||||
|
||||
TIMER_ADD_CLIENT(tc_zip_inflate);
|
||||
@ -69,7 +73,9 @@ decompresses blocks from file_io callback.
|
||||
|
||||
static LibError LibError_from_zlib(int zlib_err, bool warn_if_failed = true)
|
||||
{
|
||||
LibError err;
|
||||
LibError err = ERR::FAIL;
|
||||
// (NB: don't just remove the cases - that raises a warning)
|
||||
#ifndef NO_ZLIB
|
||||
switch(zlib_err)
|
||||
{
|
||||
case Z_OK:
|
||||
@ -85,6 +91,7 @@ static LibError LibError_from_zlib(int zlib_err, bool warn_if_failed = true)
|
||||
default:
|
||||
err = ERR::FAIL; break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(warn_if_failed)
|
||||
DEBUG_WARN_ERR(err);
|
||||
@ -421,6 +428,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int dummy;
|
||||
}
|
||||
ZLibCompressor;
|
||||
|
||||
#endif // #ifndef NO_ZLIB
|
||||
|
||||
|
||||
|
@ -581,7 +581,7 @@ LibError file_init()
|
||||
|
||||
LibError file_shutdown()
|
||||
{
|
||||
stats_dump();
|
||||
file_stats_dump();
|
||||
path_shutdown();
|
||||
file_io_shutdown();
|
||||
return INFO::OK;
|
||||
|
@ -286,7 +286,7 @@ template<typename T> int percent(T num, T divisor)
|
||||
return (int)(100*num / divisor);
|
||||
}
|
||||
|
||||
void stats_dump()
|
||||
void file_stats_dump()
|
||||
{
|
||||
const double KB = 1e3; const double MB = 1e6; const double ms = 1e-3;
|
||||
|
||||
|
@ -64,7 +64,7 @@ extern void stats_block_cache(CacheRet cr);
|
||||
// archive builder
|
||||
extern void stats_ab_connection(bool already_exists);
|
||||
|
||||
extern void stats_dump();
|
||||
extern void file_stats_dump();
|
||||
|
||||
#else
|
||||
|
||||
@ -87,7 +87,7 @@ extern void stats_dump();
|
||||
#define stats_cache(cr, size, atom_fn)
|
||||
#define stats_block_cache(cr)
|
||||
#define stats_ab_connection(already_exists)
|
||||
#define stats_dump()
|
||||
#define file_stats_dump()
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -931,7 +931,7 @@ int h_get_refcnt(Handle h)
|
||||
|
||||
void h_mgr_shutdown()
|
||||
{
|
||||
debug_printf("==h_mgr_shutdown== (all handle frees after this are leaks)\n");
|
||||
debug_printf("H_MGR| shutdown. any handle frees after this are leaks!\n");
|
||||
|
||||
// forcibly close all open handles
|
||||
for(i32 i = 0; i <= last_in_use; i++)
|
||||
|
27
source/lib/secure_crt.cpp
Normal file
27
source/lib/secure_crt.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "secure_crt.h"
|
||||
|
||||
|
||||
int sprintf_s(char* buf, size_t max_chars, const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int len = vsnprintf(buf, max_chars, fmt, args);
|
||||
va_end(args);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
errno_t fopen_s(FILE** pfile, const char* filename, const char* mode)
|
||||
{
|
||||
*pfile = NULL;
|
||||
FILE* file = fopen(filename, mode);
|
||||
if(!file)
|
||||
return ENOENT;
|
||||
*pfile = file;
|
||||
return 0;
|
||||
}
|
13
source/lib/secure_crt.h
Normal file
13
source/lib/secure_crt.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef INCLUDED_SECURE_CRT
|
||||
#define INCLUDED_SECURE_CRT
|
||||
#if !HAVE_SECURE_CRT
|
||||
|
||||
extern int sprintf_s(char* buf, size_t max_chars, const char* fmt, ...);
|
||||
|
||||
typedef int errno_t;
|
||||
extern errno_t fopen_s(FILE** pfile, const char* filename, const char* mode);
|
||||
|
||||
#define fscanf_s fscanf
|
||||
|
||||
#endif // #if !HAVE_SECURE_CRT
|
||||
#endif // #ifndef INCLUDED_SECURE_CRT
|
@ -155,10 +155,10 @@ PfnDliHook __pfnDliFailureHook2;
|
||||
|
||||
|
||||
// note: must be last, since DLLs are unloaded here
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(y))
|
||||
#pragma SECTION_POST_ATEXIT(Y)
|
||||
WIN_REGISTER_FUNC(wdll_shutdown);
|
||||
#pragma data_seg()
|
||||
|
||||
#pragma FORCE_INCLUDE(wdll_shutdown)
|
||||
#pragma SECTION_RESTORE
|
||||
|
||||
|
||||
#pragma intrinsic(strlen,memcmp,memcpy)
|
||||
@ -632,3 +632,4 @@ EXTERN_C PfnDliHook __pfnDliNotifyHook2 = notify_hook;
|
||||
EXTERN_C PfnDliHook __pfnDliFailureHook2 = 0;
|
||||
|
||||
|
||||
|
||||
|
@ -34,9 +34,12 @@
|
||||
#include "lib/sysdep/cpu.h"
|
||||
#include "win_internal.h"
|
||||
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_MAIN(b))
|
||||
|
||||
#pragma SECTION_PRE_LIBC(D)
|
||||
WIN_REGISTER_FUNC(wdbg_init);
|
||||
#pragma data_seg()
|
||||
#pragma FORCE_INCLUDE(wdbg_init)
|
||||
#pragma SECTION_RESTORE
|
||||
|
||||
|
||||
// used to prevent the vectored exception handler from taking charge when
|
||||
// an exception is raised from the main thread (allows __try blocks to
|
||||
@ -731,9 +734,6 @@ static LibError wdbg_init(void)
|
||||
PVOID (WINAPI *pAddVectoredExceptionHandler)(IN ULONG FirstHandler, IN PVECTORED_EXCEPTION_HANDLER VectoredHandler);
|
||||
*(void**)&pAddVectoredExceptionHandler = GetProcAddress(hKernel32Dll, "AddVectoredExceptionHandler");
|
||||
FreeLibrary(hKernel32Dll);
|
||||
// make sure the reference is released so BoundsChecker
|
||||
// doesn't complain. it won't actually be unloaded anyway -
|
||||
// there is at least one other reference.
|
||||
if(pAddVectoredExceptionHandler)
|
||||
pAddVectoredExceptionHandler(TRUE, vectored_exception_handler);
|
||||
#endif
|
||||
@ -811,3 +811,4 @@ bool debug_is_stack_ptr(void* p)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,11 +48,13 @@
|
||||
#endif
|
||||
|
||||
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_LIBC(b))
|
||||
#pragma SECTION_PRE_LIBC(D)
|
||||
WIN_REGISTER_FUNC(wdbg_sym_init);
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(b))
|
||||
#pragma FORCE_INCLUDE(wdbg_sym_init)
|
||||
#pragma SECTION_POST_ATEXIT(J)
|
||||
WIN_REGISTER_FUNC(wdbg_sym_shutdown);
|
||||
#pragma data_seg()
|
||||
#pragma FORCE_INCLUDE(wdbg_sym_shutdown)
|
||||
#pragma SECTION_RESTORE
|
||||
|
||||
|
||||
// note: it is safe to use debug_assert/debug_warn/CHECK_ERR even during a
|
||||
|
@ -33,9 +33,10 @@
|
||||
#include "win_internal.h"
|
||||
|
||||
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(x))
|
||||
#pragma SECTION_POST_ATEXIT(J)
|
||||
WIN_REGISTER_FUNC(wdir_watch_shutdown);
|
||||
#pragma data_seg()
|
||||
#pragma FORCE_INCLUDE(wdir_watch_shutdown)
|
||||
#pragma SECTION_RESTORE
|
||||
|
||||
|
||||
// rationale for polling:
|
||||
|
@ -102,72 +102,38 @@ void win_free(void* p)
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// module init and shutdown mechanism
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
// module init and shutdown
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// init and shutdown mechanism: register a function to be called at
|
||||
// pre-libc init, pre-main init or shutdown.
|
||||
//
|
||||
// each module has the linker add a pointer to its init or shutdown
|
||||
// function to a table (at a user-defined position).
|
||||
// zero runtime overhead, and there's no need for a central dispatcher
|
||||
// that knows about all the modules.
|
||||
//
|
||||
// disadvantage: requires compiler support (MS VC-specific).
|
||||
//
|
||||
// alternatives:
|
||||
// - initialize via constructor. however, that would leave the problem of
|
||||
// shutdown order and timepoint, which is also taken care of here.
|
||||
// - register init/shutdown functions from a NLSO constructor:
|
||||
// clunky, and setting order is more difficult.
|
||||
// - on-demand initialization: complicated; don't know in what order
|
||||
// things happen. also, no way to determine how long init takes.
|
||||
//
|
||||
// the "segment name" determines when and in what order the functions are
|
||||
// called: "LIB$W{type}{group}", where {type} is C for pre-libc init,
|
||||
// I for pre-main init, or T for terminators (last of the atexit handlers).
|
||||
// {group} is [B, Y]; groups are called in alphabetical order, but
|
||||
// call order within the group itself is unspecified.
|
||||
//
|
||||
// define the segment via #pragma data_seg(name), register any functions
|
||||
// to be called via WIN_REGISTER_FUNC, and then restore the previous segment
|
||||
// with #pragma data_seg() .
|
||||
//
|
||||
// note: group must be [B, Y]. data declared in groups A or Z may
|
||||
// be placed beyond the table start/end by the linker, since the linker's
|
||||
// ordering WRT other source files' data is undefined within a segment.
|
||||
|
||||
typedef LibError (*_PIFV)(void);
|
||||
typedef LibError (*Pfn)(void);
|
||||
|
||||
// pointers to start and end of function tables.
|
||||
// note: COFF tosses out empty segments, so we have to put in one value
|
||||
// (zero, because call_func_tbl has to ignore NULL entries anyway).
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_LIBC(a))
|
||||
_PIFV pre_libc_begin[] = { 0 };
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_LIBC(z))
|
||||
_PIFV pre_libc_end[] = { 0 };
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_MAIN(a))
|
||||
_PIFV pre_main_begin[] = { 0 };
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_MAIN(z))
|
||||
_PIFV pre_main_end[] = { 0 };
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(a))
|
||||
_PIFV shutdown_begin[] = { 0 };
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(z))
|
||||
_PIFV shutdown_end[] = { 0 };
|
||||
#pragma data_seg()
|
||||
#pragma SECTION_PRE_LIBC(A)
|
||||
Pfn pre_libc_begin = 0;
|
||||
#pragma SECTION_PRE_LIBC(Z)
|
||||
Pfn pre_libc_end = 0;
|
||||
#pragma SECTION_PRE_MAIN(A)
|
||||
Pfn pre_main_begin = 0;
|
||||
#pragma SECTION_PRE_MAIN(Z)
|
||||
Pfn pre_main_end = 0;
|
||||
#pragma SECTION_POST_ATEXIT(A)
|
||||
Pfn shutdown_begin = 0;
|
||||
#pragma SECTION_POST_ATEXIT(Z)
|
||||
Pfn shutdown_end = 0;
|
||||
#pragma SECTION_RESTORE
|
||||
// note: /include is not necessary, since these are referenced below.
|
||||
|
||||
#pragma comment(linker, "/merge:.LIB=.data")
|
||||
|
||||
// call all non-NULL function pointers in [begin, end).
|
||||
// note: the range may be larger than expected due to section padding.
|
||||
// that (and the COFF empty section problem) is why we need to ignore zeroes.
|
||||
static void call_func_tbl(_PIFV* begin, _PIFV* end)
|
||||
static void call_func_tbl(Pfn* begin, Pfn* end)
|
||||
{
|
||||
for(_PIFV* p = begin; p < end; p++)
|
||||
for(Pfn* p = begin; p < end; p++)
|
||||
if(*p)
|
||||
(*p)();
|
||||
}
|
||||
@ -247,7 +213,7 @@ static HMODULE hUser32Dll;
|
||||
|
||||
static void at_exit(void)
|
||||
{
|
||||
call_func_tbl(shutdown_begin, shutdown_end);
|
||||
call_func_tbl(&shutdown_begin, &shutdown_end);
|
||||
|
||||
cs_shutdown();
|
||||
|
||||
@ -267,7 +233,7 @@ void win_pre_main_init()
|
||||
debug_heap_enable(DEBUG_HEAP_NORMAL);
|
||||
#endif
|
||||
|
||||
call_func_tbl(pre_main_begin, pre_main_end);
|
||||
call_func_tbl(&pre_main_begin, &pre_main_end);
|
||||
|
||||
atexit(at_exit);
|
||||
|
||||
@ -321,7 +287,7 @@ static inline void pre_libc_init()
|
||||
// than documenting the problem and asking it not be delay-loaded.
|
||||
hUser32Dll = LoadLibrary("user32.dll");
|
||||
|
||||
call_func_tbl(pre_libc_begin, pre_libc_end);
|
||||
call_func_tbl(&pre_libc_begin, &pre_libc_end);
|
||||
}
|
||||
|
||||
|
||||
|
@ -29,9 +29,10 @@
|
||||
|
||||
#include "lib/lib.h" // BIT
|
||||
|
||||
#pragma region WindowsHeaderAndFixes
|
||||
|
||||
// Win32 socket decls aren't portable (e.g. problems with socklen_t)
|
||||
// => skip winsock.h; wposix wsock.h should be used instead
|
||||
// Win32 socket declarations aren't portable (e.g. problems with socklen_t)
|
||||
// => skip winsock.h; posix_sock.h should be used instead.
|
||||
#define _WINSOCKAPI_
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@ -46,7 +47,6 @@
|
||||
#define _WIN32_WINNT 0x0501
|
||||
|
||||
|
||||
|
||||
#define NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_
|
||||
//#define NOVIRTUALKEYCODES // VK_*
|
||||
//#define NOWINMESSAGES // WM_*, EM_*, LB_*, CB_*
|
||||
@ -338,52 +338,10 @@ enum DataKind
|
||||
DataIsConstant
|
||||
};
|
||||
|
||||
#pragma endregion
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef _CRTIMP
|
||||
# ifdef _DLL
|
||||
# define _CRTIMP __declspec(dllimport)
|
||||
# else
|
||||
# define _CRTIMP
|
||||
# endif
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
extern _CRTIMP intptr_t _get_osfhandle(int);
|
||||
extern _CRTIMP int _open_osfhandle(intptr_t, int);
|
||||
extern _CRTIMP int _open(const char* fn, int mode, ...);
|
||||
extern _CRTIMP int _read (int fd, void* buf, size_t nbytes);
|
||||
extern _CRTIMP int _write(int fd, void* buf, size_t nbytes);
|
||||
extern _CRTIMP int _close(int);
|
||||
|
||||
extern _CRTIMP char* _getcwd(char*, size_t);
|
||||
|
||||
#ifndef NO_WINSOCK
|
||||
extern __declspec(dllimport) int __stdcall WSAStartup(unsigned short, void*);
|
||||
extern __declspec(dllimport) int __stdcall WSACleanup(void);
|
||||
extern __declspec(dllimport) int __stdcall WSAAsyncSelect(int s, HANDLE hWnd, unsigned int wMsg, long lEvent);
|
||||
extern __declspec(dllimport) int __stdcall WSAGetLastError(void);
|
||||
#endif // #ifndef NO_WINSOCK
|
||||
|
||||
#ifdef USE_WINMAIN
|
||||
extern int WinMainCRTStartup(void);
|
||||
#else
|
||||
extern int mainCRTStartup(void);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define FD_READ BIT(0)
|
||||
#define FD_WRITE BIT(1)
|
||||
#define FD_ACCEPT BIT(3)
|
||||
#define FD_CONNECT BIT(4)
|
||||
#define FD_CLOSE BIT(5)
|
||||
|
||||
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// locking
|
||||
//
|
||||
|
||||
// critical sections used by win-specific code
|
||||
enum
|
||||
@ -397,7 +355,6 @@ enum
|
||||
NUM_CS
|
||||
};
|
||||
|
||||
|
||||
extern void win_lock(uint idx);
|
||||
extern void win_unlock(uint idx);
|
||||
|
||||
@ -405,48 +362,103 @@ extern void win_unlock(uint idx);
|
||||
extern int win_is_locked(uint idx);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// module init and shutdown
|
||||
|
||||
// register functions to be called before libc init, before main,
|
||||
// or after atexit.
|
||||
//
|
||||
// overview:
|
||||
// participating modules store function pointer(s) to their init and/or
|
||||
// shutdown function in a specific COFF section. the sections are
|
||||
// grouped according to the desired notification and the order in which
|
||||
// functions are to be called (useful if one module depends on another).
|
||||
// they are then gathered by the linker and arranged in alphabetical order.
|
||||
// placeholder variables in the sections indicate where the series of
|
||||
// functions begins and ends for a given notification time.
|
||||
// at runtime, all of the function pointers between the markers are invoked.
|
||||
//
|
||||
// details:
|
||||
// the section names are of the format ".LIB${type}{group}".
|
||||
// {type} is C for pre-libc init, I for pre-main init, or
|
||||
// T for terminators (last of the atexit handlers).
|
||||
// {group} is [B, Y]; all functions in a group are called before those of
|
||||
// the next (alphabetically) higher group, but order within the group is
|
||||
// undefined. this is because the linker sorts sections alphabetically,
|
||||
// but doesn't specify the order in which object files are processed.
|
||||
// another consequence is that groups A and Z must not be used!
|
||||
// (data placed there might end up outside the start/end markers)
|
||||
//
|
||||
// example:
|
||||
// #pragma SECTION_PRE_LIBC(G))
|
||||
// WIN_REGISTER_FUNC(wtime_init);
|
||||
// #pragma FORCE_INCLUDE(wtime_init)
|
||||
// #pragma SECTION_POST_ATEXIT(D))
|
||||
// WIN_REGISTER_FUNC(wtime_shutdown);
|
||||
// #pragma FORCE_INCLUDE(wtime_shutdown)
|
||||
// #pragma SECTION_RESTORE
|
||||
//
|
||||
// rationale:
|
||||
// several methods of module init are possible: (see Large Scale C++ Design)
|
||||
// - on-demand initialization: each exported function would have to check
|
||||
// if init already happened. that would be brittle and hard to verify.
|
||||
// - singleton: variant of the above, but not applicable to a
|
||||
// procedural interface (and quite ugly to boot).
|
||||
// - registration: NLSO constructors call a central notification function.
|
||||
// module dependencies would be quite difficult to express - this would
|
||||
// require a graph or separate lists for each priority (clunky).
|
||||
// worse, a fatal flaw is that other C++ constructors may depend on the
|
||||
// modules we are initializing and already have run. there is no way
|
||||
// to influence ctor call order between separate source files, so
|
||||
// this is out of the question.
|
||||
// - linker-based registration: same as above, but the linker takes care
|
||||
// of assembling various functions into one sorted table. the list of
|
||||
// init functions is available before C++ ctors have run. incidentally,
|
||||
// zero runtime overhead is incurred. unfortunately, this approach is
|
||||
// MSVC-specific. however, the MS CRT uses a similar method for its
|
||||
// init, so this is expected to remain supported.
|
||||
|
||||
// macros to simplify usage.
|
||||
// notes:
|
||||
// - #pragma cannot be packaged in macros due to expansion rules.
|
||||
// - __declspec(allocate) would be tempting, since that could be
|
||||
// wrapped in WIN_REGISTER_FUNC. unfortunately it inexplicably cannot
|
||||
// cope with split string literals (e.g. "ab" "c"). that disqualifies
|
||||
// it, since we want to hide the section name behind a macro, which
|
||||
// would require the abovementioned merging.
|
||||
#define SECTION_PRE_LIBC(group) data_seg(".LIB$C" #group)
|
||||
#define SECTION_PRE_MAIN(group) data_seg(".LIB$I" #group)
|
||||
#define SECTION_POST_ATEXIT(group) data_seg(".LIB$T" #group)
|
||||
#define SECTION_RESTORE data_seg()
|
||||
// use to make sure the link-stage optimizer doesn't discard the
|
||||
// function pointers (happens on VC8)
|
||||
#define FORCE_INCLUDE(id) comment(linker, "/include:_p"#id)
|
||||
|
||||
#define WIN_REGISTER_FUNC(func)\
|
||||
static LibError func(void);\
|
||||
extern "C" LibError (*p##func)(void) = func
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// misc
|
||||
|
||||
extern void* win_alloc(size_t size);
|
||||
extern void win_free(void* p);
|
||||
|
||||
|
||||
// thread safe, useable in constructors
|
||||
#define WIN_ONCE(code) \
|
||||
{ \
|
||||
win_lock(ONCE_CS); \
|
||||
static bool ONCE_init_; /* avoid name conflict */ \
|
||||
if(!ONCE_init_) \
|
||||
{ \
|
||||
ONCE_init_ = true; \
|
||||
code; \
|
||||
} \
|
||||
win_unlock(ONCE_CS); \
|
||||
// thread safe, usable in constructors
|
||||
#define WIN_ONCE(code)\
|
||||
{\
|
||||
win_lock(ONCE_CS);\
|
||||
static bool ONCE_init_; /* avoid name conflict */\
|
||||
if(!ONCE_init_)\
|
||||
{\
|
||||
ONCE_init_ = true;\
|
||||
code;\
|
||||
}\
|
||||
win_unlock(ONCE_CS);\
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// init and shutdown mechanism: register a function to be called at
|
||||
// pre-main init or shutdown.
|
||||
//
|
||||
// the "segment name" determines when and in what order the functions are
|
||||
// called: "LIB$W{type}{group}", where {type} is C for pre-libc init,
|
||||
// I for pre-main init, or T for terminators (last of the atexit handlers).
|
||||
// {group} is [B, Y]; groups are called in alphabetical order, but
|
||||
// call order within the group itself is unspecified.
|
||||
//
|
||||
// define the segment via #pragma data_seg(name), register any functions
|
||||
// to be called via WIN_REGISTER_FUNC, and then restore the previous segment
|
||||
// with #pragma data_seg() .
|
||||
|
||||
#define WIN_REGISTER_FUNC(func) static LibError func(void); static LibError (*p##func)(void) = func
|
||||
|
||||
#define WIN_CALLBACK_PRE_LIBC(group) ".LIB$WC" #group
|
||||
#define WIN_CALLBACK_PRE_MAIN(group) ".LIB$WI" #group
|
||||
#define WIN_CALLBACK_POST_ATEXIT(group) ".LIB$WT" #group
|
||||
|
||||
|
||||
|
||||
#define WIN_SAVE_LAST_ERROR DWORD last_err__ = GetLastError();
|
||||
#define WIN_RESTORE_LAST_ERROR STMT(if(last_err__ != 0 && GetLastError() == 0) SetLastError(last_err__););
|
||||
|
||||
@ -466,4 +478,21 @@ extern char win_exe_dir[MAX_PATH+1];
|
||||
// necessary; see rationale at function definition.
|
||||
extern LONG WINAPI wdbg_exception_filter(EXCEPTION_POINTERS* ep);
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef USE_WINMAIN
|
||||
extern "C" int WinMainCRTStartup(void);
|
||||
#else
|
||||
extern "C" int mainCRTStartup(void);
|
||||
#endif
|
||||
|
||||
|
||||
#define FD_READ BIT(0)
|
||||
#define FD_WRITE BIT(1)
|
||||
#define FD_ACCEPT BIT(3)
|
||||
#define FD_CONNECT BIT(4)
|
||||
#define FD_CLOSE BIT(5)
|
||||
|
||||
|
||||
#endif // #ifndef WIN_INTERNAL_H
|
||||
|
@ -29,13 +29,17 @@
|
||||
#include "wposix_internal.h"
|
||||
#include "wfilesystem.h" // mode_t
|
||||
#include "wtime.h" // timespec
|
||||
#include "waio_internal.h"
|
||||
|
||||
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_LIBC(c))
|
||||
#pragma SECTION_PRE_LIBC(J)
|
||||
WIN_REGISTER_FUNC(waio_init);
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(x))
|
||||
#pragma FORCE_INCLUDE(waio_init)
|
||||
#pragma SECTION_POST_ATEXIT(D)
|
||||
WIN_REGISTER_FUNC(waio_shutdown);
|
||||
#pragma data_seg()
|
||||
#pragma FORCE_INCLUDE(waio_shutdown)
|
||||
#pragma SECTION_RESTORE
|
||||
|
||||
|
||||
#define lock() win_lock(WAIO_CS)
|
||||
#define unlock() win_unlock(WAIO_CS)
|
||||
|
12
source/lib/sysdep/win/wposix/waio_internal.h
Normal file
12
source/lib/sysdep/win/wposix/waio_internal.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern _CRTIMP int _open(const char* fn, int mode, ...);
|
||||
extern _CRTIMP int _read (int fd, void* buf, size_t nbytes);
|
||||
extern _CRTIMP int _write(int fd, void* buf, size_t nbytes);
|
||||
extern _CRTIMP int _close(int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -45,9 +45,6 @@ long sysconf(int name)
|
||||
const HMODULE hKernel32Dll = LoadLibrary("kernel32.dll");
|
||||
*(void**)&pGlobalMemoryStatusEx = GetProcAddress(hKernel32Dll, "GlobalMemoryStatusEx");
|
||||
FreeLibrary(hKernel32Dll);
|
||||
// make sure the reference is released so BoundsChecker
|
||||
// doesn't complain. it won't actually be unloaded anyway -
|
||||
// there is at least one other reference.
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -23,6 +23,18 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern _CRTIMP intptr_t _get_osfhandle(int);
|
||||
extern _CRTIMP int _open_osfhandle(intptr_t, int);
|
||||
extern _CRTIMP char* _getcwd(char*, size_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// cast intptr_t to HANDLE; centralized for easier changing, e.g. avoiding
|
||||
// warnings. i = -1 converts to INVALID_HANDLE_VALUE (same value).
|
||||
|
@ -32,13 +32,6 @@
|
||||
#include "wtime.h" // timespec
|
||||
|
||||
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_LIBC(b))
|
||||
WIN_REGISTER_FUNC(wpthread_init);
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(y))
|
||||
WIN_REGISTER_FUNC(wpthread_shutdown);
|
||||
#pragma data_seg()
|
||||
|
||||
|
||||
static HANDLE HANDLE_from_pthread(pthread_t p)
|
||||
{
|
||||
return (HANDLE)((char*)0 + p);
|
||||
@ -463,35 +456,30 @@ int sem_msgwait_np(sem_t* sem)
|
||||
// work. win_lock allows recursive locking, so if creating 2 threads,
|
||||
// the parent thread may create both without being stopped and thus
|
||||
// stomp on the first thread's func_and_arg.
|
||||
// - stashing func and arg in TLS would work, but it is a
|
||||
// very limited resource.
|
||||
// - heap allocations are the obvious safe solution, but we're trying to
|
||||
// minimize those here.
|
||||
// - blocking pthread_create until the trampoline has latched func_and_arg
|
||||
// works. this seems a bit easier to understand than nonrecursive CS.
|
||||
// would work. this is a bit easier to understand than nonrecursive CS.
|
||||
// deadlock is impossible because thread_start allows the parent to
|
||||
// continue before doing anything dangerous. however, this requires
|
||||
// initializing a semaphore, which leads to init order problems.
|
||||
// - stashing func and arg in TLS would work, but it is a very limited
|
||||
// resource and __declspec(thread) is documented as possibly
|
||||
// interfering with delay loading.
|
||||
// - heap allocations are the obvious safe solution. we'd like to
|
||||
// minimize them, but it's the least painful way.
|
||||
|
||||
struct FuncAndArg
|
||||
{
|
||||
void* (*func)(void*);
|
||||
void* arg;
|
||||
|
||||
FuncAndArg(void* (*func_)(void*), void* arg_)
|
||||
: func(func_), arg(arg_) {}
|
||||
};
|
||||
|
||||
|
||||
static sem_t sem_thread_create;
|
||||
|
||||
// bridge calling conventions required by _beginthreadex and POSIX.
|
||||
static unsigned __stdcall thread_start(void* param)
|
||||
{
|
||||
const FuncAndArg* func_and_arg = (const FuncAndArg*)param;
|
||||
void* (*func)(void*) = func_and_arg->func;
|
||||
void* arg = func_and_arg->arg;
|
||||
// allow creator to run again.
|
||||
// potentially pulls rug out from under <param>.
|
||||
int err = sem_post(&sem_thread_create);
|
||||
debug_assert(err == 0);
|
||||
win_free(param);
|
||||
|
||||
void* ret = (void*)-1;
|
||||
__try
|
||||
@ -510,23 +498,30 @@ static unsigned __stdcall thread_start(void* param)
|
||||
|
||||
int pthread_create(pthread_t* thread_id, const void* UNUSED(attr), void* (*func)(void*), void* arg)
|
||||
{
|
||||
const FuncAndArg func_and_arg(func, arg);
|
||||
// notes:
|
||||
// - use win_alloc instead of the normal heap because we /might/
|
||||
// potentially be called before _cinit.
|
||||
// - placement new is more trouble than it's worth
|
||||
// (see REDEFINED_NEW), so we don't bother with a ctor.
|
||||
FuncAndArg* func_and_arg = (FuncAndArg*)win_alloc(sizeof(FuncAndArg));
|
||||
if(!func_and_arg)
|
||||
{
|
||||
WARN_ERR(ERR::NO_MEM);
|
||||
return -1;
|
||||
}
|
||||
func_and_arg->func = func;
|
||||
func_and_arg->arg = arg;
|
||||
|
||||
// _beginthreadex has more overhead and no value added vs.
|
||||
// CreateThread, but it avoids small memory leaks in
|
||||
// ExitThread when using the statically-linked CRT (-> MSDN).
|
||||
const uintptr_t id = _beginthreadex(0, 0, thread_start, (void*)&func_and_arg, 0, 0);
|
||||
const uintptr_t id = _beginthreadex(0, 0, thread_start, func_and_arg, 0, 0);
|
||||
if(!id)
|
||||
{
|
||||
WARN_ERR(ERR::FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// block until thread_start has latched func_and_arg.
|
||||
// (forces thread-switch)
|
||||
int err = sem_wait(&sem_thread_create);
|
||||
debug_assert(err == 0);
|
||||
|
||||
// SUSv3 doesn't specify whether this is optional - go the safe route.
|
||||
if(thread_id)
|
||||
*thread_id = (pthread_t)id;
|
||||
@ -565,20 +560,3 @@ int pthread_join(pthread_t thread, void** value_ptr)
|
||||
CloseHandle(hThread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static LibError wpthread_init()
|
||||
{
|
||||
int err = sem_init(&sem_thread_create, 0, 0);
|
||||
debug_assert(err == 0);
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
static LibError wpthread_shutdown()
|
||||
{
|
||||
int err = sem_destroy(&sem_thread_create);
|
||||
debug_assert(err == 0);
|
||||
return INFO::OK;
|
||||
}
|
||||
|
@ -25,18 +25,20 @@
|
||||
|
||||
#include "../delay_load.h"
|
||||
#include "wposix_internal.h"
|
||||
|
||||
#include "wsock_internal.h"
|
||||
|
||||
#if MSC_VERSION
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#endif
|
||||
|
||||
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_MAIN(k))
|
||||
#pragma SECTION_PRE_MAIN(K)
|
||||
WIN_REGISTER_FUNC(wsock_init);
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(b))
|
||||
#pragma FORCE_INCLUDE(wsock_init)
|
||||
#pragma SECTION_POST_ATEXIT(D)
|
||||
WIN_REGISTER_FUNC(wsock_shutdown);
|
||||
#pragma data_seg()
|
||||
#pragma FORCE_INCLUDE(wsock_shutdown)
|
||||
#pragma SECTION_RESTORE
|
||||
|
||||
|
||||
// IPv6 globals
|
||||
|
12
source/lib/sysdep/win/wposix/wsock_internal.h
Normal file
12
source/lib/sysdep/win/wposix/wsock_internal.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern __declspec(dllimport) int __stdcall WSAStartup(unsigned short, void*);
|
||||
extern __declspec(dllimport) int __stdcall WSACleanup(void);
|
||||
extern __declspec(dllimport) int __stdcall WSAAsyncSelect(int s, HANDLE hWnd, unsigned int wMsg, long lEvent);
|
||||
extern __declspec(dllimport) int __stdcall WSAGetLastError(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -42,12 +42,13 @@
|
||||
static const int CALIBRATION_FREQ = 1;
|
||||
|
||||
|
||||
// automatic module init (before main) and shutdown (before termination)
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_LIBC(b))
|
||||
#pragma SECTION_PRE_LIBC(G)
|
||||
WIN_REGISTER_FUNC(wtime_init);
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(b))
|
||||
#pragma FORCE_INCLUDE(wtime_init)
|
||||
#pragma SECTION_POST_ATEXIT(D)
|
||||
WIN_REGISTER_FUNC(wtime_shutdown);
|
||||
#pragma data_seg()
|
||||
#pragma FORCE_INCLUDE(wtime_shutdown)
|
||||
#pragma SECTION_RESTORE
|
||||
|
||||
|
||||
namespace ERR
|
||||
|
@ -54,11 +54,14 @@
|
||||
#endif
|
||||
|
||||
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_MAIN(b))
|
||||
|
||||
#pragma SECTION_PRE_MAIN(K)
|
||||
WIN_REGISTER_FUNC(wsdl_init);
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(d))
|
||||
#pragma FORCE_INCLUDE(wsdl_init)
|
||||
#pragma SECTION_POST_ATEXIT(D)
|
||||
WIN_REGISTER_FUNC(wsdl_shutdown);
|
||||
#pragma data_seg()
|
||||
#pragma FORCE_INCLUDE(wsdl_shutdown)
|
||||
#pragma SECTION_RESTORE
|
||||
|
||||
|
||||
// in fullscreen mode, i.e. not windowed.
|
||||
|
@ -386,8 +386,6 @@ int main(int argc, char* argv[])
|
||||
Init(args, 0);
|
||||
MainControllerInit();
|
||||
|
||||
debug_filter_add("LOADER"); // TODO: remove this?
|
||||
|
||||
while(!quit)
|
||||
Frame();
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#if OS_WIN
|
||||
#include "lib/sysdep/win/win_internal.h"
|
||||
#include "lib/sysdep/win/wposix/wsock_internal.h"
|
||||
#endif
|
||||
|
||||
#include "Network.h"
|
||||
|
Loading…
Reference in New Issue
Block a user