1
0
forked from 0ad/0ad

# 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:
janwas 2007-01-07 16:50:36 +00:00
parent ecb83f12f4
commit 95f8aa126f
24 changed files with 300 additions and 225 deletions

View File

@ -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

View File

@ -581,7 +581,7 @@ LibError file_init()
LibError file_shutdown()
{
stats_dump();
file_stats_dump();
path_shutdown();
file_io_shutdown();
return INFO::OK;

View File

@ -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;

View File

@ -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

View File

@ -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
View 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
View 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

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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:

View File

@ -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);
}

View File

@ -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,11 +362,91 @@ 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
// thread safe, usable in constructors
#define WIN_ONCE(code)\
{\
win_lock(ONCE_CS);\
@ -422,31 +459,6 @@ extern void win_free(void* p);
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

View File

@ -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)

View 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

View File

@ -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.
}
);

View File

@ -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).

View File

@ -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;
}

View File

@ -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

View 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

View File

@ -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

View File

@ -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.

View File

@ -386,8 +386,6 @@ int main(int argc, char* argv[])
Init(args, 0);
MainControllerInit();
debug_filter_add("LOADER"); // TODO: remove this?
while(!quit)
Frame();

View File

@ -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"