1
0
forked from 0ad/0ad

fixes+improvements from work (overhaul wutil, add convenience macros for DLL imports)

This was SVN commit r7717.
This commit is contained in:
janwas 2010-07-08 10:18:42 +00:00
parent 0c149cf447
commit 8c1bd05ab9
6 changed files with 173 additions and 102 deletions

View File

@ -206,4 +206,21 @@ bool IsAligned(T t, uintptr_t multiple)
return ((uintptr_t)t % multiple) == 0;
}
template<typename T>
T MaxPowerOfTwoDivisor(T value)
{
debug_assert(value != T(0));
for(size_t log2 = 0; log2 < sizeof(T)*CHAR_BIT; log2++)
{
if(IsBitSet(value, log2))
return T(1) << log2;
}
debug_assert(0); // unreachable (!= 0 => there is a set bit)
return 0;
}
#endif // #ifndef INCLUDED_BITS

View File

@ -247,7 +247,7 @@ again:
// initializer returns pthread_mutex_t directly and CRITICAL_SECTIONS
// shouldn't be copied.
//
// note: we use win_alloc instead of new because the (no longer extant)
// note: we use wutil_Allocate instead of new because the (no longer extant)
// memory manager used a pthread_mutex.
static CRITICAL_SECTION* CRITICAL_SECTION_from_pthread_mutex_t(pthread_mutex_t* m)
@ -262,7 +262,7 @@ static CRITICAL_SECTION* CRITICAL_SECTION_from_pthread_mutex_t(pthread_mutex_t*
pthread_mutex_t pthread_mutex_initializer()
{
CRITICAL_SECTION* cs = (CRITICAL_SECTION*)win_alloc(sizeof(CRITICAL_SECTION));
CRITICAL_SECTION* cs = (CRITICAL_SECTION*)wutil_Allocate(sizeof(CRITICAL_SECTION));
InitializeCriticalSection(cs);
return (pthread_mutex_t)cs;
}
@ -273,7 +273,7 @@ int pthread_mutex_destroy(pthread_mutex_t* m)
if(!cs)
return -1;
DeleteCriticalSection(cs);
win_free(cs);
wutil_Free(cs);
*m = 0; // cause double-frees to be noticed
return 0;
}
@ -546,7 +546,7 @@ int sem_msgwait_np(sem_t* sem)
// - a local variable in pthread_create isn't safe because the
// new thread might not start before pthread_create returns.
// - using one static FuncAndArg protected by critical section doesn't
// work. win_lock allows recursive locking, so if creating 2 threads,
// work. wutil_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.
// - blocking pthread_create until the trampoline has latched func_and_arg
@ -572,7 +572,7 @@ 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;
win_free(param);
wutil_Free(param);
void* ret = 0;
__try
@ -592,11 +592,11 @@ static unsigned __stdcall thread_start(void* param)
int pthread_create(pthread_t* thread_id, const void* UNUSED(attr), void* (*func)(void*), void* arg)
{
// notes:
// - use win_alloc instead of the normal heap because we /might/
// - use wutil_Allocate 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));
FuncAndArg* func_and_arg = (FuncAndArg*)wutil_Allocate(sizeof(FuncAndArg));
if(!func_and_arg)
{
WARN_ERR(ERR::NO_MEM);

View File

@ -257,7 +257,7 @@ long __stdcall wseh_ExceptionFilter(struct _EXCEPTION_POINTERS* ep)
// someone is already holding the dbghelp lock - this is bad.
// we'll report this problem first and then try to display the
// exception info regardless (maybe dbghelp won't blow up).
if(win_is_locked(WDBG_SYM_CS) == 1)
if(wutil_IsLocked(WDBG_SYM_CS) == 1)
DEBUG_DISPLAY_ERROR(L"Exception raised while critical section is held - may deadlock..");
// a dump file is essential for debugging, so write it before

View File

@ -260,7 +260,7 @@ ErrorReaction sys_display_error(const wchar_t* text, size_t flags)
MSG msg;
BOOL quit_pending = PeekMessage(&msg, 0, WM_QUIT, WM_QUIT, PM_REMOVE);
const HINSTANCE hInstance = wutil_LibModuleHandle;
const HINSTANCE hInstance = wutil_LibModuleHandle();
LPCWSTR lpTemplateName = MAKEINTRESOURCEW(IDD_DIALOG1);
const DialogParams params = { text, flags };
// get the enclosing app's window handle. we can't just pass 0 or

View File

@ -30,7 +30,8 @@
#include <stdio.h>
#include <stdlib.h> // __argc
#include "lib/path_util.h"
#include "lib/file/file.h"
#include "lib/file/vfs/vfs.h"
#include "lib/posix/posix.h"
#include "lib/sysdep/os/win/win.h"
#include "lib/sysdep/os/win/winit.h"
@ -45,19 +46,17 @@ WINIT_REGISTER_LATE_SHUTDOWN(wutil_Shutdown);
//-----------------------------------------------------------------------------
// safe allocator
//
// safe allocator that may be used independently of libc malloc
// may be used independently of libc malloc
// (in particular, before _cinit and while calling static dtors).
// used by wpthread critical section code.
//
void* win_alloc(size_t size)
void* wutil_Allocate(size_t size)
{
const DWORD flags = HEAP_ZERO_MEMORY;
return HeapAlloc(GetProcessHeap(), flags, size);
}
void win_free(void* p)
void wutil_Free(void* p)
{
const DWORD flags = 0;
HeapFree(GetProcessHeap(), flags, p);
@ -74,21 +73,21 @@ void win_free(void* p)
static CRITICAL_SECTION cs[NUM_CS];
static bool cs_valid;
void win_lock(WinLockId id)
void wutil_Lock(WinLockId id)
{
if(!cs_valid)
return;
EnterCriticalSection(&cs[id]);
}
void win_unlock(WinLockId id)
void wutil_Unlock(WinLockId id)
{
if(!cs_valid)
return;
LeaveCriticalSection(&cs[id]);
}
bool win_is_locked(WinLockId id)
bool wutil_IsLocked(WinLockId id)
{
if(!cs_valid)
return false;
@ -128,20 +127,40 @@ LibError LibError_from_GLE(bool warn_if_failed)
switch(GetLastError())
{
case ERROR_OUTOFMEMORY:
err = ERR::NO_MEM; break;
case ERROR_NOT_ENOUGH_MEMORY:
err = ERR::NO_MEM;
break;
case ERROR_INVALID_HANDLE:
case ERROR_INVALID_PARAMETER:
err = ERR::INVALID_PARAM; break;
case ERROR_BAD_ARGUMENTS:
err = ERR::INVALID_PARAM;
break;
case ERROR_INSUFFICIENT_BUFFER:
err = ERR::BUF_SIZE; break;
/*
err = ERR::BUF_SIZE;
break;
case ERROR_ACCESS_DENIED:
err = ERR::FILE_ACCESS; break;
err = ERR::FILE_ACCESS;
break;
case ERROR_NOT_SUPPORTED:
err = ERR::NOT_SUPPORTED;
break;
case ERROR_CALL_NOT_IMPLEMENTED:
err = ERR::NOT_IMPLEMENTED;
break;
case ERROR_PROC_NOT_FOUND:
err = ERR::NO_SYS;
break;
case ERROR_BUSY:
err = ERR::AGAIN;
break;
case ERROR_FILE_NOT_FOUND:
err = ERR::VFS_FILE_NOT_FOUND;
break;
case ERROR_PATH_NOT_FOUND:
err = ERR::TNODE_NOT_FOUND; break;
*/
err = ERR::VFS_DIR_NOT_FOUND;
break;
default:
break; // err already set above
}
if(warn_if_failed)
@ -150,10 +169,6 @@ LibError LibError_from_GLE(bool warn_if_failed)
}
// return the LibError equivalent of GetLastError(), or ERR::FAIL if
// there's no equal.
// you should SetLastError(0) before calling whatever will set ret
// to make sure we do not return any stale errors.
LibError LibError_from_win32(DWORD ret, bool warn_if_failed)
{
if(ret != FALSE)
@ -169,8 +184,8 @@ LibError LibError_from_win32(DWORD ret, bool warn_if_failed)
// the argv pointers.
static wchar_t* argvContents;
int wutil_argc = 0;
wchar_t** wutil_argv = 0;
int s_argc = 0;
wchar_t** s_argv = 0;
static void ReadCommandLine()
{
@ -198,36 +213,48 @@ static void ReadCommandLine()
if(!ignoreSpace)
{
argvContents[i] = '\0';
wutil_argc++;
s_argc++;
}
break;
}
}
wutil_argc++;
s_argc++;
// have argv entries point into the tokenized string
wutil_argv = (wchar_t**)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, wutil_argc*sizeof(wchar_t*));
s_argv = (wchar_t**)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, s_argc*sizeof(wchar_t*));
wchar_t* nextArg = argvContents;
for(int i = 0; i < wutil_argc; i++)
for(int i = 0; i < s_argc; i++)
{
wutil_argv[i] = nextArg;
s_argv[i] = nextArg;
nextArg += wcslen(nextArg)+1;
}
}
int wutil_argc()
{
return s_argc;
}
wchar_t** wutil_argv()
{
debug_assert(s_argv);
return s_argv;
}
static void FreeCommandLine()
{
HeapFree(GetProcessHeap(), 0, wutil_argv);
HeapFree(GetProcessHeap(), 0, s_argv);
HeapFree(GetProcessHeap(), 0, argvContents);
}
bool wutil_HasCommandLineArgument(const wchar_t* arg)
{
for(int i = 0; i < wutil_argc; i++)
for(int i = 0; i < s_argc; i++)
{
if(!wcscmp(wutil_argv[i], arg))
if(!wcscmp(s_argv[i], arg))
return true;
}
@ -277,11 +304,11 @@ static void GetDirectories()
{
const UINT charsWritten = GetSystemDirectoryW(path, MAX_PATH);
debug_assert(charsWritten != 0);
systemPath = new(win_alloc(sizeof(fs::wpath))) fs::wpath(path);
systemPath = new(wutil_Allocate(sizeof(fs::wpath))) fs::wpath(path);
}
// executable's directory
executablePath = new(win_alloc(sizeof(fs::wpath))) fs::wpath(wutil_DetectExecutablePath());
executablePath = new(wutil_Allocate(sizeof(fs::wpath))) fs::wpath(wutil_DetectExecutablePath());
// application data
{
@ -289,7 +316,7 @@ static void GetDirectories()
HANDLE token = 0;
const HRESULT ret = SHGetFolderPathW(hwnd, CSIDL_APPDATA, token, 0, path);
debug_assert(SUCCEEDED(ret));
appdataPath = new(win_alloc(sizeof(fs::wpath))) fs::wpath(path);
appdataPath = new(wutil_Allocate(sizeof(fs::wpath))) fs::wpath(path);
}
}
@ -297,11 +324,11 @@ static void GetDirectories()
static void FreeDirectories()
{
systemPath->~basic_path();
win_free(systemPath);
wutil_Free(systemPath);
executablePath->~basic_path();
win_free(executablePath);
wutil_Free(executablePath);
appdataPath->~basic_path();
win_free(appdataPath);
wutil_Free(appdataPath);
}
@ -311,7 +338,7 @@ static void FreeDirectories()
// HACK: make sure a reference to user32 is held, even if someone
// decides to delay-load it. this fixes bug #66, which was the
// Win32 mouse cursor (set via user32!SetCursor) appearing as a
// black 32x32(?) rectangle. underlying cause was as follows:
// black 32x32(?) rectangle. the underlying cause was as follows:
// powrprof.dll was the first client of user32, causing it to be
// loaded. after we were finished with powrprof, we freed it, in turn
// causing user32 to unload. later code would then reload user32,
@ -341,14 +368,13 @@ static void FreeUser32Dll()
static void EnableLowFragmentationHeap()
{
#if WINVER >= 0x0501
const HMODULE hKernel32Dll = GetModuleHandleW(L"kernel32.dll");
typedef BOOL (WINAPI* PHeapSetInformation)(HANDLE, HEAP_INFORMATION_CLASS, void*, size_t);
PHeapSetInformation pHeapSetInformation = (PHeapSetInformation)GetProcAddress(hKernel32Dll, "HeapSetInformation");
if(!pHeapSetInformation)
return;
ULONG flags = 2; // enable LFH
pHeapSetInformation(GetProcessHeap(), HeapCompatibilityInformation, &flags, sizeof(flags));
WUTIL_FUNC(pHeapSetInformation, BOOL, (HANDLE, HEAP_INFORMATION_CLASS, void*, size_t));
WUTIL_IMPORT_KERNEL32(HeapSetInformation, pHeapSetInformation);
if(pHeapSetInformation)
{
ULONG flags = 2; // enable LFH
pHeapSetInformation(GetProcessHeap(), HeapCompatibilityInformation, &flags, sizeof(flags));
}
#endif // #if WINVER >= 0x0501
}
@ -395,6 +421,8 @@ const wchar_t* wutil_WindowsFamily()
return L"WinXP64";
case WUTIL_VERSION_VISTA:
return L"Vista";
case WUTIL_VERSION_7:
return L"Win7";
default:
return L"Windows";
}
@ -422,21 +450,17 @@ size_t wutil_WindowsVersion()
// that's bad, because the actual drivers are not in the subdirectory. to
// work around this, provide for temporarily disabling redirection.
typedef BOOL (WINAPI *PIsWow64Process)(HANDLE, PBOOL);
typedef BOOL (WINAPI *PWow64DisableWow64FsRedirection)(PVOID*);
typedef BOOL (WINAPI *PWow64RevertWow64FsRedirection)(PVOID);
static PIsWow64Process pIsWow64Process;
static PWow64DisableWow64FsRedirection pWow64DisableWow64FsRedirection;
static PWow64RevertWow64FsRedirection pWow64RevertWow64FsRedirection;
static WUTIL_FUNC(pIsWow64Process, BOOL, (HANDLE, PBOOL));
static WUTIL_FUNC(pWow64DisableWow64FsRedirection, BOOL, (PVOID*));
static WUTIL_FUNC(pWow64RevertWow64FsRedirection, BOOL, (PVOID));
static bool isWow64;
static void ImportWow64Functions()
{
const HMODULE hKernel32Dll = GetModuleHandleW(L"kernel32.dll");
pIsWow64Process = (PIsWow64Process)GetProcAddress(hKernel32Dll, "IsWow64Process");
pWow64DisableWow64FsRedirection = (PWow64DisableWow64FsRedirection)GetProcAddress(hKernel32Dll, "Wow64DisableWow64FsRedirection");
pWow64RevertWow64FsRedirection = (PWow64RevertWow64FsRedirection)GetProcAddress(hKernel32Dll, "Wow64RevertWow64FsRedirection");
WUTIL_IMPORT_KERNEL32(IsWow64Process, pIsWow64Process);
WUTIL_IMPORT_KERNEL32(Wow64DisableWow64FsRedirection, pWow64DisableWow64FsRedirection);
WUTIL_IMPORT_KERNEL32(Wow64RevertWow64FsRedirection, pWow64RevertWow64FsRedirection);
}
static void DetectWow64()
@ -468,7 +492,7 @@ WinScopedDisableWow64Redirection::WinScopedDisableWow64Redirection()
// more need to verify the pointers (their existence is implied).
if(!wutil_IsWow64())
return;
BOOL ok = pWow64DisableWow64FsRedirection(&m_wasRedirectionEnabled);
const BOOL ok = pWow64DisableWow64FsRedirection(&m_wasRedirectionEnabled);
WARN_IF_FALSE(ok);
}
@ -476,7 +500,7 @@ WinScopedDisableWow64Redirection::~WinScopedDisableWow64Redirection()
{
if(!wutil_IsWow64())
return;
BOOL ok = pWow64RevertWow64FsRedirection(m_wasRedirectionEnabled);
const BOOL ok = pWow64RevertWow64FsRedirection(m_wasRedirectionEnabled);
WARN_IF_FALSE(ok);
}
@ -486,22 +510,31 @@ WinScopedDisableWow64Redirection::~WinScopedDisableWow64Redirection()
#ifndef LIB_STATIC_LINK
HMODULE wutil_LibModuleHandle;
static HMODULE s_hModule;
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD UNUSED(reason), LPVOID UNUSED(reserved))
{
DisableThreadLibraryCalls(hInstance);
wutil_LibModuleHandle = hInstance;
s_hModule = hInstance;
return TRUE; // success (ignored unless reason == DLL_PROCESS_ATTACH)
}
HMODULE wutil_LibModuleHandle()
{
return s_hModule;
}
#else
HMODULE wutil_LibModuleHandle = GetModuleHandle(0);
HMODULE wutil_LibModuleHandle()
{
return GetModuleHandle(0);
}
#endif
//-----------------------------------------------------------------------------
// find main window

View File

@ -27,10 +27,6 @@
#ifndef INCLUDED_WUTIL
#define INCLUDED_WUTIL
#if !OS_WIN
#error "wutil.h: do not include if not compiling for Windows"
#endif
#include "lib/sysdep/os/win/win.h"
template<typename H>
@ -40,17 +36,42 @@ bool wutil_IsValidHandle(H h)
}
//
//-----------------------------------------------------------------------------
// dynamic linking
// define a function pointer (optionally prepend 'static')
#define WUTIL_FUNC(varName, ret, params)\
ret (WINAPI* varName) params
// rationale:
// - splitting up WUTIL_FUNC and WUTIL_IMPORT is a bit verbose in
// the common case of a local function pointer definition,
// but allows one-time initialization of static variables.
// - differentiating between procName and varName allows searching
// for the actual definition of the function pointer in the code.
// - a cast would require passing in ret/params.
// - writing a type-punned pointer breaks strict-aliasing rules.
#define WUTIL_IMPORT(hModule, procName, varName)\
STMT(\
const FARPROC f = GetProcAddress(hModule, #procName);\
memcpy(&varName, &f, sizeof(FARPROC));\
)
// note: Kernel32 is guaranteed to be loaded, so we don't
// need to LoadLibrary and FreeLibrary.
#define WUTIL_IMPORT_KERNEL32(procName, varName)\
WUTIL_IMPORT(GetModuleHandleW(L"kernel32.dll"), procName, varName)
//-----------------------------------------------------------------------------
// safe allocator
//
extern void* win_alloc(size_t size);
extern void win_free(void* p);
extern void* wutil_Allocate(size_t size);
extern void wutil_Free(void* p);
//
//-----------------------------------------------------------------------------
// locks
//
// critical sections used by win-specific code
enum WinLockId
@ -64,11 +85,11 @@ enum WinLockId
NUM_CS
};
extern void win_lock(WinLockId id);
extern void win_unlock(WinLockId id);
extern void wutil_Lock(WinLockId id);
extern void wutil_Unlock(WinLockId id);
// used in a desperate attempt to avoid deadlock in wseh.
extern bool win_is_locked(WinLockId id);
extern bool wutil_IsLocked(WinLockId id);
class WinScopedLock
{
@ -76,12 +97,12 @@ public:
WinScopedLock(WinLockId id)
: m_id(id)
{
win_lock(m_id);
wutil_Lock(m_id);
}
~WinScopedLock()
{
win_unlock(m_id);
wutil_Unlock(m_id);
}
private:
@ -89,9 +110,8 @@ private:
};
//
//-----------------------------------------------------------------------------
// errors
//
/**
* some WinAPI functions SetLastError(0) on success, which is bad because
@ -131,23 +151,23 @@ LibError LibError_from_GLE(bool warn_if_failed = true);
#define WARN_WIN32_ERR (void)LibError_from_GLE(true)
/// if ret is false, returns LibError_from_GLE.
/**
* @return INFO::OK if ret != FALSE, else LibError_from_GLE().
**/
extern LibError LibError_from_win32(DWORD ret, bool warn_if_failed = true);
//
//-----------------------------------------------------------------------------
// command line
//
extern int wutil_argc;
extern wchar_t** wutil_argv;
extern int wutil_argc();
extern wchar_t** wutil_argv();
extern bool wutil_HasCommandLineArgument(const wchar_t* arg);
//
//-----------------------------------------------------------------------------
// directories
//
// used by wutil_ExecutablePath, but provided in case other code
// needs to know this before our wutil_Init runs.
@ -158,9 +178,8 @@ extern const fs::wpath& wutil_ExecutablePath();
extern const fs::wpath& wutil_AppdataPath();
//
//-----------------------------------------------------------------------------
// version
//
extern const wchar_t* wutil_WindowsVersionString();
@ -169,6 +188,7 @@ const size_t WUTIL_VERSION_2K = 0x0500;
const size_t WUTIL_VERSION_XP = 0x0501;
const size_t WUTIL_VERSION_XP64 = 0x0502;
const size_t WUTIL_VERSION_VISTA = 0x0600;
const size_t WUTIL_VERSION_7 = 0x0601;
/**
* @return short textual representation of the appropriate WUTIL_VERSION
@ -178,9 +198,8 @@ extern const wchar_t* wutil_WindowsFamily();
extern size_t wutil_WindowsVersion();
//
//-----------------------------------------------------------------------------
// Wow64
//
extern bool wutil_IsWow64();
@ -195,12 +214,14 @@ private:
};
//-----------------------------------------------------------------------------
/**
* module handle of lib code (that of the main EXE if linked statically,
* otherwise the DLL).
* @return module handle of lib code (that of the main EXE if
* linked statically, otherwise the DLL).
* this is necessary for the error dialog.
**/
extern HMODULE wutil_LibModuleHandle;
extern HMODULE wutil_LibModuleHandle();
/**