diff --git a/source/lib/bits.h b/source/lib/bits.h index 37a3b514ab..e396c83272 100644 --- a/source/lib/bits.h +++ b/source/lib/bits.h @@ -206,4 +206,21 @@ bool IsAligned(T t, uintptr_t multiple) return ((uintptr_t)t % multiple) == 0; } + +template +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 diff --git a/source/lib/sysdep/os/win/wposix/wpthread.cpp b/source/lib/sysdep/os/win/wposix/wpthread.cpp index bc7af0618b..f863c325da 100644 --- a/source/lib/sysdep/os/win/wposix/wpthread.cpp +++ b/source/lib/sysdep/os/win/wposix/wpthread.cpp @@ -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); diff --git a/source/lib/sysdep/os/win/wseh.cpp b/source/lib/sysdep/os/win/wseh.cpp index 73f8c3f02d..2f6bdc399c 100644 --- a/source/lib/sysdep/os/win/wseh.cpp +++ b/source/lib/sysdep/os/win/wseh.cpp @@ -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 diff --git a/source/lib/sysdep/os/win/wsysdep.cpp b/source/lib/sysdep/os/win/wsysdep.cpp index a3a7f0376f..7a4393c676 100644 --- a/source/lib/sysdep/os/win/wsysdep.cpp +++ b/source/lib/sysdep/os/win/wsysdep.cpp @@ -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 diff --git a/source/lib/sysdep/os/win/wutil.cpp b/source/lib/sysdep/os/win/wutil.cpp index 41e4b3b1bb..ec2ecf0e2e 100644 --- a/source/lib/sysdep/os/win/wutil.cpp +++ b/source/lib/sysdep/os/win/wutil.cpp @@ -30,7 +30,8 @@ #include #include // __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 diff --git a/source/lib/sysdep/os/win/wutil.h b/source/lib/sysdep/os/win/wutil.h index 35094e547d..ba48502283 100644 --- a/source/lib/sysdep/os/win/wutil.h +++ b/source/lib/sysdep/os/win/wutil.h @@ -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 @@ -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(); /**