//========= 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 #include #ifdef OSX #include #include #include #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( <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; 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