forked from 0ad/0ad
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:
parent
03543147b7
commit
2e5d9452aa
@ -332,7 +332,7 @@ public:
|
||||
head = (head + 1) % n;
|
||||
}
|
||||
else
|
||||
debug_warn("underflow");
|
||||
debug_assert(0); // underflow
|
||||
}
|
||||
|
||||
class iterator
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ public:
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
boost::shared_ptr<Impl> impl;
|
||||
shared_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
#endif // #ifndef INCLUDED_HEADERLESS
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
216
source/lib/frequency_filter.cpp
Normal file
216
source/lib/frequency_filter.cpp
Normal 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));
|
||||
}
|
21
source/lib/frequency_filter.h
Normal file
21
source/lib/frequency_filter.h
Normal 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
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
12
source/lib/lib_api.h
Normal 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
|
@ -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);\
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
#ifndef INCLUDED_LOCKFREE
|
||||
#define INCLUDED_LOCKFREE
|
||||
|
||||
#include "posix/posix_types.h" // uintptr_t
|
||||
#include "lib/sysdep/cpu.h" // cpu_CAS
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -2,7 +2,7 @@
|
||||
* =========================================================================
|
||||
* File : hpet.cpp
|
||||
* Project : 0 A.D.
|
||||
* Description : Timer implementation using timeGetTime
|
||||
* Description : Timer implementation using High Precision Event Timer
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* =========================================================================
|
||||
* File : hpet.h
|
||||
* Project : 0 A.D.
|
||||
* Description : Timer implementation using timeGetTime
|
||||
* Description : Timer implementation using High Precision Event Timer
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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 );
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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).
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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();
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user