diff --git a/source/lib/res/file/compression.cpp b/source/lib/res/file/compression.cpp index 744acca86f..01d9897e9b 100644 --- a/source/lib/res/file/compression.cpp +++ b/source/lib/res/file/compression.cpp @@ -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 diff --git a/source/lib/res/file/file.cpp b/source/lib/res/file/file.cpp index 7ca6add84a..c4879cb1bc 100644 --- a/source/lib/res/file/file.cpp +++ b/source/lib/res/file/file.cpp @@ -581,7 +581,7 @@ LibError file_init() LibError file_shutdown() { - stats_dump(); + file_stats_dump(); path_shutdown(); file_io_shutdown(); return INFO::OK; diff --git a/source/lib/res/file/file_stats.cpp b/source/lib/res/file/file_stats.cpp index fe3ba626c1..94ac177354 100644 --- a/source/lib/res/file/file_stats.cpp +++ b/source/lib/res/file/file_stats.cpp @@ -286,7 +286,7 @@ template 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; diff --git a/source/lib/res/file/file_stats.h b/source/lib/res/file/file_stats.h index d1c5af3e1d..db83d8a061 100644 --- a/source/lib/res/file/file_stats.h +++ b/source/lib/res/file/file_stats.h @@ -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 diff --git a/source/lib/res/h_mgr.cpp b/source/lib/res/h_mgr.cpp index cb1924e64d..190db6e168 100644 --- a/source/lib/res/h_mgr.cpp +++ b/source/lib/res/h_mgr.cpp @@ -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++) diff --git a/source/lib/secure_crt.cpp b/source/lib/secure_crt.cpp new file mode 100644 index 0000000000..acb4f61413 --- /dev/null +++ b/source/lib/secure_crt.cpp @@ -0,0 +1,27 @@ +#include "precompiled.h" + +#include +#include + +#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; +} diff --git a/source/lib/secure_crt.h b/source/lib/secure_crt.h new file mode 100644 index 0000000000..1cf72cf657 --- /dev/null +++ b/source/lib/secure_crt.h @@ -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 diff --git a/source/lib/sysdep/win/delay_load.cpp b/source/lib/sysdep/win/delay_load.cpp index 2377d83fa5..fe14f7c003 100644 --- a/source/lib/sysdep/win/delay_load.cpp +++ b/source/lib/sysdep/win/delay_load.cpp @@ -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; + diff --git a/source/lib/sysdep/win/wdbg.cpp b/source/lib/sysdep/win/wdbg.cpp index 9840ea3117..bc444ada8d 100644 --- a/source/lib/sysdep/win/wdbg.cpp +++ b/source/lib/sysdep/win/wdbg.cpp @@ -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; } + diff --git a/source/lib/sysdep/win/wdbg_sym.cpp b/source/lib/sysdep/win/wdbg_sym.cpp index 905213bd42..2db9580543 100644 --- a/source/lib/sysdep/win/wdbg_sym.cpp +++ b/source/lib/sysdep/win/wdbg_sym.cpp @@ -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 diff --git a/source/lib/sysdep/win/wdir_watch.cpp b/source/lib/sysdep/win/wdir_watch.cpp index c390cdae4d..550b5538e9 100644 --- a/source/lib/sysdep/win/wdir_watch.cpp +++ b/source/lib/sysdep/win/wdir_watch.cpp @@ -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: diff --git a/source/lib/sysdep/win/win.cpp b/source/lib/sysdep/win/win.cpp index 75fd3584c0..73d97af82d 100644 --- a/source/lib/sysdep/win/win.cpp +++ b/source/lib/sysdep/win/win.cpp @@ -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); } diff --git a/source/lib/sysdep/win/win_internal.h b/source/lib/sysdep/win/win_internal.h index 77c165025b..c4ed5ff94b 100644 --- a/source/lib/sysdep/win/win_internal.h +++ b/source/lib/sysdep/win/win_internal.h @@ -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 diff --git a/source/lib/sysdep/win/wposix/waio.cpp b/source/lib/sysdep/win/wposix/waio.cpp index 72b8ed9ae1..ff7d8cd248 100644 --- a/source/lib/sysdep/win/wposix/waio.cpp +++ b/source/lib/sysdep/win/wposix/waio.cpp @@ -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) diff --git a/source/lib/sysdep/win/wposix/waio_internal.h b/source/lib/sysdep/win/wposix/waio_internal.h new file mode 100644 index 0000000000..ecfdc7b50f --- /dev/null +++ b/source/lib/sysdep/win/wposix/waio_internal.h @@ -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 diff --git a/source/lib/sysdep/win/wposix/wposix.cpp b/source/lib/sysdep/win/wposix/wposix.cpp index fb06e7d416..5a622f9fd3 100644 --- a/source/lib/sysdep/win/wposix/wposix.cpp +++ b/source/lib/sysdep/win/wposix/wposix.cpp @@ -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. } ); diff --git a/source/lib/sysdep/win/wposix/wposix_internal.h b/source/lib/sysdep/win/wposix/wposix_internal.h index 997ff8a5bc..36a382914e 100644 --- a/source/lib/sysdep/win/wposix/wposix_internal.h +++ b/source/lib/sysdep/win/wposix/wposix_internal.h @@ -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). diff --git a/source/lib/sysdep/win/wposix/wpthread.cpp b/source/lib/sysdep/win/wposix/wpthread.cpp index 48336ed331..68e74e3534 100644 --- a/source/lib/sysdep/win/wposix/wpthread.cpp +++ b/source/lib/sysdep/win/wposix/wpthread.cpp @@ -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 . - 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; -} diff --git a/source/lib/sysdep/win/wposix/wsock.cpp b/source/lib/sysdep/win/wposix/wsock.cpp index 27d5b5ff91..584a0dd8c9 100644 --- a/source/lib/sysdep/win/wposix/wsock.cpp +++ b/source/lib/sysdep/win/wposix/wsock.cpp @@ -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 diff --git a/source/lib/sysdep/win/wposix/wsock_internal.h b/source/lib/sysdep/win/wposix/wsock_internal.h new file mode 100644 index 0000000000..38a1d9337b --- /dev/null +++ b/source/lib/sysdep/win/wposix/wsock_internal.h @@ -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 diff --git a/source/lib/sysdep/win/wposix/wtime.cpp b/source/lib/sysdep/win/wposix/wtime.cpp index 61577205a2..c63714ef2e 100644 --- a/source/lib/sysdep/win/wposix/wtime.cpp +++ b/source/lib/sysdep/win/wposix/wtime.cpp @@ -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 diff --git a/source/lib/sysdep/win/wsdl.cpp b/source/lib/sysdep/win/wsdl.cpp index bc80a659b2..254f4e23ce 100644 --- a/source/lib/sysdep/win/wsdl.cpp +++ b/source/lib/sysdep/win/wsdl.cpp @@ -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. diff --git a/source/main.cpp b/source/main.cpp index b04b619abe..5f53e60737 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -386,8 +386,6 @@ int main(int argc, char* argv[]) Init(args, 0); MainControllerInit(); - debug_filter_add("LOADER"); // TODO: remove this? - while(!quit) Frame(); diff --git a/source/network/SocketBase.cpp b/source/network/SocketBase.cpp index d69cd27912..f775469487 100644 --- a/source/network/SocketBase.cpp +++ b/source/network/SocketBase.cpp @@ -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"