1
This commit is contained in:
478
tier0/platform.cpp
Normal file
478
tier0/platform.cpp
Normal file
@ -0,0 +1,478 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "pch_tier0.h"
|
||||
#include <time.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_X360)
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include "tier0/platform.h"
|
||||
#include "tier0/minidump.h"
|
||||
#ifdef _X360
|
||||
#include "xbox/xbox_console.h"
|
||||
#include "xbox/xbox_win32stubs.h"
|
||||
#else
|
||||
#include "tier0/vcrmode.h"
|
||||
#endif
|
||||
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
||||
#include "tier0/memalloc.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
#endif
|
||||
|
||||
//our global error callback function. Note that this is not initialized, but static space guarantees this is NULL at app start.
|
||||
//If you initialize, it will set to zero again when the CPP runs its static initializers, which could stomp the value if another
|
||||
//CPP sets this value while initializing its static space
|
||||
static ExitProcessWithErrorCBFn g_pfnExitProcessWithErrorCB; //= NULL
|
||||
|
||||
#ifndef _X360
|
||||
extern VCRMode_t g_VCRMode;
|
||||
#endif
|
||||
static LARGE_INTEGER g_PerformanceFrequency;
|
||||
static double g_PerformanceCounterToS;
|
||||
static double g_PerformanceCounterToMS;
|
||||
static double g_PerformanceCounterToUS;
|
||||
static LARGE_INTEGER g_ClockStart;
|
||||
static bool s_bTimeInitted;
|
||||
|
||||
// Benchmark mode uses this heavy-handed method
|
||||
static bool g_bBenchmarkMode = false;
|
||||
static double g_FakeBenchmarkTime = 0;
|
||||
static double g_FakeBenchmarkTimeInc = 1.0 / 66.0;
|
||||
|
||||
static void InitTime()
|
||||
{
|
||||
if( !s_bTimeInitted )
|
||||
{
|
||||
s_bTimeInitted = true;
|
||||
QueryPerformanceFrequency(&g_PerformanceFrequency);
|
||||
g_PerformanceCounterToS = 1.0 / g_PerformanceFrequency.QuadPart;
|
||||
g_PerformanceCounterToMS = 1e3 / g_PerformanceFrequency.QuadPart;
|
||||
g_PerformanceCounterToUS = 1e6 / g_PerformanceFrequency.QuadPart;
|
||||
QueryPerformanceCounter(&g_ClockStart);
|
||||
}
|
||||
}
|
||||
|
||||
bool Plat_IsInBenchmarkMode()
|
||||
{
|
||||
return g_bBenchmarkMode;
|
||||
}
|
||||
|
||||
void Plat_SetBenchmarkMode( bool bBenchmark )
|
||||
{
|
||||
g_bBenchmarkMode = bBenchmark;
|
||||
}
|
||||
|
||||
double Plat_FloatTime()
|
||||
{
|
||||
if (! s_bTimeInitted )
|
||||
InitTime();
|
||||
if ( g_bBenchmarkMode )
|
||||
{
|
||||
g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
|
||||
return g_FakeBenchmarkTime;
|
||||
}
|
||||
|
||||
LARGE_INTEGER CurrentTime;
|
||||
|
||||
QueryPerformanceCounter( &CurrentTime );
|
||||
|
||||
double fRawSeconds = (double)( CurrentTime.QuadPart - g_ClockStart.QuadPart ) * g_PerformanceCounterToS;
|
||||
|
||||
return fRawSeconds;
|
||||
}
|
||||
|
||||
uint32 Plat_MSTime()
|
||||
{
|
||||
if (! s_bTimeInitted )
|
||||
InitTime();
|
||||
if ( g_bBenchmarkMode )
|
||||
{
|
||||
g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
|
||||
return (uint32)(g_FakeBenchmarkTime * 1000.0);
|
||||
}
|
||||
|
||||
LARGE_INTEGER CurrentTime;
|
||||
|
||||
QueryPerformanceCounter( &CurrentTime );
|
||||
|
||||
return (uint32) ( ( CurrentTime.QuadPart - g_ClockStart.QuadPart ) * g_PerformanceCounterToMS );
|
||||
}
|
||||
|
||||
uint64 Plat_USTime()
|
||||
{
|
||||
if (! s_bTimeInitted )
|
||||
InitTime();
|
||||
if ( g_bBenchmarkMode )
|
||||
{
|
||||
g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
|
||||
return (uint64)(g_FakeBenchmarkTime * 1e6);
|
||||
}
|
||||
|
||||
LARGE_INTEGER CurrentTime;
|
||||
|
||||
QueryPerformanceCounter( &CurrentTime );
|
||||
|
||||
return (uint64) ( ( CurrentTime.QuadPart - g_ClockStart.QuadPart ) * g_PerformanceCounterToUS );
|
||||
}
|
||||
|
||||
void GetCurrentDate( int *pDay, int *pMonth, int *pYear )
|
||||
{
|
||||
struct tm *pNewTime;
|
||||
time_t long_time;
|
||||
|
||||
time( &long_time ); /* Get time as long integer. */
|
||||
pNewTime = localtime( &long_time ); /* Convert to local time. */
|
||||
|
||||
*pDay = pNewTime->tm_mday;
|
||||
*pMonth = pNewTime->tm_mon + 1;
|
||||
*pYear = pNewTime->tm_year + 1900;
|
||||
}
|
||||
|
||||
|
||||
// Wraps the thread-safe versions of ctime. buf must be at least 26 bytes
|
||||
char *Plat_ctime( const time_t *timep, char *buf, size_t bufsize )
|
||||
{
|
||||
if ( EINVAL == ctime_s( buf, bufsize, timep ) )
|
||||
return NULL;
|
||||
else
|
||||
return buf;
|
||||
}
|
||||
|
||||
void Plat_GetModuleFilename( char *pOut, int nMaxBytes )
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS_PC
|
||||
SetLastError( ERROR_SUCCESS ); // clear the error code
|
||||
GetModuleFileName( NULL, pOut, nMaxBytes );
|
||||
if ( GetLastError() != ERROR_SUCCESS )
|
||||
Error( "Plat_GetModuleFilename: The buffer given is too small (%d bytes).", nMaxBytes );
|
||||
#elif PLATFORM_X360
|
||||
pOut[0] = 0x00; // return null string on Xbox 360
|
||||
#else
|
||||
// We shouldn't need this on POSIX.
|
||||
Assert( false );
|
||||
pOut[0] = 0x00; // Null the returned string in release builds
|
||||
#endif
|
||||
}
|
||||
|
||||
void Plat_ExitProcess( int nCode )
|
||||
{
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
// We don't want global destructors in our process OR in any DLL to get executed.
|
||||
// _exit() avoids calling global destructors in our module, but not in other DLLs.
|
||||
const char *pchCmdLineA = Plat_GetCommandLineA();
|
||||
if ( nCode || ( strstr( pchCmdLineA, "gc.exe" ) && strstr( pchCmdLineA, "gc.dll" ) && strstr( pchCmdLineA, "-gc" ) ) )
|
||||
{
|
||||
int *x = NULL; *x = 1; // cause a hard crash, GC is not allowed to exit voluntarily from gc.dll
|
||||
}
|
||||
TerminateProcess( GetCurrentProcess(), nCode );
|
||||
#elif defined(_PS3)
|
||||
// We do not use this path to exit on PS3 (naturally), rather we want a clear crash:
|
||||
int *x = NULL; *x = 1;
|
||||
#else
|
||||
_exit( nCode );
|
||||
#endif
|
||||
}
|
||||
|
||||
void Plat_ExitProcessWithError( int nCode, bool bGenerateMinidump )
|
||||
{
|
||||
//try to delegate out if they have registered a callback
|
||||
if( g_pfnExitProcessWithErrorCB )
|
||||
{
|
||||
if( g_pfnExitProcessWithErrorCB( nCode ) )
|
||||
return;
|
||||
}
|
||||
|
||||
//handle default behavior
|
||||
if( bGenerateMinidump )
|
||||
{
|
||||
//don't generate mini dumps in the debugger
|
||||
if( !Plat_IsInDebugSession() )
|
||||
{
|
||||
WriteMiniDump();
|
||||
}
|
||||
}
|
||||
|
||||
//and exit our process
|
||||
Plat_ExitProcess( nCode );
|
||||
}
|
||||
|
||||
void Plat_SetExitProcessWithErrorCB( ExitProcessWithErrorCBFn pfnCB )
|
||||
{
|
||||
g_pfnExitProcessWithErrorCB = pfnCB;
|
||||
}
|
||||
|
||||
// Wraps the thread-safe versions of gmtime
|
||||
struct tm *Plat_gmtime( const time_t *timep, struct tm *result )
|
||||
{
|
||||
if ( EINVAL == gmtime_s( result, timep ) )
|
||||
return NULL;
|
||||
else
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
time_t Plat_timegm( struct tm *timeptr )
|
||||
{
|
||||
return _mkgmtime( timeptr );
|
||||
}
|
||||
|
||||
|
||||
// Wraps the thread-safe versions of localtime
|
||||
struct tm *Plat_localtime( const time_t *timep, struct tm *result )
|
||||
{
|
||||
if ( EINVAL == localtime_s( result, timep ) )
|
||||
return NULL;
|
||||
else
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool vtune( bool resume )
|
||||
{
|
||||
#ifndef _X360
|
||||
static bool bInitialized = false;
|
||||
static void (__cdecl *VTResume)(void) = NULL;
|
||||
static void (__cdecl *VTPause) (void) = NULL;
|
||||
|
||||
// Grab the Pause and Resume function pointers from the VTune DLL the first time through:
|
||||
if( !bInitialized )
|
||||
{
|
||||
bInitialized = true;
|
||||
|
||||
HINSTANCE pVTuneDLL = LoadLibrary( "vtuneapi.dll" );
|
||||
|
||||
if( pVTuneDLL )
|
||||
{
|
||||
VTResume = (void(__cdecl *)())GetProcAddress( pVTuneDLL, "VTResume" );
|
||||
VTPause = (void(__cdecl *)())GetProcAddress( pVTuneDLL, "VTPause" );
|
||||
}
|
||||
}
|
||||
|
||||
// Call the appropriate function, as indicated by the argument:
|
||||
if( resume && VTResume )
|
||||
{
|
||||
VTResume();
|
||||
return true;
|
||||
|
||||
}
|
||||
else if( !resume && VTPause )
|
||||
{
|
||||
VTPause();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Plat_IsInDebugSession()
|
||||
{
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
return (IsDebuggerPresent() != 0);
|
||||
#elif defined( _WIN32 ) && defined( _X360 )
|
||||
return (XBX_IsDebuggerPresent() != 0);
|
||||
#elif defined( LINUX )
|
||||
#error This code is implemented in platform_posix.cpp
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Plat_DebugString( const char * psz )
|
||||
{
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
::OutputDebugStringA( psz );
|
||||
#elif defined( _WIN32 ) && defined( _X360 )
|
||||
XBX_OutputDebugString( psz );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
const tchar *Plat_GetCommandLine()
|
||||
{
|
||||
#ifdef TCHAR_IS_WCHAR
|
||||
return GetCommandLineW();
|
||||
#else
|
||||
return GetCommandLine();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GetMemoryInformation( MemoryInformation *pOutMemoryInfo )
|
||||
{
|
||||
if ( !pOutMemoryInfo )
|
||||
return false;
|
||||
|
||||
MEMORYSTATUSEX memStat;
|
||||
ZeroMemory( &memStat, sizeof( MEMORYSTATUSEX ) );
|
||||
memStat.dwLength = sizeof( MEMORYSTATUSEX );
|
||||
|
||||
if ( !GlobalMemoryStatusEx( &memStat ) )
|
||||
return false;
|
||||
|
||||
const uint cOneMb = 1024 * 1024;
|
||||
|
||||
switch ( pOutMemoryInfo->m_nStructVersion )
|
||||
{
|
||||
case 0:
|
||||
( *pOutMemoryInfo ).m_nPhysicalRamMbTotal = memStat.ullTotalPhys / cOneMb;
|
||||
( *pOutMemoryInfo ).m_nPhysicalRamMbAvailable = memStat.ullAvailPhys / cOneMb;
|
||||
|
||||
( *pOutMemoryInfo ).m_nVirtualRamMbTotal = memStat.ullTotalVirtual / cOneMb;
|
||||
( *pOutMemoryInfo ).m_nVirtualRamMbAvailable = memStat.ullAvailVirtual / cOneMb;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const char *Plat_GetCommandLineA()
|
||||
{
|
||||
return GetCommandLineA();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Watchdog timer
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void Plat_BeginWatchdogTimer( int nSecs )
|
||||
{
|
||||
}
|
||||
void Plat_EndWatchdogTimer( void )
|
||||
{
|
||||
}
|
||||
int Plat_GetWatchdogTime( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void Plat_SetWatchdogHandlerFunction( Plat_WatchDogHandlerFunction_t function )
|
||||
{
|
||||
}
|
||||
|
||||
bool Is64BitOS()
|
||||
{
|
||||
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
|
||||
static LPFN_ISWOW64PROCESS pfnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( GetModuleHandle("kernel32"), "IsWow64Process" );
|
||||
|
||||
static BOOL bIs64bit = FALSE;
|
||||
static bool bInitialized = false;
|
||||
if ( bInitialized )
|
||||
return bIs64bit == (BOOL)TRUE;
|
||||
else
|
||||
{
|
||||
bInitialized = true;
|
||||
return pfnIsWow64Process && pfnIsWow64Process(GetCurrentProcess(), &bIs64bit) && bIs64bit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------------- //
|
||||
// Memory stuff.
|
||||
//
|
||||
// DEPRECATED. Still here to support binary back compatability of tier0.dll
|
||||
//
|
||||
// -------------------------------------------------------------------------------------------------- //
|
||||
#ifndef _X360
|
||||
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
||||
|
||||
typedef void (*Plat_AllocErrorFn)( unsigned long size );
|
||||
|
||||
void Plat_DefaultAllocErrorFn( unsigned long size )
|
||||
{
|
||||
}
|
||||
|
||||
Plat_AllocErrorFn g_AllocError = Plat_DefaultAllocErrorFn;
|
||||
#endif
|
||||
|
||||
#ifndef _X360
|
||||
CRITICAL_SECTION g_AllocCS;
|
||||
class CAllocCSInit
|
||||
{
|
||||
public:
|
||||
CAllocCSInit()
|
||||
{
|
||||
InitializeCriticalSection( &g_AllocCS );
|
||||
}
|
||||
} g_AllocCSInit;
|
||||
#endif
|
||||
|
||||
#ifndef _X360
|
||||
PLATFORM_INTERFACE void* Plat_Alloc( unsigned long size )
|
||||
{
|
||||
EnterCriticalSection( &g_AllocCS );
|
||||
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
||||
void *pRet = g_pMemAlloc->Alloc( size );
|
||||
#else
|
||||
void *pRet = malloc( size );
|
||||
#endif
|
||||
LeaveCriticalSection( &g_AllocCS );
|
||||
if ( pRet )
|
||||
{
|
||||
return pRet;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
||||
g_AllocError( size );
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _X360
|
||||
PLATFORM_INTERFACE void* Plat_Realloc( void *ptr, unsigned long size )
|
||||
{
|
||||
EnterCriticalSection( &g_AllocCS );
|
||||
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
||||
void *pRet = g_pMemAlloc->Realloc( ptr, size );
|
||||
#else
|
||||
void *pRet = realloc( ptr, size );
|
||||
#endif
|
||||
LeaveCriticalSection( &g_AllocCS );
|
||||
if ( pRet )
|
||||
{
|
||||
return pRet;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
||||
g_AllocError( size );
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _X360
|
||||
PLATFORM_INTERFACE void Plat_Free( void *ptr )
|
||||
{
|
||||
EnterCriticalSection( &g_AllocCS );
|
||||
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
||||
g_pMemAlloc->Free( ptr );
|
||||
#else
|
||||
free( ptr );
|
||||
#endif
|
||||
LeaveCriticalSection( &g_AllocCS );
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _X360
|
||||
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
||||
PLATFORM_INTERFACE void Plat_SetAllocErrorFn( Plat_AllocErrorFn fn )
|
||||
{
|
||||
g_AllocError = fn;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user