source-engine/external/vpc/tier0/platform_posix.cpp

427 lines
7.8 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "pch_tier0.h"
#include "tier0/platform.h"
#include "tier0/memalloc.h"
#include "tier0/dbg.h"
#include "tier0/threadtools.h"
#include <sys/time.h>
#include <unistd.h>
#ifdef OSX
#include <sys/sysctl.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#endif
static bool g_bBenchmarkMode = false;
static double g_FakeBenchmarkTime = 0;
static double g_FakeBenchmarkTimeInc = 1.0 / 66.0;
bool Plat_IsInBenchmarkMode()
{
return g_bBenchmarkMode;
}
void Plat_SetBenchmarkMode( bool bBenchmark )
{
g_bBenchmarkMode = bBenchmark;
}
#ifdef OSX
static uint64 start_time = 0;
static mach_timebase_info_data_t sTimebaseInfo;
static double conversion = 0.0;
void InitTime()
{
start_time = mach_absolute_time();
mach_timebase_info(&sTimebaseInfo);
conversion = 1e-9 * (double) sTimebaseInfo.numer / (double) sTimebaseInfo.denom;
}
uint64 Plat_GetClockStart()
{
if ( !start_time )
{
InitTime();
}
return start_time * conversion;
}
double Plat_FloatTime()
{
if ( g_bBenchmarkMode )
{
g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
return g_FakeBenchmarkTime;
}
if ( !start_time )
{
InitTime();
}
uint64 now = mach_absolute_time();
return ( now - start_time ) * conversion;
}
#else
static int secbase = 0;
void InitTime( struct timeval &tp )
{
secbase = tp.tv_sec;
}
uint64 Plat_GetClockStart()
{
if ( !secbase )
{
struct timeval tp;
gettimeofday( &tp, NULL );
InitTime( tp );
}
return secbase;
}
double Plat_FloatTime()
{
if ( g_bBenchmarkMode )
{
g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
return g_FakeBenchmarkTime;
}
struct timeval tp;
gettimeofday( &tp, NULL );
if ( !secbase )
{
InitTime( tp );
return ( tp.tv_usec / 1000000.0 );
}
return (( tp.tv_sec - secbase ) + tp.tv_usec / 1000000.0 );
}
#endif
uint32 Plat_MSTime()
{
if ( g_bBenchmarkMode )
{
g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
return (unsigned long)(g_FakeBenchmarkTime * 1000.0);
}
struct timeval tp;
static int secbase = 0;
gettimeofday( &tp, NULL );
if ( !secbase )
{
secbase = tp.tv_sec;
return ( tp.tv_usec / 1000.0 );
}
return (unsigned long)(( tp.tv_sec - secbase )*1000.0 + tp.tv_usec / 1000.0 );
}
// 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 )
{
return asctime_r( tm, buf );
}
// 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 )
{
return ctime_r( timep, buf );
}
// Wraps the thread-safe versions of gmtime
struct tm *Plat_gmtime( const time_t *timep, struct tm *result )
{
return gmtime_r( timep, result );
}
time_t Plat_timegm( struct tm *timeptr )
{
return timegm( timeptr );
}
// Wraps the thread-safe versions of localtime
struct tm *Plat_localtime( const time_t *timep, struct tm *result )
{
return localtime_r( timep, result );
}
bool vtune( bool resume )
{
}
// -------------------------------------------------------------------------------------------------- //
// Memory stuff.
// -------------------------------------------------------------------------------------------------- //
PLATFORM_INTERFACE void Plat_DefaultAllocErrorFn( unsigned long size )
{
}
typedef void (*Plat_AllocErrorFn)( unsigned long size );
Plat_AllocErrorFn g_AllocError = Plat_DefaultAllocErrorFn;
PLATFORM_INTERFACE void* Plat_Alloc( unsigned long size )
{
void *pRet = g_pMemAlloc->Alloc( size );
if ( pRet )
{
return pRet;
}
else
{
g_AllocError( size );
return 0;
}
}
PLATFORM_INTERFACE void* Plat_Realloc( void *ptr, unsigned long size )
{
void *pRet = g_pMemAlloc->Realloc( ptr, size );
if ( pRet )
{
return pRet;
}
else
{
g_AllocError( size );
return 0;
}
}
PLATFORM_INTERFACE void Plat_Free( void *ptr )
{
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
g_pMemAlloc->Free( ptr );
#else
free( ptr );
#endif
}
PLATFORM_INTERFACE void Plat_SetAllocErrorFn( Plat_AllocErrorFn fn )
{
g_AllocError = fn;
}
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;
}
PLATFORM_INTERFACE void Plat_SetCommandLineArgs( char **argv, int argc )
{
g_CmdLine[0] = 0;
for ( int i = 0; i < argc; i++ )
{
strncat( g_CmdLine, argv[i], sizeof(g_CmdLine) - strlen(g_CmdLine) );
}
g_CmdLine[ sizeof(g_CmdLine) -1 ] = 0;
}
PLATFORM_INTERFACE const tchar *Plat_GetCommandLine()
{
return g_CmdLine;
}
PLATFORM_INTERFACE bool Is64BitOS()
{
#if defined OSX
return true;
#elif defined LINUX
FILE *pp = popen( "uname -m", "r" );
if ( pp != NULL )
{
char rgchArchString[256];
fgets( rgchArchString, sizeof( rgchArchString ), pp );
pclose( pp );
if ( !strncasecmp( rgchArchString, "x86_64", strlen( "x86_64" ) ) )
return true;
}
#else
Assert( !"implement Is64BitOS" );
#endif
return false;
}
bool Plat_IsInDebugSession()
{
#if defined(OSX)
int mib[4];
struct kinfo_proc info;
size_t size;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
size = sizeof(info);
info.kp_proc.p_flag = 0;
sysctl(mib,4,&info,&size,NULL,0);
bool result = ((info.kp_proc.p_flag & P_TRACED) == P_TRACED);
return result;
#elif defined(LINUX)
char s[256];
snprintf(s, 256, "/proc/%d/cmdline", getppid());
FILE * fp = fopen(s, "r");
if (fp != NULL)
{
fread(s, 256, 1, fp);
fclose(fp);
return (0 == strncmp(s, "gdb", 3));
}
return false;
#endif
}
void Plat_ExitProcess( int nCode )
{
_exit( nCode );
}
static int s_nWatchDogTimerTimeScale = 0;
static bool s_bInittedWD = false;
static void InitWatchDogTimer( void )
{
if( !strstr( g_CmdLine, "-nowatchdog" ) )
{
#ifdef _DEBUG
s_nWatchDogTimerTimeScale = 10; // debug is slow
#else
s_nWatchDogTimerTimeScale = 1;
#endif
}
}
// watchdog timer support
void BeginWatchdogTimer( int nSecs )
{
if (! s_bInittedWD )
{
s_bInittedWD = true;
InitWatchDogTimer();
}
nSecs *= s_nWatchDogTimerTimeScale;
nSecs = MIN( nSecs, 5 * 60 ); // no more than 5 minutes no matter what
if ( nSecs )
alarm( nSecs );
}
void EndWatchdogTimer( void )
{
alarm( 0 );
}
static CThreadMutex g_LocalTimeMutex;
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( &ltime );
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( &ltime );
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;
struct tm * tmp = gmtime( &tmtTime );
* pTime = * tmp;
}
#ifdef LINUX
size_t ApproximateProcessMemoryUsage( void )
{
int nRet = 0;
FILE *pFile = fopen( "/proc/self/statm", "r" );
if ( pFile )
{
int nSize, nTotalProgramSize, nResident, nResidentSetSize, nShare, nSharedPagesTotal, nDummy0;
if ( fscanf( pFile, "%d %d %d %d %d %d %d", &nSize, &nTotalProgramSize, &nResident, &nResidentSetSize, &nShare, &nSharedPagesTotal, &nDummy0 ) )
{
nRet = 4096 * nSize;
}
fclose( pFile );
}
return nRet;
}
#else
size_t ApproximateProcessMemoryUsage( void )
{
return 0;
}
#endif