You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
559 lines
12 KiB
559 lines
12 KiB
//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//===========================================================================// |
|
|
|
#include "pch_tier0.h" |
|
#include <time.h> |
|
|
|
#if defined(_WIN32) && !defined(_X360) |
|
#define WINDOWS_LEAN_AND_MEAN |
|
#define _WIN32_WINNT 0x0403 |
|
#include <windows.h> |
|
#endif |
|
#include <errno.h> |
|
#include <assert.h> |
|
#include "tier0/platform.h" |
|
#if defined( _X360 ) |
|
#include "xbox/xbox_console.h" |
|
#endif |
|
#include "tier0/threadtools.h" |
|
|
|
#include "tier0/memalloc.h" |
|
|
|
#if defined( _PS3 ) |
|
#include <cell/fios/fios_common.h> |
|
#include <cell/fios/fios_memory.h> |
|
#include <cell/fios/fios_configuration.h> |
|
#include <sys/process.h> |
|
|
|
#if !defined(_CERT) |
|
#include "sn/LibSN.h" |
|
#endif |
|
|
|
/* |
|
#include <sys/types.h> |
|
#include <sys/process.h> |
|
#include <sys/prx.h> |
|
|
|
#include <sysutil/sysutil_syscache.h> |
|
|
|
#include <cell/sysmodule.h> |
|
*/ |
|
#include <cell/fios/fios_time.h> |
|
#endif // _PS3 |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
#ifdef _WIN32 |
|
static LARGE_INTEGER g_PerformanceFrequency; |
|
static LARGE_INTEGER g_MSPerformanceFrequency; |
|
static LARGE_INTEGER g_ClockStart; |
|
static bool s_bTimeInitted; |
|
#endif |
|
|
|
// Benchmark mode uses this heavy-handed method |
|
static bool g_bBenchmarkMode = false; |
|
#ifdef _WIN32 |
|
static double g_FakeBenchmarkTime = 0; |
|
static double g_FakeBenchmarkTimeInc = 1.0 / 66.0; |
|
#endif |
|
|
|
static CThreadFastMutex g_LocalTimeMutex; |
|
|
|
|
|
#ifdef _WIN32 |
|
static void InitTime() |
|
{ |
|
if( !s_bTimeInitted ) |
|
{ |
|
s_bTimeInitted = true; |
|
QueryPerformanceFrequency(&g_PerformanceFrequency); |
|
g_MSPerformanceFrequency.QuadPart = g_PerformanceFrequency.QuadPart / 1000; |
|
QueryPerformanceCounter(&g_ClockStart); |
|
} |
|
} |
|
#endif |
|
|
|
bool Plat_IsInBenchmarkMode() |
|
{ |
|
return g_bBenchmarkMode; |
|
} |
|
|
|
void Plat_SetBenchmarkMode( bool bBenchmark ) |
|
{ |
|
g_bBenchmarkMode = bBenchmark; |
|
} |
|
|
|
#ifdef _PS3 |
|
cell::fios::abstime_t g_fiosLaunchTime = 0; |
|
#endif |
|
|
|
|
|
double Plat_FloatTime() |
|
{ |
|
#ifdef _WIN32 |
|
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 ) / (double)(g_PerformanceFrequency.QuadPart); |
|
|
|
return fRawSeconds; |
|
#else |
|
return cell::fios::FIOSAbstimeToMicroseconds( cell::fios::FIOSGetCurrentTime() - g_fiosLaunchTime ) * 1e-6; |
|
#endif |
|
} |
|
|
|
|
|
uint32 Plat_MSTime() |
|
{ |
|
#ifdef _WIN32 |
|
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_MSPerformanceFrequency.QuadPart); |
|
#elif defined(_PS3) |
|
return (uint32) cell::fios::FIOSAbstimeToMilliseconds( cell::fios::FIOSGetCurrentTime() - g_fiosLaunchTime ); |
|
#else |
|
#error |
|
#endif |
|
} |
|
|
|
uint64 Timer_GetTimeUS() |
|
{ |
|
#ifdef _PS3 |
|
return cell::fios::FIOSAbstimeToMicroseconds( cell::fios::FIOSGetCurrentTime() - g_fiosLaunchTime ); |
|
#else |
|
return uint64( Plat_FloatTime() * 1000000 ); |
|
#endif |
|
} |
|
|
|
uint64 Plat_GetClockStart() |
|
{ |
|
#if defined( _WIN32 ) |
|
if ( !s_bTimeInitted ) |
|
InitTime(); |
|
|
|
return g_ClockStart.QuadPart; |
|
#elif defined( _PS3 ) |
|
return g_fiosLaunchTime; |
|
#else |
|
return 0; |
|
#endif |
|
} |
|
|
|
void Plat_GetLocalTime( struct tm *pNow ) |
|
{ |
|
// We just provide a wrapper on this function so we can protect access to time() everywhere. |
|
time_t ltime; |
|
time( <ime ); |
|
|
|
Plat_ConvertToLocalTime( ltime, pNow ); |
|
} |
|
|
|
void Plat_ConvertToLocalTime( uint64 nTime, struct tm *pNow ) |
|
{ |
|
// Since localtime() returns a global, we need to protect against multiple threads stomping it. |
|
g_LocalTimeMutex.Lock(); |
|
|
|
time_t ltime = (time_t)nTime; |
|
tm *pTime = localtime( <ime ); |
|
if ( pTime ) |
|
*pNow = *pTime; |
|
else |
|
memset( pNow, 0, sizeof( *pNow ) ); |
|
|
|
g_LocalTimeMutex.Unlock(); |
|
} |
|
|
|
void Plat_GetTimeString( struct tm *pTime, char *pOut, int nMaxBytes ) |
|
{ |
|
g_LocalTimeMutex.Lock(); |
|
|
|
char *pStr = asctime( pTime ); |
|
strncpy( pOut, pStr, nMaxBytes ); |
|
pOut[nMaxBytes-1] = 0; |
|
|
|
g_LocalTimeMutex.Unlock(); |
|
} |
|
|
|
|
|
void Plat_gmtime( uint64 nTime, struct tm *pTime ) |
|
{ |
|
time_t tmtTime = nTime; |
|
#ifdef _PS3 |
|
struct tm * tmp = gmtime( &tmtTime ); |
|
* pTime = * tmp; |
|
#else |
|
gmtime_s( pTime, &tmtTime ); |
|
#endif |
|
} |
|
|
|
time_t Plat_timegm( struct tm *timeptr ) |
|
{ |
|
#ifndef _GAMECONSOLE |
|
return _mkgmtime( timeptr ); |
|
#else |
|
int *pnCrashHereBecauseConsolesDontSupportMkGmTime = 0; |
|
*pnCrashHereBecauseConsolesDontSupportMkGmTime = 0; |
|
return 0; |
|
#endif |
|
} |
|
|
|
void Plat_GetModuleFilename( char *pOut, int nMaxBytes ) |
|
{ |
|
#ifdef PLATFORM_WINDOWS_PC |
|
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. |
|
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 GetCurrentDate( int *pDay, int *pMonth, int *pYear ) |
|
{ |
|
struct tm long_time; |
|
Plat_GetLocalTime( &long_time ); |
|
|
|
*pDay = long_time.tm_mday; |
|
*pMonth = long_time.tm_mon + 1; |
|
*pYear = long_time.tm_year + 1900; |
|
} |
|
|
|
// Wraps the thread-safe versions of asctime. buf must be at least 26 bytes |
|
char *Plat_asctime( const struct tm *tm, char *buf, size_t bufsize ) |
|
{ |
|
#ifdef _PS3 |
|
snprintf( buf, bufsize, "%s", asctime(tm) ); |
|
return buf; |
|
#else |
|
if ( EINVAL == asctime_s( buf, bufsize, tm ) ) |
|
return NULL; |
|
else |
|
return buf; |
|
#endif |
|
} |
|
|
|
|
|
// 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 ) |
|
{ |
|
#ifdef _PS3 |
|
snprintf( buf, bufsize, "%s", ctime( timep ) ); |
|
return buf; |
|
#else |
|
if ( EINVAL == ctime_s( buf, bufsize, timep ) ) |
|
return NULL; |
|
else |
|
return buf; |
|
#endif |
|
} |
|
|
|
|
|
// Wraps the thread-safe versions of gmtime |
|
struct tm *Plat_gmtime( const time_t *timep, struct tm *result ) |
|
{ |
|
#ifdef _PS3 |
|
*result = *gmtime( timep ); |
|
return result; |
|
#else |
|
if ( EINVAL == gmtime_s( result, timep ) ) |
|
return NULL; |
|
else |
|
return result; |
|
#endif |
|
} |
|
|
|
|
|
// Wraps the thread-safe versions of localtime |
|
struct tm *Plat_localtime( const time_t *timep, struct tm *result ) |
|
{ |
|
#ifdef _PS3 |
|
*result = *localtime( timep ); |
|
return result; |
|
#else |
|
if ( EINVAL == localtime_s( result, timep ) ) |
|
return NULL; |
|
else |
|
return result; |
|
#endif |
|
} |
|
|
|
bool vtune( bool resume ) |
|
{ |
|
#if IS_WINDOWS_PC |
|
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( _X360 ) |
|
return (XBX_IsDebuggerPresent() != 0); |
|
#elif defined( _WIN32 ) |
|
return (IsDebuggerPresent() != 0); |
|
#elif defined( _PS3 ) && !defined(_CERT) |
|
return snIsDebuggerPresent(); |
|
#else |
|
return false; |
|
#endif |
|
} |
|
|
|
void Plat_DebugString( const char * psz ) |
|
{ |
|
#ifdef _CERT |
|
return; // do nothing! |
|
#endif |
|
|
|
#if defined( _X360 ) |
|
XBX_OutputDebugString( psz ); |
|
#elif defined( _WIN32 ) |
|
::OutputDebugStringA( psz ); |
|
#elif defined(_PS3) |
|
printf("%s",psz); |
|
#else |
|
// do nothing? |
|
#endif |
|
} |
|
|
|
|
|
#if defined( PLATFORM_WINDOWS_PC ) |
|
void Plat_MessageBox( const char *pTitle, const char *pMessage ) |
|
{ |
|
MessageBox( NULL, pMessage, pTitle, MB_OK ); |
|
} |
|
#endif |
|
|
|
PlatOSVersion_t Plat_GetOSVersion() |
|
{ |
|
#ifdef PLATFORM_WINDOWS_PC |
|
OSVERSIONINFO info; |
|
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); |
|
if ( GetVersionEx( &info ) ) |
|
return (PlatOSVersion_t)info.dwMajorVersion; |
|
return PLAT_OS_VERSION_UNKNOWN; |
|
#elif defined( PLATFORM_X360 ) |
|
return PLAT_OS_VERSION_XBOX360; |
|
#else |
|
return PLAT_OS_VERSION_UNKNOWN; |
|
#endif |
|
} |
|
|
|
#if defined( PLATFORM_PS3 ) |
|
//copied from platform_posix.cpp |
|
static char g_CmdLine[ 2048 ] = ""; |
|
PLATFORM_INTERFACE void Plat_SetCommandLine( const char *cmdLine ) |
|
{ |
|
strncpy( g_CmdLine, cmdLine, sizeof(g_CmdLine) ); |
|
g_CmdLine[ sizeof(g_CmdLine) -1 ] = 0; |
|
} |
|
#endif |
|
|
|
PLATFORM_INTERFACE const tchar *Plat_GetCommandLine() |
|
{ |
|
#if defined( _PS3 ) |
|
#pragma message("Plat_GetCommandLine() not implemented on PS3") // **** |
|
return g_CmdLine; |
|
#elif defined( TCHAR_IS_WCHAR ) |
|
return GetCommandLineW(); |
|
#else |
|
return GetCommandLine(); |
|
#endif |
|
} |
|
|
|
PLATFORM_INTERFACE const char *Plat_GetCommandLineA() |
|
{ |
|
#if defined( _PS3 ) |
|
#pragma message("Plat_GetCommandLineA() not implemented on PS3") // **** |
|
return g_CmdLine; |
|
#else |
|
return GetCommandLineA(); |
|
#endif |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Dynamically load a function |
|
//----------------------------------------------------------------------------- |
|
#ifdef PLATFORM_WINDOWS |
|
|
|
void *Plat_GetProcAddress( const char *pszModule, const char *pszName ) |
|
{ |
|
HMODULE hModule = ::LoadLibrary( pszModule ); |
|
return ( hModule ) ? ::GetProcAddress( hModule, pszName ) : NULL; |
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------- // |
|
// 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 |
|
|
|
#if !defined( _X360 ) && !defined( _PS3 ) |
|
|
|
|
|
CRITICAL_SECTION g_AllocCS; |
|
class CAllocCSInit |
|
{ |
|
public: |
|
CAllocCSInit() |
|
{ |
|
InitializeCriticalSection( &g_AllocCS ); |
|
} |
|
} g_AllocCSInit; |
|
|
|
|
|
PLATFORM_INTERFACE void* Plat_Alloc( unsigned long size ) |
|
{ |
|
EnterCriticalSection( &g_AllocCS ); |
|
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE) |
|
void *pRet = MemAlloc_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; |
|
} |
|
} |
|
|
|
|
|
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; |
|
} |
|
} |
|
|
|
|
|
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 ); |
|
} |
|
|
|
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE) |
|
PLATFORM_INTERFACE void Plat_SetAllocErrorFn( Plat_AllocErrorFn fn ) |
|
{ |
|
g_AllocError = fn; |
|
} |
|
#endif |
|
|
|
#endif |
|
|
|
|
|
#endif |