part2: misc source/lib fixes/improvements

move all except user-specified config choices out of config.h and into
appropriate headers
CPU_IA32 -> ARCH_IA32
wsdl: disable use of ddraw (will soon be replaced by WMI)

use shared_ptr without namespace qualifier (it's in tr1)
debug_warn -> debug_assert(0)
LIB_API to allow building as DLL
smart pointers: reduce use of .get()
cache_adt: use map instead of hash_map (avoids needing a hashCompare
class). also remove spurious warning
code_annotation.h: better cassert implementation
move FPS measuring portion of timer.cpp into frequency_filter
move include of memory headers into mmgr.h (to avoid errors, we must
ensure they are included if mmgr is used)
posix_filesystem.h: move definition of mkdir to wfilesystem
stl: disable iterator checks in release mode
wmi: fix COM init bug, use smart pointers
wutil: add code to get DLL module handle (if compiled as such), add
WinScopedLock
timer: fix handling of raw ticks

This was SVN commit r5517.
This commit is contained in:
janwas 2007-12-20 20:09:19 +00:00
parent 03543147b7
commit 2e5d9452aa
68 changed files with 836 additions and 881 deletions

View File

@ -332,7 +332,7 @@ public:
head = (head + 1) % n;
}
else
debug_warn("underflow");
debug_assert(0); // underflow
}
class iterator

View File

@ -122,7 +122,7 @@ void single_free(void* storage, volatile uintptr_t* in_use_flag, void* p)
// ok, flag has been reset to 0
}
else
debug_warn("in_use_flag out of sync (double free?)");
debug_assert(0); // in_use_flag out of sync (double free?)
}
// was allocated from heap
else

View File

@ -36,7 +36,7 @@
* @param unaligned_size minimum size [bytes] to allocate.
* @return page-aligned and -padded memory or 0 on error / out of memory.
**/
extern void* page_aligned_alloc(size_t unaligned_size);
LIB_API void* page_aligned_alloc(size_t unaligned_size);
/**
* free a previously allocated page-aligned region.
@ -44,10 +44,10 @@ extern void* page_aligned_alloc(size_t unaligned_size);
* @param p exact value returned from page_aligned_alloc
* @param size exact value passed to page_aligned_alloc
**/
extern void page_aligned_free(void* p, size_t unaligned_size);
LIB_API void page_aligned_free(void* p, size_t unaligned_size);
// adapter that allows calling page_aligned_free as a boost::shared_ptr deleter.
// adapter that allows calling page_aligned_free as a shared_ptr deleter.
class PageAlignedDeleter
{
public:
@ -86,7 +86,7 @@ private:
* @return 0 if out of memory, otherwise matrix that should be cast to
* type** (sizeof(type) == el_size). must be freed via matrix_free.
**/
extern void** matrix_alloc(uint cols, uint rows, size_t el_size);
LIB_API void** matrix_alloc(uint cols, uint rows, size_t el_size);
/**
* free the given matrix.
@ -95,7 +95,7 @@ extern void** matrix_alloc(uint cols, uint rows, size_t el_size);
* callers will likely want to pass variables of a different type
* (e.g. int**); they must be cast to void**.
**/
extern void matrix_free(void** matrix);
LIB_API void matrix_free(void** matrix);
//-----------------------------------------------------------------------------
@ -120,7 +120,7 @@ extern void matrix_free(void** matrix);
* @return allocated memory (typically = <storage>, but falls back to
* malloc if that's in-use), or 0 (with warning) if out of memory.
**/
extern void* single_calloc(void* storage, volatile uintptr_t* in_use_flag, size_t size);
LIB_API void* single_calloc(void* storage, volatile uintptr_t* in_use_flag, size_t size);
/**
* Free a memory block that had been allocated by single_calloc.
@ -129,7 +129,7 @@ extern void* single_calloc(void* storage, volatile uintptr_t* in_use_flag, size_
* @param in_use_flag Exact value passed to single_calloc.
* @param Exact value returned by single_calloc.
**/
extern void single_free(void* storage, volatile uintptr_t* in_use_flag, void* p);
LIB_API void single_free(void* storage, volatile uintptr_t* in_use_flag, void* p);
#ifdef __cplusplus
@ -219,7 +219,7 @@ void InitObject()
*
* raises a warning if there's not enough room (indicates incorrect usage)
**/
extern void* static_calloc(StaticStorage* ss, size_t size);
LIB_API void* static_calloc(StaticStorage* ss, size_t size);
// (no need to free static_calloc-ed memory since it's in the BSS)
@ -322,7 +322,7 @@ public:
{
Allocs::iterator it = allocs.find(p);
if(it == allocs.end())
debug_warn("AllocatorChecker: freeing invalid pointer");
debug_assert(0); // freeing invalid pointer
else
{
// size must match what was passed to notify_alloc
@ -346,4 +346,13 @@ private:
Allocs allocs;
};
template<class T>
struct DummyDeleter
{
void operator()(T* UNUSED(t))
{
}
};
#endif // #ifndef INCLUDED_ALLOCATORS

View File

@ -59,7 +59,7 @@ struct Bucket
* will be returned by bucket_alloc (whose size parameter is then ignored).
* @return LibError.
**/
extern LibError bucket_create(Bucket* b, size_t el_size);
LIB_API LibError bucket_create(Bucket* b, size_t el_size);
/**
* free all memory that ensued from <b>.
@ -68,7 +68,7 @@ extern LibError bucket_create(Bucket* b, size_t el_size);
*
* @param Bucket*
**/
extern void bucket_destroy(Bucket* b);
LIB_API void bucket_destroy(Bucket* b);
/**
* Dole out memory from the Bucket.
@ -79,7 +79,7 @@ extern void bucket_destroy(Bucket* b);
* @return allocated memory, or 0 if the Bucket would have to be expanded and
* there isn't enough memory to do so.
**/
extern void* bucket_alloc(Bucket* b, size_t size);
LIB_API void* bucket_alloc(Bucket* b, size_t size);
/**
* make an entry available for reuse in the given Bucket.
@ -91,6 +91,6 @@ extern void* bucket_alloc(Bucket* b, size_t size);
* @param Bucket*
* @param el entry allocated via bucket_alloc.
**/
extern void bucket_free(Bucket* b, void* el);
LIB_API void bucket_free(Bucket* b, void* el);
#endif // #ifndef INCLUDED_BUCKET

View File

@ -45,7 +45,7 @@ struct DynArray
* (* rounded up to next page size multiple)
* @return LibError.
**/
extern LibError da_alloc(DynArray* da, size_t max_size);
LIB_API LibError da_alloc(DynArray* da, size_t max_size);
/**
* free all memory (address space + physical) that constitutes the
@ -56,7 +56,7 @@ extern LibError da_alloc(DynArray* da, size_t max_size);
* @param DynArray* da; zeroed afterwards.
* @return LibError
**/
extern LibError da_free(DynArray* da);
LIB_API LibError da_free(DynArray* da);
/**
* expand or shrink the array: changes the amount of currently committed
@ -67,7 +67,7 @@ extern LibError da_free(DynArray* da);
* pages are added/removed until this is met.
* @return LibError.
**/
extern LibError da_set_size(DynArray* da, size_t new_size);
LIB_API LibError da_set_size(DynArray* da, size_t new_size);
/**
* Make sure at least <size> bytes starting at da->pos are committed and
@ -77,7 +77,7 @@ extern LibError da_set_size(DynArray* da, size_t new_size);
* @param size Minimum amount to guarantee [bytes]
* @return LibError
**/
extern LibError da_reserve(DynArray* da, size_t size);
LIB_API LibError da_reserve(DynArray* da, size_t size);
/**
* change access rights of the array memory.
@ -89,7 +89,7 @@ extern LibError da_reserve(DynArray* da, size_t size);
* @param prot a combination of the PROT_* values used with mprotect.
* @return LibError.
**/
extern LibError da_set_prot(DynArray* da, int prot);
LIB_API LibError da_set_prot(DynArray* da, int prot);
/**
* "wrap" (i.e. store information about) the given buffer in a DynArray.
@ -104,7 +104,7 @@ extern LibError da_set_prot(DynArray* da, int prot);
* @param size maximum size (no alignment requirements)
* @return LibError.
**/
extern LibError da_wrap_fixed(DynArray* da, u8* p, size_t size);
LIB_API LibError da_wrap_fixed(DynArray* da, u8* p, size_t size);
/**
* "read" from array, i.e. copy into the given buffer.
@ -116,7 +116,7 @@ extern LibError da_wrap_fixed(DynArray* da, u8* p, size_t size);
* @param size [bytes] to copy
* @return LibError.
**/
extern LibError da_read(DynArray* da, void* data_dst, size_t size);
LIB_API LibError da_read(DynArray* da, void* data_dst, size_t size);
/**
* "write" to array, i.e. copy from the given buffer.
@ -128,6 +128,6 @@ extern LibError da_read(DynArray* da, void* data_dst, size_t size);
* @param size [bytes] to copy
* @return LibError.
**/
extern LibError da_append(DynArray* da, const void* data_src, size_t size);
LIB_API LibError da_append(DynArray* da, const void* data_src, size_t size);
#endif // #ifndef INCLUDED_DYNARRAY

View File

@ -730,20 +730,20 @@ HeaderlessAllocator::HeaderlessAllocator(size_t poolSize)
void HeaderlessAllocator::Reset()
{
return impl.get()->Reset();
return impl->Reset();
}
void* HeaderlessAllocator::Allocate(size_t size) throw()
{
return impl.get()->Allocate(size);
return impl->Allocate(size);
}
void HeaderlessAllocator::Deallocate(void* p, size_t size)
{
return impl.get()->Deallocate((u8*)p, size);
return impl->Deallocate((u8*)p, size);
}
void HeaderlessAllocator::Validate() const
{
return impl.get()->Validate();
return impl->Validate();
}

View File

@ -66,7 +66,7 @@ public:
private:
class Impl;
boost::shared_ptr<Impl> impl;
shared_ptr<Impl> impl;
};
#endif // #ifndef INCLUDED_HEADERLESS

View File

@ -38,7 +38,7 @@ extern LibError mem_Protect(u8* p, size_t size, int prot);
// rationale for the function-based interface: a class encapsulating the
// freelist pointer would force each header to include mem_util.h;
// instead, implementations need only declare a void* pointer.
void mem_freelist_AddToFront(void*& freelist, void* el);
void* mem_freelist_Detach(void*& freelist);
extern void mem_freelist_AddToFront(void*& freelist, void* el);
extern void* mem_freelist_Detach(void*& freelist);
#endif // #ifndef INCLUDED_MEM_UTIL

View File

@ -83,14 +83,14 @@ void pool_free(Pool* p, void* el)
// check if requested_size matches that when allocating)
if(p->el_size == 0)
{
debug_warn("cannot free variable-size items");
debug_assert(0); // cannot free variable-size items
return;
}
if(pool_contains(p, el))
mem_freelist_AddToFront(p->freelist, el);
else
debug_warn("invalid pointer (not in pool)");
debug_assert(0); // invalid pointer (not in pool)
}

View File

@ -57,7 +57,7 @@ const size_t POOL_VARIABLE_ALLOCS = ~0u;
* allow variable-sized allocations, but pool_free is then unusable.
* @return LibError
**/
extern LibError pool_create(Pool* p, size_t max_size, size_t el_size);
LIB_API LibError pool_create(Pool* p, size_t max_size, size_t el_size);
/**
* free all memory (address space + physical) that constitutes the
@ -71,7 +71,7 @@ extern LibError pool_create(Pool* p, size_t max_size, size_t el_size);
* @param Pool*
* @return LibError.
**/
extern LibError pool_destroy(Pool* p);
LIB_API LibError pool_destroy(Pool* p);
/**
* indicate whether a pointer was allocated from the given pool.
@ -81,7 +81,7 @@ extern LibError pool_destroy(Pool* p);
* @param Pool*
* @return bool.
**/
extern bool pool_contains(const Pool* p, void* el);
LIB_API bool pool_contains(const Pool* p, void* el);
/**
* Dole out memory from the pool.
@ -92,7 +92,7 @@ extern bool pool_contains(const Pool* p, void* el);
* @return allocated memory, or 0 if the Pool would have to be expanded and
* there isn't enough memory to do so.
**/
extern void* pool_alloc(Pool* p, size_t size);
LIB_API void* pool_alloc(Pool* p, size_t size);
/**
* Make a fixed-size element available for reuse in the given Pool.
@ -104,7 +104,7 @@ extern void* pool_alloc(Pool* p, size_t size);
* @param Pool*
* @param el Element returned by pool_alloc.
**/
extern void pool_free(Pool* p, void* el);
LIB_API void pool_free(Pool* p, void* el);
/**
* "free" all user allocations that ensued from the given Pool.
@ -114,7 +114,7 @@ extern void pool_free(Pool* p, void* el);
*
* @param Pool*
**/
extern void pool_free_all(Pool* p);
LIB_API void pool_free_all(Pool* p);
#ifdef __cplusplus

View File

@ -10,7 +10,7 @@
#include "precompiled.h"
#if CPU_IA32
#if ARCH_IA32
# include "lib/sysdep/ia32/ia32_asm.h" // ia32_asm_log2_of_pow2
#endif
@ -28,7 +28,7 @@ int log2_of_pow2(uint n)
{
int bit_index;
#if CPU_IA32
#if ARCH_IA32
bit_index = ia32_asm_log2_of_pow2(n);
#else
if(!is_pow2(n))

View File

@ -113,4 +113,11 @@ extern uint round_up_to_pow2(uint x);
extern uintptr_t round_up (uintptr_t n, uintptr_t multiple);
extern uintptr_t round_down(uintptr_t n, uintptr_t multiple);
template<typename T>
bool IsAligned(T t, uintptr_t multiple)
{
return ((uintptr_t)t % multiple) == 0;
}
#endif // #ifndef INCLUDED_BITS

View File

@ -11,7 +11,18 @@
#ifndef INCLUDED_BYTE_ORDER
#define INCLUDED_BYTE_ORDER
#include "config.h"
#include "lib/sysdep/cpu.h"
// detect byte order via predefined macros.
#ifndef BYTE_ORDER
# define LITTLE_ENDIAN 0x4321
# define BIG_ENDIAN 0x1234
# if ARCH_IA32 || ARCH_IA64 || ARCH_AMD64 || ARCH_ALPHA || ARCH_ARM || ARCH_MIPS || defined(__LITTLE_ENDIAN__)
# define BYTE_ORDER LITTLE_ENDIAN
# else
# define BYTE_ORDER BIG_ENDIAN
# endif
#endif
/**

View File

@ -233,8 +233,11 @@ public:
void remove(Key key)
{
MapIt it = map.find(key);
debug_assert(it != map.end());
remove_(it);
// note: don't complain if not in the cache: this happens after
// writing a file and invalidating its cache entry, which may
// or may not exist.
if(it != map.end())
remove_(it);
}
void on_access(Entry& entry)
@ -287,9 +290,10 @@ again:
}
protected:
// note: use hash_map instead of map for better locality
// (relevant when iterating over all items in remove_least_valuable)
class Map : public STL_HASH_MAP<Key, Entry>
// note: hash_map is probably better in terms of locality
// (relevant when iterating over all items in remove_least_valuable),
// but would require a hash comparator for VfsPath.
class Map : public std::map<Key, Entry>
{
public:
static Entry& entry_from_it(typename Map::iterator it) { return it->second; }
@ -557,7 +561,7 @@ public:
return;
}
}
debug_warn("entry not found in list");
debug_assert(0); // entry not found in list
}
void remove_least_valuable(std::list<Entry>& entry_list)

View File

@ -74,7 +74,7 @@ checking, but does not cause any compiler warnings.
# if !MSC_VERSION || CONFIG_PARANOIA
# define UNREACHABLE\
STMT(\
debug_warn("hit supposedly unreachable code");\
debug_assert(0); /* hit supposedly unreachable code */\
abort();\
)
// b) VC only: don't generate any code; squelch the warning and optimize.
@ -125,15 +125,17 @@ switch(x % 2)
* no runtime overhead; may be used anywhere, including file scope.
* especially useful for testing sizeof types.
*
* this version has a more descriptive error message, but may cause a
* struct redefinition warning if used from the same line in different files.
*
* note: alternative method in C++: specialize a struct only for true;
* using it will raise 'incomplete type' errors if instantiated with false.
*
* @param expression that is expected to evaluate to non-zero at compile-time.
**/
#define cassert(expr) struct UID__ { unsigned int CASSERT_FAILURE: (expr); }
#define cassert(expr) typedef detail::static_assert<(expr)>::type UID__;
namespace detail
{
template<bool> struct static_assert;
template<> struct static_assert<true>
{
typedef int type;
};
}
/**
* compile-time debug_assert. causes a compile error if the expression

View File

@ -2,7 +2,7 @@
* =========================================================================
* File : config.h
* Project : 0 A.D.
* Description : compile-time configuration and capability detection.
* Description : user-specified compile-time configuration.
* =========================================================================
*/
@ -11,18 +11,13 @@
#ifndef INCLUDED_CONFIG
#define INCLUDED_CONFIG
// the config/have macros are always defined; their values (1 or 0) are
// the config macros are always defined; their values (1 or 0) are
// tested with #if instead of #ifdef.
// this protects user code from typos such as #ifdef _MSC_VEER, which
// would silently remove code. instead, we will at least get "test of
// undefined macro" warnings here. not including this header also triggers
// such warnings, but won't happen often because we're included from PCH.
//-----------------------------------------------------------------------------
// user-specified configuration choices
//-----------------------------------------------------------------------------
//
// allow override via compiler settings by checking #ifndef.
// omit frame pointers - stack frames will not be generated, which
@ -36,7 +31,7 @@
# endif
#endif
// (only applicable if CPU_IA32) 64-bit values will be returned in EDX:EAX.
// (only applicable if ARCH_IA32) 64-bit values will be returned in EDX:EAX.
// this chiefly affects ia32_rdtsc. if not set, a safer but slower fallback
// will be used that doesn't assume anything about return convention.
#ifndef CONFIG_RETURN64_EDX_EAX
@ -46,11 +41,7 @@
// allow use of RDTSC for raw tick counts (otherwise, the slower but
// more reliable on MP systems wall-clock will be used).
#ifndef CONFIG_TIMER_ALLOW_RDTSC
# if CPU_IA32
# define CONFIG_TIMER_ALLOW_RDTSC 1
# else
# define CONFIG_TIMER_ALLOW_RDTSC 0
# endif
# define CONFIG_TIMER_ALLOW_RDTSC 1
#endif
// this enables/disables the actual checking done by OverrunProtector-s
@ -81,12 +72,11 @@
# define CONFIG_PARANOIA 0
#endif
// finale release; disables some safety checks.
// final release; disables some safety checks.
#ifndef CONFIG_FINAL
# define CONFIG_FINAL 0
#endif
// enable trace output for low-level code - various functions will
// debug_printf when they are entered/exited. note that the appropriate
// TRACEn tags must be debug_filter_add-ed for this to have any effect.
@ -100,341 +90,9 @@
# define CONFIG_DISABLE_EXCEPTIONS 0
#endif
//-----------------------------------------------------------------------------
// auto-detect OS and platform via predefined macros
//-----------------------------------------------------------------------------
// rationale:
// - these macros have consistent names and numerical values; using
// them saves other code from having to know the obscure predefined macros.
// - we'd like to use #if/#elif/#endif chains for e.g. OS_* to allow warning
// if none is selected, but there's no good way to #define all inapplicable
// settings to 0. doing so up front is hard to maintain and would require
// #undef before setting any one to 1. #ifndef afterwards for each setting
// is ugly and brittle as well. we therefore use #if/#else/#endif.
// compiler
// 0 if not present, or (major*100 + minor). note that more than
// one *_VERSION may be non-zero due to interoperability (e.g. ICC with MSC).
// .. VC
#ifdef _MSC_VER
# define MSC_VERSION _MSC_VER
#else
# define MSC_VERSION 0
#endif
// .. ICC (VC-compatible)
#if defined(__INTEL_COMPILER)
# define ICC_VERSION __INTEL_COMPILER
#else
# define ICC_VERSION 0
#endif
// .. LCC (VC-compatible)
#if defined(__LCC__)
# define LCC_VERSION __LCC__
#else
# define LCC_VERSION 0
#endif
// .. GCC
#ifdef __GNUC__
# define GCC_VERSION (__GNUC__*100 + __GNUC_MINOR__)
#else
# define GCC_VERSION 0
#endif
// STL
// (checked by STL implementation-specific code in debug_stl).
// .. Dinkumware
#if MSC_VERSION
# include <yvals.h> // defines _CPPLIB_VER
#endif
#if defined(_CPPLIB_VER)
# define STL_DINKUMWARE _CPPLIB_VER
#else
# define STL_DINKUMWARE 0
#endif
// .. GCC
#if defined(__GLIBCPP__)
# define STL_GCC __GLIBCPP__
#elif defined(__GLIBCXX__)
# define STL_GCC __GLIBCXX__
#else
# define STL_GCC 0
#endif
// .. ICC
#if defined(__INTEL_CXXLIB_ICC)
# define STL_ICC __INTEL_CXXLIB_ICC
#else
# define STL_ICC 0
#endif
// OS
// .. Windows
#if defined(_WIN64)
# define OS_WIN64 1
#else
# define OS_WIN64 0
#endif
#if defined(_WIN32)
# define OS_WIN 1
#else
# define OS_WIN 0
#endif
// .. Linux
#if defined(linux) || defined(__linux) || defined(__linux__)
# define OS_LINUX 1
#else
# define OS_LINUX 0
#endif
// .. Mac OS X
#if (defined(__APPLE__) && defined(__MACH__))
# define OS_MACOSX 1
#else
# define OS_MACOSX 0
#endif
// .. BSD
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
# define OS_BSD 1
#else
# define OS_BSD 0
#endif
// .. Solaris
#if defined(sun) || defined(__sun)
# define OS_SOLARIS 1
#else
# define OS_SOLARIS 0
#endif
// .. BeOS
#if defined(__BEOS__)
# define OS_BEOS 1
#else
# define OS_BEOS 0
#endif
// .. Mac OS 9 or below
#if defined(macintosh)
# define OS_MAC 1
#else
# define OS_MAC 0
#endif
// .. Amiga
#if defined(AMIGA)
# define OS_AMIGA 1
#else
# define OS_AMIGA 0
#endif
// .. Unix-based
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)
# define OS_UNIX 1
#else
# define OS_UNIX 0
#endif
// convenience: additionally set OS_UNIX for Unix-based OSes
// note: doing this in an separate section instead of adding the extra define
// to all affected OSes saves a few undefs or macro redefinition warnings.
#if OS_LINUX || OS_MACOSX || OS_BSD || OS_SOLARIS
# undef OS_UNIX
# define OS_UNIX 1
#endif
// convenience: additionally set OS_BSD for BSD-based OSes. see note above.
#if OS_MACOSX
# undef OS_BSD
# define OS_BSD 1
#endif
// CPU
// .. IA-32
#if defined(_M_IX86) || defined(i386) || defined(_X86_)
# define CPU_IA32 1
#else
# define CPU_IA32 0
#endif
// .. IA-64
#if defined(_M_IA64) || defined(__ia64__)
# define CPU_IA64 1
#else
# define CPU_IA64 0
#endif
// .. AMD64
#if defined(_M_AMD64) || defined(__amd64__) || defined(__amd64)
# define CPU_AMD64 1
#else
# define CPU_AMD64 0
#endif
// .. Alpha
#if defined(_M_ALPHA) || defined(__alpha__) || defined(__alpha)
# define CPU_ALPHA 1
#else
# define CPU_ALPHA 0
#endif
// .. ARM
#if defined(__arm__)
# define CPU_ARM 1
#else
# define CPU_ARM 0
#endif
// .. MIPS
#if defined(__MIPS__) || defined(__mips__) || defined(__mips)
# define CPU_MIPS 1
#else
# define CPU_MIPS 0
#endif
// byte order
// if already defined by someone else, assume they are also correct :P
#ifndef BYTE_ORDER
# define LITTLE_ENDIAN 0x4321
# define BIG_ENDIAN 0x1234
# if CPU_IA32 || CPU_IA64 || CPU_AMD64 || CPU_ALPHA || CPU_ARM || CPU_MIPS || defined(__LITTLE_ENDIAN__)
# define BYTE_ORDER LITTLE_ENDIAN
# else
# define BYTE_ORDER BIG_ENDIAN
# endif
#endif
//-----------------------------------------------------------------------------
// auto-detect platform features, given the above information
//-----------------------------------------------------------------------------
// check if compiling in pure C mode (not C++) with support for C99.
// (this is more convenient than testing __STDC_VERSION__ directly)
//
// note: C99 provides several useful but disjunct bits of functionality.
// unfortunately, most C++ compilers do not offer a complete implementation.
// however, many of these features are likely to be added to C++, and/or are
// already available as extensions. what we'll do is add a HAVE_ macro for
// each feature and test those instead. they are set if HAVE_C99, or also if
// the compiler happens to support something compatible.
//
// rationale: lying about __STDC_VERSION__ via Premake so as to enable support
// for some C99 functions doesn't work. Mac OS X headers would then use the
// restrict keyword, which is never supported by g++ (because that might
// end up breaking valid C++98 programs).
#define HAVE_C99 0
#ifdef __STDC_VERSION__
# if __STDC_VERSION__ >= 199901L
# undef HAVE_C99
# define HAVE_C99 1
# endif
#endif
// strdup, wcsdup
#if OS_MACOSX
# define HAVE_STRDUP 1
# define HAVE_WCSDUP 0
#else
# define HAVE_STRDUP 1
# define HAVE_WCSDUP 1
#endif
// emulation needed on VC8 because this function is "deprecated".
// not present on VC7, either.
#if MSC_VERSION
# define HAVE_MKDIR 0
#else
# define HAVE_MKDIR 1
#endif
// rint*, fminf, fpclassify (too few/diverse to make separate HAVE_ for each)
#if HAVE_C99 || GCC_VERSION
# define HAVE_C99_MATH 1
#else
# define HAVE_C99_MATH 0
#endif
// gettimeofday()
#if OS_UNIX
# define HAVE_GETTIMEOFDAY 1
#else
# define HAVE_GETTIMEOFDAY 0
#endif
// clock_gettime()
#define HAVE_CLOCK_GETTIME 0
#if OS_UNIX
# include <unistd.h>
# if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
# undef HAVE_CLOCK_GETTIME
# define HAVE_CLOCK_GETTIME 1
# endif
#endif
// X server
#if OS_LINUX
# define HAVE_X 1
#else
# define HAVE_X 0
#endif
// MSVC/ICC-style __asm{} blocks (Intel syntax)
#if MSC_VERSION
# define HAVE_MS_ASM 1
#else
# define HAVE_MS_ASM 0
#endif
// GNU-style __asm() blocks (AT&T syntax)
#if GCC_VERSION
# define HAVE_GNU_ASM 1
#else
# define HAVE_GNU_ASM 0
#endif
// precompiled headers (affects what precompiled.h pulls in; see there)
#if MSC_VERSION
# define HAVE_PCH 1
#elif defined(USING_PCH)
# define HAVE_PCH 1
#else
# define HAVE_PCH 0
#endif
// VC debug memory allocator / leak detector
// notes:
// - PCH is required because it makes sure system headers are included
// before redefining new (otherwise, tons of errors result);
// - disabled on ICC9 because the ICC 9.0.006 beta appears to generate
// incorrect code when we redefine new.
// TODO: remove when no longer necessary
#if MSC_VERSION && \
(!defined(NDEBUG) || defined(TESTING)) && \
HAVE_PCH && \
ICC_VERSION != 900
# define HAVE_VC_DEBUG_ALLOC 1
#else
# define HAVE_VC_DEBUG_ALLOC 0
#endif
// nonstandard STL containers
#define HAVE_STL_SLIST 0
#if STL_DINKUMWARE
# define HAVE_STL_HASH 1
#else
# define HAVE_STL_HASH 0
#endif
// safe CRT functions: strcpy_s, fopen_s, etc.
// these are always available to users: if not provided by the CRT, we
// implement them ourselves. this flag is only used to skip our impl.
#if MSC_VERSION >= 1400
# define HAVE_SECURE_CRT 1
#else
# define HAVE_SECURE_CRT 0
#endif
// should we use our float->int code? newer GCC versions with -ffast-math and
// VC8 can use SSE, so skip it there.
#if CPU_IA32 && MSC_VERSION && MSC_VERSION < 1400
# define USE_IA32_FLOAT_TO_INT 1
#else
# define USE_IA32_FLOAT_TO_INT 0
#ifndef CONFIG_ENABLE_PCH
# define CONFIG_ENABLE_PCH 1
#endif
#endif // #ifndef INCLUDED_CONFIG

View File

@ -70,7 +70,7 @@ void debug_wprintf_mem(const wchar_t* fmt, ...)
va_end(args);
if(len < 0)
{
debug_warn("vswprintf failed");
debug_assert(0); // vswprintf failed
return;
}
debug_log_pos += len+2;
@ -112,7 +112,7 @@ void debug_filter_add(const char* tag)
// too many already?
if(num_tags == MAX_TAGS)
{
debug_warn("increase MAX_TAGS");
debug_assert(0); // increase MAX_TAGS
return;
}
@ -204,14 +204,11 @@ void debug_wprintf(const wchar_t* fmt, ...)
const size_t MAX_BYTES = MAX_CHARS*2;
char mbs_buf[MAX_BYTES]; mbs_buf[MAX_BYTES-1] = '\0';
size_t bytes_written = wcstombs(mbs_buf, wcs_buf, MAX_BYTES);
// .. error
if(bytes_written == (size_t)-1)
debug_warn("invalid wcs character encountered");
// .. exact fit, make sure it's 0-terminated
debug_assert(bytes_written != (size_t)-1); // else: invalid wcs character encountered
debug_assert(bytes_written <= MAX_BYTES); // else: overflow (should be impossible)
// exact fit, ensure it's 0-terminated
if(bytes_written == MAX_BYTES)
mbs_buf[MAX_BYTES-1] = '\0';
// .. paranoia: overflow is impossible
debug_assert(bytes_written <= MAX_BYTES);
if(debug_filter_allows(mbs_buf))
debug_puts(mbs_buf);
@ -396,8 +393,7 @@ static void symbol_string_add_to_cache(const char* string, void* symbol)
{
// note: must be zeroed to set each Symbol to "invalid"
symbols = (Symbol*)calloc(MAX_SYMBOLS, sizeof(Symbol));
if(!symbols)
debug_warn("failed to allocate symbols");
debug_assert(symbols);
}
// hash table is completely full (guard against infinite loop below).
@ -680,7 +676,7 @@ void debug_skip_next_err(LibError err)
if(cpu_CAS(&expected_err_valid, 0, 1))
expected_err = err;
else
debug_warn("internal error: concurrent attempt to skip assert/error");
debug_assert(0); // internal error: concurrent attempt to skip assert/error
}
@ -691,8 +687,7 @@ static bool should_skip_this_error(LibError err)
// (use cpu_CAS to ensure only one error is skipped)
if(cpu_CAS(&expected_err_valid, 1, 0))
{
if(!was_expected_err)
debug_warn("anticipated error was not raised");
debug_assert(was_expected_err);
return was_expected_err;
}

View File

@ -65,7 +65,7 @@ even if debug information is present and assert dialogs are useless.
* check heap integrity (independently of mmgr).
* errors are reported by the CRT or via debug_display_error.
**/
extern void debug_heap_check(void);
LIB_API void debug_heap_check(void);
enum DebugHeapChecks
{
@ -90,7 +90,7 @@ enum DebugHeapChecks
* call at any time; from then on, the specified checks will be performed.
* if not called, the default is DEBUG_HEAP_NONE, i.e. do nothing.
**/
extern void debug_heap_enable(DebugHeapChecks what);
LIB_API void debug_heap_enable(DebugHeapChecks what);
//-----------------------------------------------------------------------------
@ -102,7 +102,7 @@ enum DebugLevel
DEBUG_LEVEL_NONE = 0,
DEBUG_LEVEL_BRIEF = 2,
DEBUG_LEVEL_DETAILED = 5,
DEBUG_LEVEL_FULL = 9,
DEBUG_LEVEL_FULL = 9
};
#define DEBUG_PRINTF_BRIEF if(debug_level >= DEBUG_LEVEL_BRIEF) debug_printf
#define DEBUG_PRINTF_DETAILED if(debug_level >= DEBUG_LEVEL_DETAILED) debug_printf
@ -114,10 +114,10 @@ enum DebugLevel
*
* @param format string and varargs; see printf.
**/
extern void debug_printf(const char* fmt, ...);
LIB_API void debug_printf(const char* fmt, ...);
/// note: this merely converts to a MBS and calls debug_printf.
extern void debug_wprintf(const wchar_t* fmt, ...);
LIB_API void debug_wprintf(const wchar_t* fmt, ...);
/**
@ -126,7 +126,7 @@ extern void debug_wprintf(const wchar_t* fmt, ...);
* is unavailable because that function is much more capable.
* implemented via sys_display_msgw; see documentation there.
**/
extern void debug_display_msgw(const wchar_t* caption, const wchar_t* msg);
LIB_API void debug_display_msgw(const wchar_t* caption, const wchar_t* msg);
/// flags to customize debug_display_error behavior
enum DebugDisplayErrorFlags
@ -219,7 +219,7 @@ enum ErrorReaction
* provides the storage. values: see DEBUG_SUPPRESS above.
* @return ErrorReaction (user's choice: continue running or stop?)
**/
extern ErrorReaction debug_display_error(const wchar_t* description,
LIB_API ErrorReaction debug_display_error(const wchar_t* description,
uint flags, uint skip, void* context,
const char* file, int line, const char* func,
u8* suppress);
@ -258,26 +258,26 @@ extern ErrorReaction debug_display_error(const wchar_t* description,
* in future, allow output with the given tag to proceed.
* no effect if already added.
**/
extern void debug_filter_add(const char* tag);
LIB_API void debug_filter_add(const char* tag);
/**
* in future, discard output with the given tag.
* no effect if not currently added.
**/
extern void debug_filter_remove(const char* tag);
LIB_API void debug_filter_remove(const char* tag);
/**
* clear all filter state; equivalent to debug_filter_remove for
* each tag that was debug_filter_add-ed.
**/
extern void debug_filter_clear();
LIB_API void debug_filter_clear();
/**
* indicate if the given text would be printed.
* useful for a series of debug_printfs - avoids needing to add a tag to
* each of their format strings.
**/
extern bool debug_filter_allows(const char* text);
LIB_API bool debug_filter_allows(const char* text);
/**
@ -286,7 +286,7 @@ extern bool debug_filter_allows(const char* text);
*
* @param format string and varags; see printf.
**/
extern void debug_wprintf_mem(const wchar_t* fmt, ...);
LIB_API void debug_wprintf_mem(const wchar_t* fmt, ...);
/**
* write an error description and all logs into crashlog.txt
@ -298,7 +298,7 @@ extern void debug_wprintf_mem(const wchar_t* fmt, ...);
* @return LibError; ERR::REENTERED if reentered via recursion or
* multithreading (not allowed since an infinite loop may result).
**/
extern LibError debug_write_crashlog(const wchar_t* text);
LIB_API LibError debug_write_crashlog(const wchar_t* text);
//-----------------------------------------------------------------------------
@ -343,7 +343,7 @@ STMT(\
* show a dialog to make sure unexpected states in the program are noticed.
* this is less error-prone than "debug_assert(0 && "text");" and avoids
* "conditional expression is constant" warnings. we'd really like to
* completely eliminate the problem; replacing 0 literals with extern
* completely eliminate the problem; replacing 0 literals with LIB_API
* volatile variables fools VC7 but isn't guaranteed to be free of overhead.
* we therefore just squelch the warning (unfortunately non-portable).
* this duplicates the code from debug_assert to avoid compiler warnings about
@ -393,7 +393,7 @@ STMT(\
* @param func name of the function containing it
* @return ErrorReaction (user's choice: continue running or stop?)
**/
extern ErrorReaction debug_assert_failed(const char* assert_expr,
LIB_API ErrorReaction debug_assert_failed(const char* assert_expr,
u8* suppress,
const char* file, int line, const char* func);
@ -407,7 +407,7 @@ extern ErrorReaction debug_assert_failed(const char* assert_expr,
* @param func name of the function containing it
* @return ErrorReaction (user's choice: continue running or stop?)
**/
extern ErrorReaction debug_warn_err(LibError err,
LIB_API ErrorReaction debug_warn_err(LibError err,
u8* suppress,
const char* file, int line, const char* func);
@ -428,14 +428,14 @@ extern ErrorReaction debug_warn_err(LibError err,
* note: this is thread-safe, but to prevent confusion, only one
* concurrent skip request is allowed.
*/
extern void debug_skip_next_err(LibError err);
LIB_API void debug_skip_next_err(LibError err);
/**
* same as debug_skip_next_err, but for asserts.
* note that this is implemented in terms of it, so only one assert or
* error skip request may be active at a time.
*/
extern void debug_skip_assert();
LIB_API void debug_skip_assert();
//-----------------------------------------------------------------------------
@ -482,13 +482,13 @@ enum DbgBreakType
* @return LibError; ERR::LIMIT if no more breakpoints are available
* (they are a limited resource - only 4 on IA-32).
**/
extern LibError debug_set_break(void* addr, DbgBreakType type);
LIB_API LibError debug_set_break(void* addr, DbgBreakType type);
/**
* remove all breakpoints that were set by debug_set_break.
* important, since these are a limited resource.
**/
extern LibError debug_remove_all_breaks();
LIB_API LibError debug_remove_all_breaks();
//-----------------------------------------------------------------------------
@ -545,7 +545,7 @@ const size_t DBG_FILE_LEN = 100;
* @return LibError; INFO::OK iff any information was successfully
* retrieved and stored.
**/
extern LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int* line);
LIB_API LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int* line);
/**
* write a complete stack trace (including values of local variables) into
@ -562,9 +562,9 @@ extern LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char
* @return LibError; ERR::REENTERED if reentered via recursion or
* multithreading (not allowed since static data is used).
**/
extern LibError debug_dump_stack(wchar_t* buf, size_t max_chars, uint skip, void* context);
LIB_API LibError debug_dump_stack(wchar_t* buf, size_t max_chars, uint skip, void* context);
extern const char* debug_get_symbol_string(void* symbol, const char* name, const char* file, int line);
LIB_API const char* debug_get_symbol_string(void* symbol, const char* name, const char* file, int line);
//-----------------------------------------------------------------------------
@ -576,7 +576,7 @@ extern const char* debug_get_symbol_string(void* symbol, const char* name, const
* this can be quite slow (~1 ms)! On Windows, it uses OutputDebugString
* (entails context switch), otherwise stdout+fflush (waits for IO).
**/
extern void debug_puts(const char* text);
LIB_API void debug_puts(const char* text);
/**
* return address of the Nth function on the call stack.
@ -590,7 +590,7 @@ extern void debug_puts(const char* text);
* for exceptions. otherwise, tracing starts from the current call stack.
* @return address of Nth function
**/
extern void* debug_get_nth_caller(uint skip, void* context);
LIB_API void* debug_get_nth_caller(uint skip, void* context);
/**
* check if a pointer appears to be totally invalid.
@ -601,13 +601,13 @@ extern void* debug_get_nth_caller(uint skip, void* context);
* @param p pointer
* @return 1 if totally bogus, otherwise 0.
**/
extern int debug_is_pointer_bogus(const void* p);
LIB_API int debug_is_pointer_bogus(const void* p);
/// does the given pointer appear to point to code?
extern bool debug_is_code_ptr(void* p);
LIB_API bool debug_is_code_ptr(void* p);
/// does the given pointer appear to point to the stack?
extern bool debug_is_stack_ptr(void* p);
LIB_API bool debug_is_stack_ptr(void* p);
/**
@ -621,7 +621,7 @@ extern bool debug_is_stack_ptr(void* p);
* the entire program; best to pass a string literal. allocating a copy
* would be quite a bit more work due to cleanup issues.
**/
extern void debug_set_thread_name(const char* name);
LIB_API void debug_set_thread_name(const char* name);
/**
* return current thread's name.
@ -629,7 +629,7 @@ extern void debug_set_thread_name(const char* name);
* @return thread name, or NULL if one hasn't been assigned yet
* via debug_set_thread_name.
**/
extern const char* debug_get_thread_name();
LIB_API const char* debug_get_thread_name();
/**
@ -654,7 +654,7 @@ struct ErrorMessageMem
*
* @param ErrorMessageMem*
**/
extern void debug_error_message_free(ErrorMessageMem* emm);
LIB_API void debug_error_message_free(ErrorMessageMem* emm);
/**
* build a string describing the given error.
@ -671,7 +671,7 @@ extern void debug_error_message_free(ErrorMessageMem* emm);
* fallback in case heap alloc fails. should be freed via
* debug_error_message_free when no longer needed.
**/
extern const wchar_t* debug_error_message_build(
LIB_API const wchar_t* debug_error_message_build(
const wchar_t* description,
const char* fn_only, int line, const char* func,
uint skip, void* context,
@ -682,6 +682,6 @@ extern const wchar_t* debug_error_message_build(
* call at exit to avoid some leaks.
* not strictly necessary.
**/
extern void debug_shutdown();
LIB_API void debug_shutdown();
#endif // #ifndef INCLUDED_DEBUG

View File

@ -0,0 +1,216 @@
#include "precompiled.h"
#include "frequency_filter.h"
/**
* variable-width window for frequency determination
**/
class FrequencyEstimator : boost::noncopyable
{
public:
FrequencyEstimator(double resolution)
: m_minDeltaTime(4.0 * resolution) // chosen to reduce error but still yield rapid updates.
, m_lastTime(0) // will be set on first XX call
, m_numEvents(1)
{
}
bool operator()(double time, double& frequency)
{
// first call
if(m_lastTime == 0.0)
{
m_lastTime = time;
return false;
}
// count # events until deltaTime is large enough
// (reduces quantization errors if resolution is low)
const double deltaTime = time - m_lastTime;
if(deltaTime < m_minDeltaTime)
{
m_numEvents++;
return false;
}
m_lastTime = time;
frequency = (1.0 / deltaTime) * m_numEvents;
m_numEvents = 1;
return true; // success
}
private:
const double m_minDeltaTime;
double m_lastTime;
int m_numEvents;
};
/**
* variable-gain IIR filter
**/
class IirFilter
{
public:
IirFilter(double old)
: m_old(old)
{
}
// bias = 0: no change. > 0: increase (n-th root). < 0: decrease (^n)
double operator()(double x, int bias)
{
// sensitivity to changes ([0,1]).
// approximately equal to a 16 sample average.
const double gain = pow(0.08, ComputeExponent(bias));
return m_old = x*gain + m_old*(1.0-gain);
}
private:
static double ComputeExponent(int bias)
{
if(bias > 0)
return 1.0 / bias; // n-th root
else if(bias == 0)
return 1.0; // no change
else
return -bias; // power-of-n
}
double m_old;
};
/**
* regulate IIR gain for rapid but smooth tracking of a function.
* this is similar in principle to a PID controller but is tuned for
* the special case of FPS values to simplify stabilizing the filter.
**/
class Controller
{
public:
Controller(double initialValue)
: m_timesOnSameSide(0)
{
std::fill(m_history, m_history+m_historySize, initialValue);
}
// bias := exponential change to gain, (-inf, inf)
int ComputeBias(double smoothedValue, double value)
{
if(!WasOnSameSide(value)) // (must be done before updating history)
m_timesOnSameSide = 0; // see below
// update history
std::copy(m_history, m_history+m_historySize, m_history+1);
m_history[m_historySize-1] = value;
// suppress large jumps.
if(Change(m_history[m_historySize-1], value) > 0.30)
return -4; // gain -> 0
// dampen spikes/bounces.
if(WasSpike())
return -1;
if(Change(smoothedValue, value) > 0.02) // ignore minor jitter
{
m_timesOnSameSide++;
// if the past few samples have been consistently above/below
// average, the function is changing and we need to catch up.
// (similar to I in a PID)
if(m_timesOnSameSide >= 3)
return std::min(m_timesOnSameSide, 4);
}
return 0;
}
private:
bool WasOnSameSide(double value) const
{
int sum = 0;
for(size_t i = 0; i < m_historySize; i++)
{
const int vote = (value >= m_history[i])? 1 : -1;
sum += vote;
}
return abs(sum) == m_historySize;
}
static double Change(double from, double to)
{
return fabs(from - to) / from;
}
// /\ or \/ in last three history entries
bool WasSpike() const
{
cassert(m_historySize >= 3);
const double h2 = m_history[m_historySize-3], h1 = m_history[m_historySize-2], h0 = m_history[m_historySize-1];
if(((h2-h1) * (h1-h0)) > 0) // no sign change
return false;
if(Change(h2, h0) > 0.05) // overall change from oldest to newest value
return false;
if(Change(h1, h0) < 0.10) // no intervening spike
return false;
return true;
}
static const size_t m_historySize = 3;
double m_history[m_historySize];
int m_timesOnSameSide;
};
class FrequencyFilter : public IFrequencyFilter
{
public:
FrequencyFilter(double resolution, double expectedFrequency)
: m_controller(expectedFrequency), m_frequencyEstimator(resolution), m_iirFilter(expectedFrequency)
, m_stableFrequency(expectedFrequency), m_smoothedFrequency(expectedFrequency)
{
}
virtual void Update(double time)
{
double frequency;
if(!m_frequencyEstimator(time, frequency))
return;
const int bias = m_controller.ComputeBias(m_smoothedFrequency, frequency);
m_smoothedFrequency = m_iirFilter(frequency, bias);
// allow the smoothed FPS to free-run until it is no longer near the
// previous stable FPS value. round up because values are more often
// too low than too high.
const double difference = fabs(m_smoothedFrequency - m_stableFrequency);
if(difference > fminf(5.f, 0.05f*m_stableFrequency))
m_stableFrequency = (int)(m_smoothedFrequency + 0.99);
}
virtual double SmoothedFrequency() const
{
return m_smoothedFrequency;
}
virtual int StableFrequency() const
{
return m_stableFrequency;
}
private:
FrequencyEstimator m_frequencyEstimator;
Controller m_controller;
IirFilter m_iirFilter;
int m_stableFrequency;
double m_smoothedFrequency;
};
PIFrequencyFilter CreateFrequencyFilter(double resolution, double expectedFrequency)
{
return PIFrequencyFilter(new FrequencyFilter(resolution, expectedFrequency));
}

View File

@ -0,0 +1,21 @@
#ifndef INCLUDED_FREQUENCY_FILTER
#define INCLUDED_FREQUENCY_FILTER
// calculate frequency of events (tuned for 100 Hz)
struct IFrequencyFilter
{
virtual void Update(double value) = 0;
// smoothed but rapidly tracked frequency
virtual double SmoothedFrequency() const = 0;
// stable, non-fluctuating value for user display
virtual int StableFrequency() const = 0;
};
typedef shared_ptr<IFrequencyFilter> PIFrequencyFilter;
// expectedFrequency is a guess that hopefully speeds up convergence
LIB_API PIFrequencyFilter CreateFrequencyFilter(double resolution, double expectedFrequency);
#endif // #ifndef INCLUDED_FREQUENCY_FILTER

View File

@ -47,7 +47,7 @@ static void dispatch_ev(const SDL_Event_* ev)
continue;
// .. invalid return value
else
debug_warn("invalid handler return value");
debug_assert(0); // invalid handler return value
}
}

View File

@ -498,7 +498,7 @@ return pool;
debug_assert(0 <= num_pools && num_pools <= MAX_POOLS);
if(num_pools >= MAX_POOLS)
{
debug_warn("increase MAX_POOLS");
debug_assert(0); // increase MAX_POOLS
return 0;
}
@ -516,7 +516,7 @@ size = round_up(size, 8);
// would overflow a bucket
if(size > BUCKET_SIZE-sizeof(u8*))
{
debug_warn("sbh_alloc: size doesn't fit in a bucket");
debug_assert(0); // size doesn't fit in a bucket
return 0;
}
@ -533,7 +533,7 @@ TNode* node_alloc(size_t size)
// would overflow a bucket
if(size > BUCKET_SIZE-sizeof(u8*))
{
debug_warn("node_alloc: size doesn't fit in a bucket");
debug_assert(0); // size doesn't fit in a bucket
return 0;
}

View File

@ -81,7 +81,7 @@ u8 u8_from_double(double in)
{
if(!(0.0 <= in && in < 1.0))
{
debug_warn("clampf not in [0,1)");
debug_assert(0); // clampf not in [0,1)
return 255;
}
@ -95,7 +95,7 @@ u16 u16_from_double(double in)
{
if(!(0.0 <= in && in < 1.0))
{
debug_warn("clampf not in [0,1)");
debug_assert(0); // clampf not in [0,1)
return 65535;
}

12
source/lib/lib_api.h Normal file
View File

@ -0,0 +1,12 @@
// note: EXTERN_C cannot be used because shared_ptr is often returned
// by value, which requires C++ linkage.
#ifdef LIB_DLL
# ifdef LIB_BUILD
# define LIB_API __declspec(dllexport)
# else
# define LIB_API __declspec(dllimport)
# endif
#else
# define LIB_API
#endif

View File

@ -259,7 +259,7 @@ STMT(\
)
// just pass on errors without any kind of annoying warning
// (useful for functions that can legitimately fail, e.g. vfs_exists).
// (useful for functions that can legitimately fail).
#define RETURN_ERR(expression)\
STMT(\
i64 err64__ = (i64)(expression);\

View File

@ -268,7 +268,7 @@ retry:
// start over. this won't realistically happen, though.
if(num_hps >= max_hps)
{
debug_warn("max_hps overrun - why?");
debug_assert(0); // max_hps overrun - why?
goto retry;
}
@ -624,7 +624,7 @@ LibError lfh_init(LFHash* hash, size_t num_entries)
if(!is_pow2((long)num_entries))
{
debug_warn("lfh_init: size must be power of 2");
debug_assert(0); // lfh_init: size must be power of 2
return ERR::INVALID_PARAM;
}

View File

@ -11,7 +11,6 @@
#ifndef INCLUDED_LOCKFREE
#define INCLUDED_LOCKFREE
#include "posix/posix_types.h" // uintptr_t
#include "lib/sysdep/cpu.h" // cpu_CAS
/*

View File

@ -90,6 +90,47 @@ good luck!
*/
//
// memory headers
//
// these are all system headers that contain "new", "malloc" etc.; they must
// come before the memory tracker headers to avoid conflicts with their
// macros. therefore, they are always included, even if !CONFIG_PCH.
#if OS_WIN
# include <malloc.h>
# include <xdebug>
# include <xtree>
#endif
#include <new>
#include <memory>
#include <locale> // operator new
#include <valarray> // free() member function
// VC debug memory allocator / leak detector
// notes:
// - PCH is required because it makes sure system headers are included
// before redefining new (otherwise, tons of errors result);
// - disabled on ICC9 because the ICC 9.0.006 beta appears to generate
// incorrect code when we redefine new.
// TODO: remove when no longer necessary
#if MSC_VERSION && \
(!defined(NDEBUG) || defined(TESTING)) && \
HAVE_PCH && \
ICC_VERSION != 900
# define HAVE_VC_DEBUG_ALLOC 1
#else
# define HAVE_VC_DEBUG_ALLOC 0
#endif
#ifndef INCLUDED_MMGR
#define INCLUDED_MMGR

View File

@ -19,7 +19,6 @@
#include "debug.h"
#include "lib/sysdep/gfx.h"
#include "lib/res/h_mgr.h"
#include "lib/res/graphics/tex.h"
#if MSC_VERSION
#pragma comment(lib, "opengl32.lib")
@ -164,7 +163,7 @@ bool ogl_HaveVersion(const char* desired_version)
int desired_major, desired_minor;
if(sscanf(desired_version, "%d.%d", &desired_major, &desired_minor) != 2)
{
debug_warn("invalid version string");
debug_assert(0); // invalid version string
return false;
}
@ -172,7 +171,7 @@ bool ogl_HaveVersion(const char* desired_version)
const char* version = (const char*)glGetString(GL_VERSION);
if(!version || sscanf(version, "%d.%d", &major, &minor) != 2)
{
debug_warn("GL_VERSION invalid");
debug_assert(0); // GL_VERSION invalid
return false;
}
@ -267,7 +266,7 @@ static void dump_gl_error(GLenum err)
void ogl_WarnIfError()
{
// glGetError may return multiple errors, so we poll it in a loop.
// the debug_warn should only happen once (if this is set), though.
// the debug_printf should only happen once (if this is set), though.
bool error_enountered = false;
GLenum first_error = 0;
@ -288,7 +287,7 @@ void ogl_WarnIfError()
{
char msg[64];
snprintf(msg, ARRAY_SIZE(msg), "OpenGL error(s) occurred: %04x", (int)first_error);
debug_warn(msg);
debug_printf(msg);
}
}
#endif
@ -303,7 +302,7 @@ void ogl_WarnIfError()
void ogl_SquelchError(GLenum err_to_ignore)
{
// glGetError may return multiple errors, so we poll it in a loop.
// the debug_warn should only happen once (if this is set), though.
// the debug_printf should only happen once (if this is set), though.
bool error_enountered = false;
GLenum first_error = 0;
@ -327,7 +326,7 @@ void ogl_SquelchError(GLenum err_to_ignore)
{
char msg[64];
snprintf(msg, ARRAY_SIZE(msg), "OpenGL error(s) occurred: %04x", (int)first_error);
debug_warn(msg);
debug_printf(msg);
}
}
@ -371,8 +370,7 @@ void ogl_Init()
// note: this is less about performance (since the above are not
// time-critical) than centralizing the 'OpenGL is ready' check.
exts = (const char*)glGetString(GL_EXTENSIONS);
if(!exts)
debug_warn("called before OpenGL is ready for use");
debug_assert(exts); // else: called before OpenGL is ready for use
have_12 = ogl_HaveVersion("1.2");
have_13 = ogl_HaveVersion("1.3");
have_14 = ogl_HaveVersion("1.4");

View File

@ -1,7 +1,7 @@
#include "precompiled.h"
#include "posix.h"
#if CPU_IA32
#if ARCH_IA32
# include "lib/sysdep/ia32/ia32_asm.h"
#endif
@ -10,7 +10,7 @@
float rintf(float f)
{
#if CPU_IA32
#if ARCH_IA32
return ia32_asm_rintf(f);
#else
return (float)(int)f;
@ -19,7 +19,7 @@ float rintf(float f)
double rint(double d)
{
#if CPU_IA32
#if ARCH_IA32
return ia32_asm_rint(d);
#else
return (double)(int)d;
@ -29,7 +29,7 @@ double rint(double d)
float fminf(float a, float b)
{
#if CPU_IA32
#if ARCH_IA32
return ia32_asm_fminf(a, b);
#else
return (a < b)? a : b;
@ -38,7 +38,7 @@ float fminf(float a, float b)
float fmaxf(float a, float b)
{
#if CPU_IA32
#if ARCH_IA32
return ia32_asm_fmaxf(a, b);
#else
return (a > b)? a : b;
@ -48,7 +48,7 @@ float fmaxf(float a, float b)
uint fpclassifyd(double d)
{
#if CPU_IA32
#if ARCH_IA32
return ia32_asm_fpclassifyd(d);
#else
// really sucky stub implementation; doesn't attempt to cover all cases.
@ -62,7 +62,7 @@ uint fpclassifyd(double d)
uint fpclassifyf(float f)
{
#if CPU_IA32
#if ARCH_IA32
return ia32_asm_fpclassifyf(f);
#else
const double d = (double)f;
@ -73,19 +73,7 @@ uint fpclassifyf(float f)
#endif // #if !HAVE_C99_MATH
#if !HAVE_STRDUP
char* strdup(const char* str)
{
const size_t num_chars = strlen(str);
char* dst = (char*)malloc((num_chars+1)*sizeof(char)); // note: strdup is required to use malloc
if(!dst)
return 0;
SAFE_STRCPY(dst, str);
return dst;
}
#endif
#if !HAVE_WCSDUP
#if EMULATE_WCSDUP
wchar_t* wcsdup(const wchar_t* str)
{
const size_t num_chars = wcslen(str);
@ -95,4 +83,4 @@ wchar_t* wcsdup(const wchar_t* str)
SAFE_WCSCPY(dst, str);
return dst;
}
#endif // #if !HAVE_WCSDUP
#endif

View File

@ -81,15 +81,24 @@ need only be renamed (e.g. _open, _stat).
#define strncasecmp strnicmp
#endif
#if !HAVE_STRDUP
extern char* strdup(const char* str);
#if OS_MACOSX
# define EMULATE_WCSDUP 1
#else
# define EMULATE_WCSDUP 0
#endif
#if !HAVE_WCSDUP
#if EMULATE_WCSDUP
extern wchar_t* wcsdup(const wchar_t* str);
#endif
// rint*, fminf, fpclassify (too few/diverse to make separate HAVE_ for each)
#if HAVE_C99 || GCC_VERSION
# define HAVE_C99_MATH 1
#else
# define HAVE_C99_MATH 0
#endif
#if !HAVE_C99_MATH
// round float to nearest integral value, according to
// current rounding mode.

View File

@ -7,7 +7,3 @@
#endif
#include "posix_errno.h" // for user convenience
#if !HAVE_MKDIR
extern int mkdir(const char* path, mode_t mode);
#endif

View File

@ -3,21 +3,20 @@
* File : precompiled.h
* Project : 0 A.D.
* Description : precompiled header. must be the first non-comment part
* : of every source file (VC6/7 requirement).
* : of every source file (VC6..8 requirement).
* =========================================================================
*/
// license: GPL; see lib/license.txt
// if the compiler supports PCH (i.e. HAVE_PCH is defined), this
// tries to include all headers that may be needed. otherwise, all source
// files will still need to include this (for various global fixes and the
// memory trackers), but additionally include all required headers.
//
// this policy yields the best compile performance with or without PCH.
// if PCHs are supported and enabled, we make an effort to include all
// system headers. otherwise, only a few headers (e.g. memory tracker)
// are pulled in and source files must include all the system headers
// they use. this policy ensures good compile performance whether or not
// PCHs are being used.
// must come before warning disables.
#include "lib/config.h"
#include "lib/config.h" // CONFIG_ENABLE_PCH
#include "lib/sysdep/compiler.h" // HAVE_PCH
// disable some common and annoying warnings
// (done as soon as possible so that headers below are covered)
@ -39,53 +38,48 @@
# endif
#endif
//
// headers made available everywhere for convenience
//
#include "lib/sysdep/compiler.h"
#include "lib/sysdep/stl.h"
#include "lib/sysdep/os.h"
#include "lib/sysdep/arch.h"
#include "lib/lib_api.h"
#include "lib/types.h"
#include "lib/lib.h"
#include "lib/lib_errors.h"
#include "lib/secure_crt.h"
#include "lib/debug.h"
#include "lib/code_annotation.h"
#include "lib/sysdep/compiler.h"
#include "lib/sysdep/stl.h"
// Boost
#include <boost/utility.hpp> // noncopyable
#include <boost/shared_array.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#pragma warning(push, 3) // filesystem isn't W4-clean
#include <boost/filesystem.hpp>
#pragma warning(pop)
using boost::shared_ptr; // has been added to TR1
namespace fs = boost::filesystem;
// (this must come after boost and common lib headers)
#include "lib/posix/posix.h"
//
// memory headers
// precompiled headers
//
// these are all system headers that contain "new", "malloc" etc.; they must
// come before the memory tracker headers to avoid conflicts with their
// macros. therefore, they are always included, even if !HAVE_PCH.
#if CONFIG_ENABLE_PCH && HAVE_PCH
#if OS_WIN
# include <malloc.h>
#endif
#include <new>
#include <memory>
#include <valarray> // free() member function
//
// headers to be precompiled
//
// candidates are all system headers we may possibly need or large/rarely
// changed project headers; everything placed in here will not need to be
// compiled every time. however, if they change, the project will have to be
// completely rebuilt. (slow!)
//
// if the compiler doesn't support precompiled headers (i.e. !HAVE_PCH),
// including anything here would actually slow things down, because we might
// not otherwise need some of these headers. therefore, do nothing and rely
// on all source files (additionally) including everything they need.
#if HAVE_PCH
// anything placed here won't need to be compiled in each translation unit,
// but will cause a complete rebuild if they change.
// all new-form C library headers
#include <cassert>
@ -96,8 +90,7 @@
#include <climits>
#include <clocale>
#include <cmath>
// Including setjmp.h here causes incompatibilities with libpng on Debian/Ubuntu
//#include <csetjmp>
//#include <csetjmp> // incompatible with libpng on Debian/Ubuntu
#include <csignal>
#include <cstdarg>
#include <cstddef>
@ -154,32 +147,13 @@
# include <hash_set>
#endif
// (further headers to be precompiled go here)
#endif // #if HAVE_PCH
#endif // #if CONFIG_PCH
// restore temporarily-disabled warnings
#if MSC_VERSION
# pragma warning(default:4702)
#endif
//
// memory trackers
//
// these must be included from every file to make sure all allocations
// are hooked. placing in the precompiled header is more convenient than
// manually #including from every file, but requires that all system
// headers containing "new", "malloc" etc. come before this (see above).
//
// note: mmgr.h activates mmgr or the VC debug heap or nothing depending
// on CONFIG_USE_MMGR and HAVE_VC_DEBUG_ALLOC settings.
# include "mmgr.h"
// Boost
#include <boost/utility.hpp> // noncopyable
#include <boost/shared_array.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
// (this must be included from every file to make sure all allocations
// are tracked; placing it in the PCH is a convenient means of doing so)
#include "mmgr.h"

View File

@ -79,16 +79,13 @@ ERROR_ASSOCIATE(ERR::STRING_NOT_TERMINATED, "Invalid string (no 0 terminator fou
// currently disabled due to high risk of false positives.
#define WARN_IF_PTR_LEN(len)\
/*
STMT( \
if(len == sizeof(char*)) \
debug_warn("make sure string buffer size is correct");\
)*/
debug_assert(len != sizeof(char*));
*/
// skip our implementation if already available, but not the
// self-test and the t* defines (needed for test).
#if !HAVE_SECURE_CRT
#if EMULATE_SECURE_CRT
#if !OS_UNIX || OS_MACOSX
// return length [in characters] of a string, not including the trailing
@ -237,4 +234,4 @@ errno_t tfopen_s(FILE** pfile, const tchar* filename, const tchar* mode)
}
#endif
#endif // #if !HAVE_SECURE_CRT
#endif // #if EMULATE_SECURE_CRT

View File

@ -11,16 +11,20 @@
#ifndef INCLUDED_SECURE_CRT
#define INCLUDED_SECURE_CRT
#include "posix/posix_types.h" // size_t
namespace ERR
{
const LibError STRING_NOT_TERMINATED = -100600;
}
// only declare these functions if using our implementation
// (otherwise, we risk incompatibilities)
#if !HAVE_SECURE_CRT
// if the platform lacks a secure CRT implementation, we'll provide one.
#if MSC_VERSION >= 1400
# define EMULATE_SECURE_CRT 0
#else
# define EMULATE_SECURE_CRT 1
#endif
#if EMULATE_SECURE_CRT
// (conflicts with glibc definitions)
#if !OS_UNIX
@ -78,5 +82,5 @@ extern errno_t _wfopen_s(FILE** pfile, const wchar_t* filename, const wchar_t* m
#define fscanf_s fscanf
#endif // #if !HAVE_SECURE_CRT
#endif // #if EMULATE_SECURE_CRT
#endif // #ifndef INCLUDED_SECURE_CRT

View File

@ -11,6 +11,38 @@
#ifndef INCLUDED_COMPILER
#define INCLUDED_COMPILER
#include "config.h" // CONFIG_OMIT_FP
// detect compiler and its version (0 if not present, otherwise
// major*100 + minor). note that more than one *_VERSION may be
// non-zero due to interoperability (e.g. ICC with MSC).
// .. VC
#ifdef _MSC_VER
# define MSC_VERSION _MSC_VER
#else
# define MSC_VERSION 0
#endif
// .. ICC (VC-compatible)
#if defined(__INTEL_COMPILER)
# define ICC_VERSION __INTEL_COMPILER
#else
# define ICC_VERSION 0
#endif
// .. LCC (VC-compatible)
#if defined(__LCC__)
# define LCC_VERSION __LCC__
#else
# define LCC_VERSION 0
#endif
// .. GCC
#ifdef __GNUC__
# define GCC_VERSION (__GNUC__*100 + __GNUC_MINOR__)
#else
# define GCC_VERSION 0
#endif
// pass "omit frame pointer" setting on to the compiler
#if MSC_VERSION
# if CONFIG_OMIT_FP
@ -23,6 +55,16 @@
#endif
// are PreCompiled Headers supported?
#if MSC_VERSION
# define HAVE_PCH 1
#elif defined(USING_PCH)
# define HAVE_PCH 1
#else
# define HAVE_PCH 0
#endif
// try to define _W64, if not already done
// (this is useful for catching pointer size bugs)
#ifndef _W64
@ -36,6 +78,29 @@
#endif
// check if compiling in pure C mode (not C++) with support for C99.
// (this is more convenient than testing __STDC_VERSION__ directly)
//
// note: C99 provides several useful but disjunct bits of functionality.
// unfortunately, most C++ compilers do not offer a complete implementation.
// however, many of these features are likely to be added to C++, and/or are
// already available as extensions. what we'll do is add a HAVE_ macro for
// each feature and test those instead. they are set if HAVE_C99, or also if
// the compiler happens to support something compatible.
//
// rationale: lying about __STDC_VERSION__ via Premake so as to enable support
// for some C99 functions doesn't work. Mac OS X headers would then use the
// restrict keyword, which is never supported by g++ (because that might
// end up breaking valid C++98 programs).
#define HAVE_C99 0
#ifdef __STDC_VERSION__
# if __STDC_VERSION__ >= 199901L
# undef HAVE_C99
# define HAVE_C99 1
# endif
#endif
// C99-like restrict (non-standard in C++, but widely supported in various forms).
//
// May be used on pointers. May also be used on member functions to indicate
@ -99,6 +164,7 @@
# define ASSUME_UNREACHABLE
#endif
// extern "C", but does the right thing in pure-C mode
#if defined(__cplusplus)
# define EXTERN_C extern "C"

View File

@ -151,7 +151,9 @@ extern void cpu_ConfigureFloatingPoint();
// convert float to int much faster than _ftol2, which would normally be
// used by (int) casts.
#if !USE_IA32_FLOAT_TO_INT
// should we use our float->int code? newer GCC versions with -ffast-math and
// VC8 can use SSE, so skip it there.
#if ARCH_IA32 && MSC_VERSION && MSC_VERSION < 1400
#define cpu_i32FromFloat(f) ((i32)f)
#define cpu_i32FromDouble(d) ((i32)d)
#define cpu_i64FromDouble(d) ((i64)d)
@ -172,7 +174,7 @@ extern i64 cpu_i64FromDouble(double d);
* casting in user code.
**/
template<typename T>
extern bool cpu_CAS(volatile T* location, T expected, T new_value)
bool cpu_CAS(volatile T* location, T expected, T new_value)
{
return cpu_CAS((volatile uintptr_t*)location, (uintptr_t)expected, (uintptr_t)new_value);
}

View File

@ -11,8 +11,8 @@
#ifndef INCLUDED_IA32
#define INCLUDED_IA32
#if !CPU_IA32
#error "including ia32.h without CPU_IA32=1"
#if !ARCH_IA32
#error "including ia32.h without ARCH_IA32=1"
#endif
#include "ia32_asm.h"
@ -35,7 +35,7 @@ extern Ia32Vendor ia32_Vendor();
/**
* @return the colloquial processor generation
* (6 = Pentium II / K6, 7 = Pentium III / Athlon, 8 = Opteron)
* (5 = Pentium, 6 = Pentium Pro/II/III / K6, 7 = Pentium4 / Athlon, 8 = Core / Opteron)
**/
extern uint ia32_Generation();

View File

@ -11,10 +11,44 @@
#ifndef INCLUDED_STL
#define INCLUDED_STL
// compiling without exceptions (usually for performance reasons);
// tell STL not to generate any.
#include "config.h"
#include "compiler.h"
// detect STL version
// .. Dinkumware
#if MSC_VERSION
# include <yvals.h> // defines _CPPLIB_VER
#endif
#if defined(_CPPLIB_VER)
# define STL_DINKUMWARE _CPPLIB_VER
#else
# define STL_DINKUMWARE 0
#endif
// .. GCC
#if defined(__GLIBCPP__)
# define STL_GCC __GLIBCPP__
#elif defined(__GLIBCXX__)
# define STL_GCC __GLIBCXX__
#else
# define STL_GCC 0
#endif
// .. ICC
#if defined(__INTEL_CXXLIB_ICC)
# define STL_ICC __INTEL_CXXLIB_ICC
#else
# define STL_ICC 0
#endif
// disable (slow!) iterator checks in release builds (unless someone already defined this)
#if STL_DINKUMWARE && defined(NDEBUG) && !defined(_SECURE_SCL)
# define _SECURE_SCL 0
#endif
// pass "disable exceptions" setting on to the STL
#if CONFIG_DISABLE_EXCEPTIONS
# if OS_WIN
# if STL_DINKUMWARE
# define _HAS_EXCEPTIONS 0
# else
# define STL_NO_EXCEPTIONS
@ -26,7 +60,8 @@
// these containers are useful but not part of C++98. most STL vendors
// provide them in some form; we hide their differences behind macros.
#if GCC_VERSION
#if STL_GCC
# include <ext/hash_map>
# include <ext/hash_set>
@ -76,7 +111,7 @@ namespace __gnu_cxx
};
}
#else // !__GNUC__
#elif STL_DINKUMWARE
# include <hash_map>
# include <hash_set>
@ -96,6 +131,15 @@ namespace __gnu_cxx
# define STL_HASH_VALUE std::hash_value
# endif // MSC_VERSION >= 1300
#endif // !__GNUC__
#endif
// nonstandard STL containers
#define HAVE_STL_SLIST 0
#if STL_DINKUMWARE
# define HAVE_STL_HASH 1
#else
# define HAVE_STL_HASH 0
#endif
#endif // #ifndef INCLUDED_STL

View File

@ -4,6 +4,12 @@
#include "precompiled.h"
#if OS_LINUX
# define HAVE_X 1
#else
# define HAVE_X 0
#endif
#if HAVE_X
#include <Xlib.h>

View File

@ -1,35 +1,23 @@
// Microsoft Visual C++ generated resource script.
//
#include "error_dialog.h"
#include <windows.h>
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
#ifdef APSTUDIO_INVOKED
1 TEXTINCLUDE
BEGIN
"error_dialog.h\0"
END
2 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
@ -39,15 +27,13 @@ END
//
IDD_DIALOG1 DIALOGEX 0, 0, 328, 260
STYLE DS_SETFONT | DS_SETFOREGROUND | DS_FIXEDSYS | WS_MINIMIZEBOX |
WS_MAXIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_TOPMOST | WS_EX_APPWINDOW
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "Program Error"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "&Continue",IDC_CONTINUE,7,239,50,14
EDITTEXT IDC_EDIT1,7,7,314,204,ES_MULTILINE | ES_READONLY |
ES_WANTRETURN | WS_VSCROLL
EDITTEXT IDC_EDIT1,7,7,314,204,ES_MULTILINE | ES_READONLY | ES_WANTRETURN | WS_VSCROLL
PUSHBUTTON "Copy",IDC_COPY,271,212,50,14
PUSHBUTTON "&Suppress",IDC_SUPPRESS,59,239,50,14
PUSHBUTTON "&Break",IDC_BREAK,111,239,50,14
@ -73,6 +59,4 @@ BEGIN
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////

View File

@ -30,8 +30,10 @@ static void unlock()
static NT_TIB* get_tib()
{
#if CPU_IA32
#if ARCH_IA32
NT_TIB* tib;
// ICC 10 doesn't support the NT_TIB.Self syntax, so we have to use
// a constant (asm code isn't 64-bit safe anyway).
__asm
{
mov eax, fs:[NT_TIB.Self]
@ -126,7 +128,7 @@ static void* while_suspended_thread_func(void* user_arg)
// abort, since GetThreadContext only works if the target is suspended.
if(err == (DWORD)-1)
{
debug_warn("while_suspended_thread_func: SuspendThread failed");
debug_assert(0); // while_suspended_thread_func: SuspendThread failed
return (void*)(intptr_t)-1;
}
// target is now guaranteed to be suspended,
@ -251,8 +253,7 @@ have_reg:
rw = 1; break;
case DBG_BREAK_DATA_WRITE:
rw = 3; break;
default:
debug_warn("invalid type");
NODEFAULT;
}
// .. length (determine from addr's alignment).
// note: IA-32 requires len=0 for code breakpoints.
@ -296,7 +297,7 @@ static LibError brk_do_request(HANDLE hThread, void* arg)
if(!GetThreadContext(hThread, &context))
WARN_RETURN(ERR::FAIL);
#if CPU_IA32
#if ARCH_IA32
if(bi->want_all_disabled)
ret = brk_disable_all_in_ctx(bi, &context);
else
@ -354,7 +355,7 @@ LibError debug_remove_all_breaks()
// but can be used to filter out obviously wrong values in a portable manner.
int debug_is_pointer_bogus(const void* p)
{
#if CPU_IA32
#if ARCH_IA32
if(p < (void*)0x10000)
return true;
if(p >= (void*)(uintptr_t)0x80000000)
@ -440,6 +441,6 @@ void wdbg_set_thread_name(const char* name)
__except(EXCEPTION_EXECUTE_HANDLER)
{
// if we get here, the debugger didn't handle the exception.
debug_warn("thread name hack doesn't work under this debugger");
debug_assert(0); // thread name hack doesn't work under this debugger
}
}

View File

@ -11,7 +11,7 @@
#ifndef INCLUDED_WDBG
#define INCLUDED_WDBG
#if HAVE_MS_ASM
#if MSC_VERSION
# define debug_break() __asm { int 3 }
#else
# error "port this or define to implementation function"

View File

@ -21,7 +21,7 @@
#include "lib/debug_stl.h"
#include "lib/app_hooks.h"
#include "lib/path_util.h"
#if CPU_IA32
#if ARCH_IA32
# include "lib/sysdep/ia32/ia32.h"
#endif
#include "win.h"
@ -261,7 +261,7 @@ func2:
*/
#if CPU_IA32 && !CONFIG_OMIT_FP
#if ARCH_IA32 && !CONFIG_OMIT_FP
static LibError ia32_walk_stack(STACKFRAME64* sf)
{
@ -299,7 +299,7 @@ static LibError ia32_walk_stack(STACKFRAME64* sf)
return INFO::OK;
}
#endif // #if CPU_IA32 && !CONFIG_OMIT_FP
#endif // #if ARCH_IA32 && !CONFIG_OMIT_FP
// called for each stack frame found by walk_stack, passing information
@ -351,7 +351,7 @@ static LibError walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip
// this MUST be done inline and not in an external function because
// compiler-generated prolog code trashes some registers.
#if CPU_IA32
#if ARCH_IA32
ia32_asm_GetCurrentContext(&context);
#else
// preferred implementation (was imported during module init)
@ -384,7 +384,7 @@ static LibError walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrFrame.Mode = AddrModeFlat;
sf.AddrStack.Mode = AddrModeFlat;
#if CPU_AMD64
#if ARCH_AMD64
sf.AddrPC.Offset = pcontext->Rip;
sf.AddrFrame.Offset = pcontext->Rbp;
sf.AddrStack.Offset = pcontext->Rsp;
@ -412,7 +412,7 @@ static LibError walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip
// code is authoritative provided its prerequisite (FP not omitted)
// is met, otherwise totally unusable.
LibError err;
#if CPU_IA32 && !CONFIG_OMIT_FP
#if ARCH_IA32 && !CONFIG_OMIT_FP
err = ia32_walk_stack(&sf);
#else
sym_init();
@ -420,7 +420,7 @@ static LibError walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip
// so we have to reset it and check for 0. *sigh*
SetLastError(0);
const HANDLE hThread = GetCurrentThread();
BOOL ok = StackWalk64(machine, hProcess, hThread, &sf, pcontext, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0);
BOOL ok = StackWalk64(machine, hProcess, hThread, &sf, (PVOID)pcontext, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0);
// note: don't use LibError_from_win32 because it raises a warning,
// and this "fails" commonly (when no stack frames are left).
err = ok? INFO::OK : ERR::FAIL;
@ -561,7 +561,7 @@ static void out(const wchar_t* fmt, ...)
// make sure out_chars_left remains nonnegative
if((size_t)len > out_chars_left)
{
debug_warn("apparently wrote more than out_chars_left");
debug_assert(0); // apparently wrote more than out_chars_left
len = (int)out_chars_left;
}
out_chars_left -= len;
@ -926,11 +926,7 @@ static LibError determine_symbol_address(DWORD id, DWORD UNUSED(type_id), const
case DataIsGlobal:
break;
default:
debug_warn("unexpected data_kind");
//case DataIsConstant
NODEFAULT;
}
// get SYMBOL_INFO (we need .Flags)
@ -1069,7 +1065,7 @@ static LibError dump_sym_base_type(DWORD type_id, const u8* p, DumpState state)
if(size == sizeof(float))
*(double*)&data = (double)*(float*)&data;
else if(size != sizeof(double))
debug_warn("dump_sym_base_type: invalid float size");
debug_assert(0); // invalid float size
fmt = L"%g";
break;
@ -1077,7 +1073,7 @@ static LibError dump_sym_base_type(DWORD type_id, const u8* p, DumpState state)
case btInt:
case btLong:
if(size != 1 && size != 2 && size != 4 && size != 8)
debug_warn("dump_sym_base_type: invalid int size");
debug_assert(0); // invalid int size
// need to re-load and sign-extend, because we output 64 bits.
data = movsx_le64(p, size);
fmt = L"%I64d";
@ -1107,7 +1103,7 @@ display_as_hex:
else if(size == 8)
fmt = L"0x%016I64X";
else
debug_warn("dump_sym_base_type: invalid uint size");
debug_assert(0); // invalid uint size
break;
// character
@ -1135,7 +1131,7 @@ display_as_hex:
fmt = L"";
}
else
debug_warn("dump_sym_base_type: non-pointer btVoid or btNoType");
debug_assert(0); // non-pointer btVoid or btNoType
break;
default:
@ -1866,6 +1862,9 @@ static LibError dump_frame_cb(const STACKFRAME64* sf, void* UNUSED(user_arg))
LibError debug_dump_stack(wchar_t* buf, size_t max_chars, uint skip, void* pcontext)
{
buf='\0';
return INFO::OK;
static uintptr_t already_in_progress;
if(!cpu_CAS(&already_in_progress, 0, 1))
return ERR::REENTERED; // NOWARN

View File

@ -232,7 +232,7 @@ LibError dir_add_watch(const char* dir, intptr_t* preqnum)
// need it before binding dir to IOCP because it is our "key".
if(last_reqnum == INT_MAX)
{
debug_warn("request numbers are no longer unique");
debug_assert(0); // request numbers are no longer unique
CloseHandle(hDir);
goto fail;
}

View File

@ -85,7 +85,7 @@ ICounter* CreateCounter(uint id)
// size until after the alloc / placement new.
if(!cpu_CAS(&isCounterAllocated, 0, 1))
debug_warn("static counter memory is already in use!");
debug_assert(0); // static counter memory is already in use!
static const size_t memSize = 200;
static u8 mem[memSize];

View File

@ -2,7 +2,7 @@
* =========================================================================
* File : hpet.cpp
* Project : 0 A.D.
* Description : Timer implementation using timeGetTime
* Description : Timer implementation using High Precision Event Timer
* =========================================================================
*/

View File

@ -2,7 +2,7 @@
* =========================================================================
* File : hpet.h
* Project : 0 A.D.
* Description : Timer implementation using timeGetTime
* Description : Timer implementation using High Precision Event Timer
* =========================================================================
*/

View File

@ -326,7 +326,7 @@ enum DataKind
#if CPU_IA32
#if ARCH_IA32
// the official version causes pointer truncation warnings.
# undef InterlockedExchangePointer
# define InterlockedExchangePointer(Target, Value) (PVOID)(uintptr_t)InterlockedExchange((PLONG)(Target), (LONG)(uintptr_t)(Value))

View File

@ -21,18 +21,18 @@ WINIT_REGISTER_EARLY_INIT(wmi_Init);
WINIT_REGISTER_EARLY_SHUTDOWN(wmi_Shutdown);
static IWbemLocator* pLoc;
static IWbemServices* pSvc;
_COM_SMARTPTR_TYPEDEF(IWbemLocator, __uuidof(IWbemLocator));
_COM_SMARTPTR_TYPEDEF(IWbemClassObject, __uuidof(IWbemClassObject));
_COM_SMARTPTR_TYPEDEF(IEnumWbemClassObject, __uuidof(IEnumWbemClassObject));
static LibError wmi_Init()
{
HRESULT hr;
// initializing with COINIT_MULTITHREADED causes the (unchanged) value of
// pSvc to be invalid by the time wmi_Shutdown is reached. the cause is
// unclear (maybe another DLL already doing CoUninitialize?), but using
// single-threaded apartment mode (the default) avoids it.
hr = CoInitialize(0);
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
if(FAILED(hr))
WARN_RETURN(ERR::_1);
@ -40,13 +40,16 @@ static LibError wmi_Init()
if(FAILED(hr))
WARN_RETURN(ERR::_2);
hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (void**)&pLoc);
if(FAILED(hr))
WARN_RETURN(ERR::_3);
{
IWbemLocatorPtr pLoc = 0;
hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (void**)&pLoc);
if(FAILED(hr))
WARN_RETURN(ERR::_3);
hr = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), 0, 0, 0, 0, 0, 0, &pSvc);
if(FAILED(hr))
WARN_RETURN(ERR::_4);
hr = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), 0, 0, 0, 0, 0, 0, &pSvc);
if(FAILED(hr))
WARN_RETURN(ERR::_4);
}
hr = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, 0, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, 0, EOAC_NONE);
if(FAILED(hr))
@ -58,10 +61,10 @@ static LibError wmi_Init()
static LibError wmi_Shutdown()
{
pSvc->Release();
pLoc->Release();
CoUninitialize();
// the memory pointed to by pSvc is already invalidated at this point;
// maybe some other module has already wiped out COM?
//pSvc->Release();
//CoUninitialize();
return INFO::OK;
}
@ -70,7 +73,7 @@ LibError wmi_GetClass(const char* className, WmiMap& wmiMap)
{
HRESULT hr;
IEnumWbemClassObject* pEnum = 0;
IEnumWbemClassObjectPtr pEnum = 0;
char query[200];
sprintf_s(query, ARRAY_SIZE(query), "SELECT * FROM %s", className);
hr = pSvc->ExecQuery(L"WQL", _bstr_t(query), WBEM_FLAG_FORWARD_ONLY|WBEM_FLAG_RETURN_IMMEDIATELY, 0, &pEnum);
@ -80,7 +83,7 @@ LibError wmi_GetClass(const char* className, WmiMap& wmiMap)
for(;;)
{
IWbemClassObject* pObj = 0;
IWbemClassObjectPtr pObj = 0;
ULONG numReturned = 0;
hr = pEnum->Next(WBEM_INFINITE, 1, &pObj, &numReturned);
if(FAILED(hr))
@ -103,9 +106,7 @@ LibError wmi_GetClass(const char* className, WmiMap& wmiMap)
wmiMap[name] = value;
SysFreeString(name);
}
pObj->Release();
}
pEnum->Release();
return INFO::OK;
}

View File

@ -32,8 +32,7 @@ char* dlerror(void)
void* dlopen(const char* so_name, int flags)
{
if(flags & RTLD_GLOBAL)
debug_warn("dlopen: unsupported flag(s)");
debug_assert(!(flags & RTLD_GLOBAL));
// if present, strip .so extension; add .dll extension
char dll_name[MAX_PATH];
@ -45,8 +44,7 @@ void* dlopen(const char* so_name, int flags)
SAFE_STRCPY(ext, "dll");
HMODULE hModule = LoadLibrary(dll_name);
if(!hModule)
debug_warn("dlopen failed");
debug_assert(hModule);
return void_from_HMODULE(hModule);
}
@ -55,8 +53,6 @@ void* dlsym(void* handle, const char* sym_name)
{
HMODULE hModule = HMODULE_from_void(handle);
void* sym = GetProcAddress(hModule, sym_name);
if(!sym)
debug_warn("dlsym failed");
debug_assert(sym);
return sym;
}

View File

@ -244,7 +244,7 @@ DIR* opendir(const char* path)
{
errno = ENOENT;
fail:
debug_warn("opendir failed");
debug_assert(0);
return 0;
}
@ -329,7 +329,7 @@ fail:
if(GetLastError() == ERROR_NO_MORE_FILES)
SetLastError(prev_err);
else
debug_warn("readdir: FindNextFile failed");
debug_assert(0); // readdir: FindNextFile failed
return 0;
}

View File

@ -18,8 +18,6 @@
typedef unsigned int mode_t;
#endif
// mkdir is defined by posix_filesystem #if !HAVE_MKDIR
// (christmas-tree values because mkdir mode is ignored anyway)
#define S_IRWXO 0xFFFF
#define S_IRWXU 0xFFFF
@ -28,6 +26,17 @@ typedef unsigned int mode_t;
#define S_ISDIR(m) (m & S_IFDIR)
#define S_ISREG(m) (m & S_IFREG)
// we need to emulate this on VC7 (not included) and VC8 (deprecated)
#if MSC_VERSION
# define EMULATE_MKDIR 1
#else
# define EMULATE_MKDIR 0
#endif
#if EMULATE_MKDIR
extern int mkdir(const char* path, mode_t mode);
#endif
//
// dirent.h

View File

@ -35,8 +35,10 @@ static DWORD win32_prot(int prot)
return PAGE_EXECUTE_READWRITE;
case PROT_READ|PROT_WRITE|PROT_EXEC:
return PAGE_EXECUTE_READWRITE;
NODEFAULT;
NODEFAULT;
}
UNREACHABLE;
}
@ -74,7 +76,7 @@ static LibError mmap_mem(void* start, size_t len, int prot, int flags, int fd, v
WARN_IF_FALSE(VirtualFree(start, len, MEM_DECOMMIT));
*pp = 0;
// make sure *pp won't be misinterpreted as an error
cassert(MAP_FAILED != 0);
cassert(MAP_FAILED);
return INFO::OK;
}
}
@ -126,8 +128,7 @@ static LibError mmap_file_access(int prot, int flags, DWORD& flProtect, DWORD& d
}
static LibError mmap_file(void* start, size_t len, int prot, int flags,
int fd, off_t ofs, void** pp)
static LibError mmap_file(void* start, size_t len, int prot, int flags, int fd, off_t ofs, void** pp)
{
debug_assert(fd != -1); // handled by mmap_mem

View File

@ -27,7 +27,7 @@
// doesn't commit mmap-ed regions anyway, but we specify this flag to
// make sure of that in the future.
#define MAP_FAILED ((void*)-1L)
#define MAP_FAILED ((void*)(intptr_t)-1L)
extern void* mmap(void* start, size_t len, int prot, int flags, int fd, off_t offset);
extern int munmap(void* start, size_t len);

View File

@ -34,9 +34,8 @@ static void InitSysconf()
// import GlobalMemoryStatusEx - it's not defined by the VC6 PSDK.
// used by _SC_*_PAGES if available (provides better results).
const HMODULE hKernel32Dll = LoadLibrary("kernel32.dll");
const HMODULE hKernel32Dll = GetModuleHandle("kernel32.dll");
*(void**)&pGlobalMemoryStatusEx = GetProcAddress(hKernel32Dll, "GlobalMemoryStatusEx");
FreeLibrary(hKernel32Dll);
}
long sysconf(int name)

View File

@ -11,13 +11,6 @@
#ifndef INCLUDED_WTIME
#define INCLUDED_WTIME
// advertise support for the timer routines we emulate; used by timer.cpp.
// #undef to avoid macro redefinition warning.
#undef HAVE_CLOCK_GETTIME
#define HAVE_CLOCK_GETTIME 1
#undef HAVE_GETTIMEOFDAY
#define HAVE_GETTIMEOFDAY 1
//
// <sys/types.h>

View File

@ -32,7 +32,7 @@ int uname(struct utsname* un)
if(ok)
SetLastError(last_err);
else
debug_warn("GetComputerName failed");
debug_assert(0); // GetComputerName failed
// hardware type
static SYSTEM_INFO si;

View File

@ -285,7 +285,7 @@ int sys_vsnprintf(TCHAR* buffer, size_t count, const TCHAR* format, va_list argp
if (chr == _T('I'))
{
debug_warn("MSVC-style \"%I64\" is not allowed!");
debug_assert(0); // MSVC-style \"%I64\" is not allowed!
}
if (is_lengthmod(chr))
@ -413,7 +413,7 @@ finished_reading:
*/
// Because of those dangerous assumptions about varargs:
#if !CPU_IA32
#if !ARCH_IA32
#error SLIGHTLY FATAL ERROR: Only x86 is supported!
#endif
@ -434,7 +434,7 @@ finished_reading:
{
if (varsizes[i] <= 0)
{
debug_warn("Invalid variable type somewhere - make sure all variable things are positional and defined");
debug_assert(0); // Invalid variable type somewhere - make sure all variable things are positional and defined
return -1;
}
@ -456,7 +456,7 @@ finished_reading:
FormatVariable* s = static_cast<FormatVariable*>(*it);
if (s->position <= 0)
{
debug_warn("Invalid use of positional elements - make sure all variable things are positional and defined");
debug_assert(0); // Invalid use of positional elements - make sure all variable things are positional and defined
return -1;
}
newstack += std::string( stackitems[s->position-1].first, stackitems[s->position-1].second );

View File

@ -53,7 +53,7 @@ static uintptr_t get_target_pc()
ret = SuspendThread(hThread);
if(ret == (DWORD)-1)
{
debug_warn("get_target_pc: SuspendThread failed");
debug_assert(0); // get_target_pc: SuspendThread failed
return 0;
}
// note: we don't need to call more than once: this increments a DWORD
@ -114,7 +114,7 @@ static void* prof_thread_func(void* UNUSED(data))
break;
// actual error: warn
if(errno != ETIMEDOUT)
debug_warn("wpcu prof_thread_func: sem_timedwait failed");
debug_assert(0); // wpcu prof_thread_func: sem_timedwait failed
uintptr_t pc = get_target_pc();
UNUSED2(pc);

View File

@ -17,7 +17,6 @@
#include <algorithm>
#include "win.h"
#include <ddraw.h>
#include <process.h> // _beginthreadex
#include <WindowsX.h> // message crackers
@ -28,7 +27,7 @@
#include "winit.h"
// for easy removal of DirectDraw dependency (used to query total video mem)
#define DDRAW
//#define DDRAW
#if MSC_VERSION
#pragma comment(lib, "user32.lib")
@ -37,6 +36,7 @@
// don't bother with dynamic linking -
// DirectX is present in all Windows versions since Win95.
#ifdef DDRAW
#include <ddraw.h>
# pragma comment(lib, "ddraw.lib")
#endif
@ -234,7 +234,7 @@ int SDL_SetVideoMode(int w, int h, int bpp, unsigned long flags)
ATOM class_atom = RegisterClass(&wc);
if(!class_atom)
{
debug_warn("SDL_SetVideoMode: RegisterClass failed");
debug_assert(0); // SDL_SetVideoMode: RegisterClass failed
return 0;
}
@ -319,8 +319,10 @@ fail:
static void video_shutdown()
{
if(fullscreen)
if(ChangeDisplaySettings(0, 0) != DISP_CHANGE_SUCCESSFUL)
debug_warn("ChangeDisplaySettings failed");
{
LONG status = ChangeDisplaySettings(0, 0);
debug_assert(status == DISP_CHANGE_SUCCESSFUL);
}
if(hGLRC != INVALID_HANDLE_VALUE)
{
@ -653,7 +655,7 @@ inline SDLKey vkmap(int vk)
if(!(0 <= vk && vk < 256))
{
debug_warn("vkmap: invalid vk");
debug_assert(0); // invalid vk
return SDLK_UNKNOWN;
}
return VK_SDLKMap[vk];

View File

@ -330,6 +330,8 @@ C++ classes. this way is more reliable/documented, but has several drawbacks:
*/
#ifndef LIB_DLL
EXTERN_C int mainCRTStartup();
static int CallStartupWithinTryBlock()
@ -366,3 +368,5 @@ EXTERN_C int wseh_EntryPoint()
#endif
return CallStartupWithinTryBlock();
}
#endif

View File

@ -127,8 +127,8 @@ static const char* GetDirectSoundDriverPath()
*(void**)&pDirectSoundEnumerateA = GetProcAddress(hDsoundDll, "DirectSoundEnumerateA");
if(pDirectSoundEnumerateA)
{
if(pDirectSoundEnumerateA(DirectSoundCallback, (void*)0) != DS_OK)
debug_warn("DirectSoundEnumerate failed");
HRESULT ret = pDirectSoundEnumerateA(DirectSoundCallback, (void*)0);
debug_assert(ret == DS_OK);
}
FreeLibrary(hDsoundDll);

View File

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

View File

@ -105,7 +105,7 @@ static void ShutdownLocks()
// only call after a Win32 function indicates failure.
LibError LibError_from_GLE(bool warn_if_failed)
{
LibError err;
LibError err = ERR::FAIL;
switch(GetLastError())
{
case ERROR_OUTOFMEMORY:
@ -123,8 +123,6 @@ LibError LibError_from_GLE(bool warn_if_failed)
case ERROR_PATH_NOT_FOUND:
err = ERR::TNODE_NOT_FOUND; break;
*/
default:
err = ERR::FAIL; break;
}
if(warn_if_failed)
@ -285,7 +283,7 @@ static void EnableMemoryTracking()
static void EnableLowFragmentationHeap()
{
#if WINVER >= 0x0501
HMODULE hKernel32Dll = LoadLibrary("kernel32.dll");
const HMODULE hKernel32Dll = GetModuleHandle("kernel32.dll");
BOOL (WINAPI* pHeapSetInformation)(HANDLE, HEAP_INFORMATION_CLASS, void*, size_t);
*(void**)&pHeapSetInformation = GetProcAddress(hKernel32Dll, "HeapSetInformation");
if(!pHeapSetInformation)
@ -293,8 +291,6 @@ static void EnableLowFragmentationHeap()
ULONG flags = 2; // enable LFH
pHeapSetInformation(GetProcessHeap(), HeapCompatibilityInformation, &flags, sizeof(flags));
FreeLibrary(hKernel32Dll);
#endif // #if WINVER >= 0x0501
}
@ -376,11 +372,10 @@ static bool isWow64;
static void ImportWow64Functions()
{
HMODULE hKernel32Dll = LoadLibrary("kernel32.dll");
const HMODULE hKernel32Dll = GetModuleHandle("kernel32.dll");
*(void**)&pIsWow64Process = GetProcAddress(hKernel32Dll, "IsWow64Process");
*(void**)&pWow64DisableWow64FsRedirection = GetProcAddress(hKernel32Dll, "Wow64DisableWow64FsRedirection");
*(void**)&pWow64RevertWow64FsRedirection = GetProcAddress(hKernel32Dll, "Wow64RevertWow64FsRedirection");
FreeLibrary(hKernel32Dll);
}
static void DetectWow64()
@ -424,6 +419,27 @@ void wutil_RevertWow64Redirection(void* wasRedirectionEnabled)
}
//-----------------------------------------------------------------------------
// module handle
#ifdef LIB_DLL
HMODULE wutil_LibModuleHandle;
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD reason, LPVOID reserved)
{
DisableThreadLibraryCalls(hInstance);
wutil_LibModuleHandle = hInstance;
return TRUE; // success (ignored unless reason == DLL_PROCESS_ATTACH)
}
#else
HMODULE wutil_LibModuleHandle = GetModuleHandle(0);
#endif
//-----------------------------------------------------------------------------
// find main window

View File

@ -60,6 +60,19 @@ extern int win_is_locked(uint idx);
win_unlock(ONCE_CS);\
}
struct WinScopedLock
{
WinScopedLock()
{
win_lock(WAIO_CS);
}
~WinScopedLock()
{
win_unlock(WAIO_CS);
}
};
//
// error codes
@ -133,6 +146,14 @@ extern void wutil_DisableWow64Redirection(void*& wasRedirectionEnabled);
extern void wutil_RevertWow64Redirection(void* wasRedirectionEnabled);
/**
* 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;
/**
* @return handle to the first window owned by the current process, or
* 0 if none exist (e.g. it hasn't yet created one).

View File

@ -24,19 +24,34 @@
#if OS_WIN
#include "lib/sysdep/win/whrt/whrt.h"
#endif
#if CONFIG_TIMER_ALLOW_RDTSC
#if OS_UNIX
# include <unistd.h>
#endif
#if ARCH_IA32 && CONFIG_TIMER_ALLOW_RDTSC
# include "lib/sysdep/ia32/ia32.h" // ia32_rdtsc
#endif
// rationale for wrapping gettimeofday and clock_gettime, instead of emulating
// them where not available: allows returning higher-resolution timer values
// than their us / ns interface, via double [seconds]. they're also not
// guaranteed to be monotonic.
#if HAVE_CLOCK_GETTIME
#if OS_UNIX || OS_WIN
# define HAVE_GETTIMEOFDAY 1
#else
# define HAVE_GETTIMEOFDAY 0
#endif
#if (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) || OS_WIN
# define HAVE_CLOCK_GETTIME 1
#else
# define HAVE_CLOCK_GETTIME 0
#endif
// rationale for wrapping gettimeofday and clock_gettime, instead of just
// emulating them where not available: allows returning higher-resolution
// timer values than their us / ns interface, via double [seconds].
// they're also not guaranteed to be monotonic.
#if HAVE_GETTIMEOFDAY
static struct timespec start;
#elif HAVE_GETTIMEOFDAY
#elif HAVE_CLOCK_GETTIME
static struct timeval start;
#endif
@ -107,141 +122,6 @@ double timer_res()
}
// calculate fps (call once per frame).
// algorithm: variable-gain IIR filter.
// less fluctuation, but rapid tracking.
// filter values are tuned for 100 FPS.
int fps;
float spf;
void calc_fps()
{
static double avg_fps = 60.0;
double cur_fps = avg_fps;
// get elapsed time [s] since last update
static double last_t;
const double t = get_time();
ONCE(last_t = t - 1.0/60.0); // first call: 60 FPS
const double dt = t - last_t;
// (in case timer resolution is low): count frames until
// timer value has changed "enough".
static double min_dt;
ONCE(min_dt = timer_res() * 4.0);
// chosen to reduce error but still yield rapid updates.
static uint num_frames = 1;
if(dt < min_dt)
{
num_frames++;
return;
}
// dt is big enough => we will update.
// calculate approximate current FPS (= 1 / elapsed time per frame).
last_t = t;
cur_fps = (1.0 / dt) * num_frames;
num_frames = 1; // reset for next time
// average and smooth cur_fps.
//
// filter design goals: steady output, but rapid signal tracking.
//
// implemented as a variable-gain IIR filter with knowledge of typical
// function characteristics. this is easier to stabilize than a PID
// scheme, since it is based on averaging actual function values,
// instead of trying to minimize output-vs-input error.
// there are some similarities, though: same_side ~= I, and
// bounced ~= D.
//
// check cur_fps function for several characteristics that
// help decide if it's actually changing or just jittering.
//
#define REL_ERR(correct, measured) (fabs((correct) - (measured)) / (correct))
#define SIGN_EQ(x0, x1, x2) ( ((x0) * (x1)) > 0.0 && ((x1) * (x2)) > 0.0 )
#define ONE_SIDE(x, x0, x1, x2) SIGN_EQ(x-x0, x-x1, x-x2)
// cur_fps history and changes over past few frames
static double h2, h1 = 30.0, h0 = 30.0;
h2 = h1; h1 = h0; h0 = cur_fps;
const double d21 = h1 - h2, d10 = h0 - h1;
const double e20 = REL_ERR(h2, h0), e10 = REL_ERR(h1, h0);
const double e0 = REL_ERR(avg_fps, h0);
// indicators that the function is jittering
const bool bounced = d21 * d10 < 0.0 && e20 < 0.05 && e10 > 0.10;
// /\ or \/
const bool jumped = e10 > 0.30;
// large change (have seen semi-legitimate changes of 25%)
const bool is_close = e0 < 0.02;
// cur_fps - avg_fps is "small"
// "same-side" check for rapid tracking of the function.
// if the past few samples have been consistently above/below the average,
// the function is moving up/down and we need to catch up.
static int same_side;
// consecutive times the last 3 samples have been on the same side.
if(!ONE_SIDE(avg_fps, h0, h1, h2)) // not all on same side:
same_side = 0; // reset counter
// (only increase if not too close to average,
// so that this isn't triggered by jitter alone)
if(!is_close)
same_side++;
//
// determine filter gain, based on above characteristics.
//
static double gain; // sensitivity to changes in cur_fps ([0,1])
double bias = 0.0; // (unlimited) exponential change to gain
// ignore (gain -> 0) large jumps.
if(jumped)
bias -= 4.0;
// don't let a "bounce" affect things too much.
else if(bounced)
bias -= 1.0;
// otherwise, function is normal here.
else
{
// function is changing, we need to track it rapidly.
// note: check close again so we aren't too loose if the function
// comes closer to the average again (meaning it probably
// wasn't really changing).
if(same_side >= 2 && !is_close)
bias += std::min(same_side, 4);
}
// bias = 0: no change. > 0: increase (n-th root). < 0: decrease (^n)
double e = (bias > 0)? 1.0 / bias : -bias;
if(e == 0.0) e = 1.0;
gain = pow(0.08, e);
// default: fairly insensitive to changes (~= 16 sample average)
// IIR filter
static double old = 30.0;
old = cur_fps*gain + old*(1.0-gain);
avg_fps = old;
spf = 1.0 / avg_fps;
// update fps counter if it differs "enough"
// currently, that means off by more than 5 FPS or 5%.
const double difference = fabs(avg_fps-fps);
const double threshold = fminf(5.f, 0.05f*fps);
if(difference > threshold)
fps = (int)(avg_fps + 0.99);
// C float -> int rounds down; we want to round up to
// hit vsync-locked framerates exactly.
}
//-----------------------------------------------------------------------------
// cumulative timer API, useful for profiling.
@ -304,17 +184,7 @@ void timer_display_client_totals()
clients = tc->next;
num_clients--;
// convert raw ticks into seconds, if necessary
double sum;
#if TIMER_USE_RAW_TICKS
# if CPU_IA32
sum = tc->sum / cpu_ClockFrequency();
# else
# error "port"
# endif
#else
sum = tc->sum;
#endif
const double sum = Timer::ToSeconds(tc->sum);
// determine scale factor for pretty display
double scale = 1e6;
@ -331,7 +201,7 @@ void timer_display_client_totals()
}
#if CONFIG_TIMER_ALLOW_RDTSC
#if ARCH_IA32 && CONFIG_TIMER_ALLOW_RDTSC
TimerRdtsc::unit TimerRdtsc::get_timestamp() const
{

View File

@ -15,26 +15,18 @@
#include <string>
#include "debug.h" // debug_printf
#include "lib/sysdep/cpu.h"
extern void timer_Init();
extern void timer_Shutdown();
LIB_API void timer_Init();
LIB_API void timer_Shutdown();
// high resolution (> 1 us) timestamp [s], starting at or near 0 s.
extern double get_time(void);
LIB_API double get_time(void);
// return resolution (expressed in [s]) of the time source underlying
// get_time.
extern double timer_res(void);
// calculate fps (call once per frame)
// several smooth filters (tuned for ~100 FPS)
// => less fluctuation, but rapid tracking
extern int fps; // for user display
extern float spf; // for time-since-last-frame use
extern void calc_fps(void);
LIB_API double timer_res(void);
//-----------------------------------------------------------------------------
@ -57,7 +49,7 @@ extern void calc_fps(void);
// note that overflow isn't an issue either way (63 bit cycle counts
// at 10 GHz cover intervals of 29 years).
#if CONFIG_TIMER_ALLOW_RDTSC
#if ARCH_IA32 && CONFIG_TIMER_ALLOW_RDTSC
// fast, IA-32 specific, not usable as wall-clock
// (see http://www.gamedev.net/reference/programming/features/timing)
@ -66,6 +58,10 @@ class TimerRdtsc
public:
typedef i64 unit;
unit get_timestamp() const;
static double ToSeconds(unit value)
{
return value / cpu_ClockFrequency();
}
};
#endif
@ -78,9 +74,13 @@ public:
{
return get_time();
}
static double ToSeconds(unit value)
{
return value;
}
};
#if CONFIG_TIMER_ALLOW_RDTSC
#if ARCH_IA32 && CONFIG_TIMER_ALLOW_RDTSC
typedef TimerRdtsc Timer;
#else
typedef TimerSafe Timer;
@ -122,14 +122,14 @@ struct TimerClient
// - always succeeds (there's no fixed limit);
// - free() is not needed nor possible.
// - description must remain valid until exit; a string literal is safest.
extern TimerClient* timer_add_client(TimerClient* tc, const char* description);
LIB_API TimerClient* timer_add_client(TimerClient* tc, const char* description);
// add <dt> to the client's total.
extern void timer_bill_client(TimerClient* tc, TimerUnit dt);
LIB_API void timer_bill_client(TimerClient* tc, TimerUnit dt);
// display all clients' totals; does not reset them.
// typically called at exit.
extern void timer_display_client_totals();
LIB_API void timer_display_client_totals();
//-----------------------------------------------------------------------------