Counter Strike : Global Offensive Source Code
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.

571 lines
11 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "pch_tier0.h"
  8. #include "tier0/platform.h"
  9. #include "tier0/memalloc.h"
  10. #include "tier0/dbg.h"
  11. #include "tier0/threadtools.h"
  12. #include <sys/time.h>
  13. #include <unistd.h>
  14. #include <signal.h>
  15. #ifdef OSX
  16. #include <mach-o/dyld.h>
  17. #include <sys/sysctl.h>
  18. #include <mach/mach.h>
  19. #include <mach/mach_time.h>
  20. #include <CoreServices/CoreServices.h>
  21. #endif
  22. static bool g_bBenchmarkMode = false;
  23. static double g_FakeBenchmarkTime = 0;
  24. static double g_FakeBenchmarkTimeInc = 1.0 / 66.0;
  25. bool Plat_IsInBenchmarkMode()
  26. {
  27. return g_bBenchmarkMode;
  28. }
  29. void Plat_SetBenchmarkMode( bool bBenchmark )
  30. {
  31. g_bBenchmarkMode = bBenchmark;
  32. }
  33. #ifdef OSX
  34. static uint64 start_time = 0;
  35. static mach_timebase_info_data_t sTimebaseInfo;
  36. static double conversion = 0.0;
  37. static double conversionMS = 0.0;
  38. static double conversionUS = 0.0;
  39. void InitTime()
  40. {
  41. start_time = mach_absolute_time();
  42. mach_timebase_info(&sTimebaseInfo);
  43. conversion = 1e-9 * (double) sTimebaseInfo.numer / (double) sTimebaseInfo.denom;
  44. conversionMS = 1e-6 * (double) sTimebaseInfo.numer / (double) sTimebaseInfo.denom;
  45. conversionUS = 1e-3 * (double) sTimebaseInfo.numer / (double) sTimebaseInfo.denom;
  46. }
  47. uint64 Plat_GetClockStart()
  48. {
  49. if ( !start_time )
  50. {
  51. InitTime();
  52. }
  53. return start_time;
  54. }
  55. double Plat_FloatTime()
  56. {
  57. if ( g_bBenchmarkMode )
  58. {
  59. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  60. return g_FakeBenchmarkTime;
  61. }
  62. if ( !start_time )
  63. {
  64. InitTime();
  65. }
  66. uint64 now = mach_absolute_time();
  67. return ( now - start_time ) * conversion;
  68. }
  69. uint32 Plat_MSTime()
  70. {
  71. if ( g_bBenchmarkMode )
  72. {
  73. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  74. return g_FakeBenchmarkTime;
  75. }
  76. if ( !start_time )
  77. {
  78. InitTime();
  79. }
  80. uint64 now = mach_absolute_time();
  81. return uint32( ( now - start_time ) * conversionMS );
  82. }
  83. uint64 Plat_USTime()
  84. {
  85. if ( g_bBenchmarkMode )
  86. {
  87. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  88. return g_FakeBenchmarkTime;
  89. }
  90. if ( !start_time )
  91. {
  92. InitTime();
  93. }
  94. uint64 now = mach_absolute_time();
  95. return uint64( ( now - start_time ) * conversionUS );
  96. }
  97. #else
  98. static int secbase = 0;
  99. void InitTime( struct timeval &tp )
  100. {
  101. secbase = tp.tv_sec;
  102. }
  103. uint64 Plat_GetClockStart()
  104. {
  105. if ( !secbase )
  106. {
  107. struct timeval tp;
  108. gettimeofday( &tp, NULL );
  109. InitTime( tp );
  110. }
  111. return secbase;
  112. }
  113. double Plat_FloatTime()
  114. {
  115. if ( g_bBenchmarkMode )
  116. {
  117. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  118. return g_FakeBenchmarkTime;
  119. }
  120. struct timeval tp;
  121. gettimeofday( &tp, NULL );
  122. if ( !secbase )
  123. {
  124. InitTime( tp );
  125. }
  126. return (( tp.tv_sec - secbase ) + tp.tv_usec / 1000000.0 );
  127. }
  128. uint32 Plat_MSTime()
  129. {
  130. if ( g_bBenchmarkMode )
  131. {
  132. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  133. return uint32( g_FakeBenchmarkTime * 1000.0 );
  134. }
  135. struct timeval tp;
  136. gettimeofday( &tp, NULL );
  137. if ( !secbase )
  138. {
  139. InitTime( tp );
  140. }
  141. return (( tp.tv_sec - secbase )*1000 + tp.tv_usec / 1000 );
  142. }
  143. uint64 Plat_USTime()
  144. {
  145. if ( g_bBenchmarkMode )
  146. {
  147. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  148. return uint32( g_FakeBenchmarkTime * 1e6 );
  149. }
  150. struct timeval tp;
  151. gettimeofday( &tp, NULL );
  152. if ( !secbase )
  153. {
  154. InitTime( tp );
  155. }
  156. return ( uint64( tp.tv_sec - secbase )*1000000ull + tp.tv_usec );
  157. }
  158. #endif
  159. // Wraps the thread-safe versions of asctime. buf must be at least 26 bytes
  160. char *Plat_asctime( const struct tm *tm, char *buf, size_t bufsize )
  161. {
  162. return asctime_r( tm, buf );
  163. }
  164. // Wraps the thread-safe versions of ctime. buf must be at least 26 bytes
  165. char *Plat_ctime( const time_t *timep, char *buf, size_t bufsize )
  166. {
  167. return ctime_r( timep, buf );
  168. }
  169. // Wraps the thread-safe versions of gmtime
  170. struct tm *Platform_gmtime( const time_t *timep, struct tm *result )
  171. {
  172. return gmtime_r( timep, result );
  173. }
  174. time_t Plat_timegm( struct tm *timeptr )
  175. {
  176. return timegm( timeptr );
  177. }
  178. // Wraps the thread-safe versions of localtime
  179. struct tm *Plat_localtime( const time_t *timep, struct tm *result )
  180. {
  181. return localtime_r( timep, result );
  182. }
  183. uint64 Plat_GetTime()
  184. {
  185. // We just provide a wrapper on this function so we can protect access to time() everywhere.
  186. time_t ltime;
  187. time( &ltime );
  188. return ltime;
  189. }
  190. bool vtune( bool resume )
  191. {
  192. return 0;
  193. }
  194. // -------------------------------------------------------------------------------------------------- //
  195. // Memory stuff.
  196. // -------------------------------------------------------------------------------------------------- //
  197. PLATFORM_INTERFACE void Plat_DefaultAllocErrorFn( unsigned long size )
  198. {
  199. }
  200. typedef void (*Plat_AllocErrorFn)( unsigned long size );
  201. Plat_AllocErrorFn g_AllocError = Plat_DefaultAllocErrorFn;
  202. PLATFORM_INTERFACE void* Plat_Alloc( unsigned long size )
  203. {
  204. void *pRet = g_pMemAlloc->Alloc( size );
  205. if ( pRet )
  206. {
  207. return pRet;
  208. }
  209. else
  210. {
  211. g_AllocError( size );
  212. return 0;
  213. }
  214. }
  215. PLATFORM_INTERFACE void* Plat_Realloc( void *ptr, unsigned long size )
  216. {
  217. void *pRet = g_pMemAlloc->Realloc( ptr, size );
  218. if ( pRet )
  219. {
  220. return pRet;
  221. }
  222. else
  223. {
  224. g_AllocError( size );
  225. return 0;
  226. }
  227. }
  228. PLATFORM_INTERFACE void Plat_Free( void *ptr )
  229. {
  230. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  231. g_pMemAlloc->Free( ptr );
  232. #else
  233. free( ptr );
  234. #endif
  235. }
  236. PLATFORM_INTERFACE void Plat_SetAllocErrorFn( Plat_AllocErrorFn fn )
  237. {
  238. g_AllocError = fn;
  239. }
  240. static char g_CmdLine[ 2048 ];
  241. PLATFORM_INTERFACE void Plat_SetCommandLine( const char *cmdLine )
  242. {
  243. strncpy( g_CmdLine, cmdLine, sizeof(g_CmdLine) );
  244. g_CmdLine[ sizeof(g_CmdLine) -1 ] = 0;
  245. }
  246. PLATFORM_INTERFACE void Plat_SetCommandLineArgs( char **argv, int argc )
  247. {
  248. g_CmdLine[0] = 0;
  249. for ( int i = 0; i < argc; i++ )
  250. {
  251. strncat( g_CmdLine, argv[i], sizeof(g_CmdLine) - strlen(g_CmdLine) );
  252. }
  253. g_CmdLine[ sizeof(g_CmdLine) -1 ] = 0;
  254. }
  255. PLATFORM_INTERFACE const tchar *Plat_GetCommandLine()
  256. {
  257. return g_CmdLine;
  258. }
  259. PLATFORM_INTERFACE bool Is64BitOS()
  260. {
  261. #if defined OSX
  262. return true;
  263. #elif defined LINUX
  264. FILE *pp = popen( "uname -m", "r" );
  265. if ( pp != NULL )
  266. {
  267. char rgchArchString[256];
  268. fgets( rgchArchString, sizeof( rgchArchString ), pp );
  269. pclose( pp );
  270. if ( !strncasecmp( rgchArchString, "x86_64", strlen( "x86_64" ) ) )
  271. return true;
  272. }
  273. #else
  274. Assert( !"implement Is64BitOS" );
  275. #endif
  276. return false;
  277. }
  278. bool Plat_IsInDebugSession()
  279. {
  280. #if defined(OSX)
  281. int mib[4];
  282. struct kinfo_proc info;
  283. size_t size;
  284. mib[0] = CTL_KERN;
  285. mib[1] = KERN_PROC;
  286. mib[2] = KERN_PROC_PID;
  287. mib[3] = getpid();
  288. size = sizeof(info);
  289. info.kp_proc.p_flag = 0;
  290. sysctl(mib,4,&info,&size,NULL,0);
  291. bool result = ((info.kp_proc.p_flag & P_TRACED) == P_TRACED);
  292. return result;
  293. #elif defined(LINUX)
  294. char s[256];
  295. snprintf(s, 256, "/proc/%d/cmdline", getppid());
  296. FILE * fp = fopen(s, "r");
  297. if (fp != NULL)
  298. {
  299. fread(s, 256, 1, fp);
  300. fclose(fp);
  301. return (0 == strncmp(s, "gdb", 3));
  302. }
  303. return false;
  304. #endif
  305. }
  306. void Plat_ExitProcess( int nCode )
  307. {
  308. fflush( stdout );
  309. if ( nCode != 0 )
  310. {
  311. // Right now we want a non-zero exit code to cause a hard crash so
  312. // that we trigger minidump.
  313. int* x = NULL;
  314. *x = 1;
  315. }
  316. _exit( nCode );
  317. }
  318. static int s_nWatchDogTimerTimeScale = 0;
  319. static bool s_bInittedWD = false;
  320. static void WatchdogCoreDumpSigHandler( int nSignal )
  321. {
  322. signal( SIGALRM, SIG_IGN );
  323. printf( "**** WARNING: Watchdog timer exceeded, aborting!\n" );
  324. abort();
  325. }
  326. static void InitWatchDogTimer( void )
  327. {
  328. if( !strstr( g_CmdLine, "-nowatchdog" ) )
  329. {
  330. #ifdef _DEBUG
  331. s_nWatchDogTimerTimeScale = 10; // debug is slow
  332. #else
  333. s_nWatchDogTimerTimeScale = 1;
  334. #endif
  335. if( !strstr( g_CmdLine, "-nonabortingwatchdog" ) )
  336. {
  337. signal( SIGALRM, WatchdogCoreDumpSigHandler );
  338. }
  339. }
  340. }
  341. // watchdog timer support
  342. void BeginWatchdogTimer( int nSecs )
  343. {
  344. if (! s_bInittedWD )
  345. {
  346. s_bInittedWD = true;
  347. InitWatchDogTimer();
  348. }
  349. nSecs *= s_nWatchDogTimerTimeScale;
  350. nSecs = MIN( nSecs, 5 * 60 ); // no more than 5 minutes no matter what
  351. if ( nSecs )
  352. alarm( nSecs );
  353. }
  354. void EndWatchdogTimer( void )
  355. {
  356. alarm( 0 );
  357. }
  358. static CThreadMutex g_LocalTimeMutex;
  359. void Plat_GetLocalTime( struct tm *pNow )
  360. {
  361. // We just provide a wrapper on this function so we can protect access to time() everywhere.
  362. time_t ltime;
  363. time( &ltime );
  364. Plat_ConvertToLocalTime( ltime, pNow );
  365. }
  366. void Plat_ConvertToLocalTime( uint64 nTime, struct tm *pNow )
  367. {
  368. // Since localtime() returns a global, we need to protect against multiple threads stomping it.
  369. g_LocalTimeMutex.Lock();
  370. time_t ltime = (time_t)nTime;
  371. tm *pTime = localtime( &ltime );
  372. if ( pTime )
  373. *pNow = *pTime;
  374. else
  375. memset( pNow, 0, sizeof( *pNow ) );
  376. g_LocalTimeMutex.Unlock();
  377. }
  378. void Plat_GetTimeString( struct tm *pTime, char *pOut, int nMaxBytes )
  379. {
  380. g_LocalTimeMutex.Lock();
  381. char *pStr = asctime( pTime );
  382. strncpy( pOut, pStr, nMaxBytes );
  383. pOut[nMaxBytes-1] = 0;
  384. g_LocalTimeMutex.Unlock();
  385. }
  386. // timezone
  387. int32 Plat_timezone( void )
  388. {
  389. return timezone;
  390. }
  391. // daylight savings
  392. int32 Plat_daylight( void )
  393. {
  394. return daylight;
  395. }
  396. void Platform_gmtime( uint64 nTime, struct tm *pTime )
  397. {
  398. time_t tmtTime = nTime;
  399. struct tm * tmp = gmtime( &tmtTime );
  400. * pTime = * tmp;
  401. }
  402. #ifdef LINUX
  403. /*
  404. From http://man7.org/linux/man-pages/man5/proc.5.html:
  405. /proc/[pid]/statm
  406. Provides information about memory usage, measured in pages.
  407. The columns are:
  408. size (1) total program size
  409. (same as VmSize in /proc/[pid]/status)
  410. resident (2) resident set size
  411. (same as VmRSS in /proc/[pid]/status)
  412. share (3) shared pages (i.e., backed by a file)
  413. text (4) text (code)
  414. lib (5) library (unused in Linux 2.6)
  415. data (6) data + stack
  416. dt (7) dirty pages (unused in Linux 2.6)
  417. */
  418. // This returns the resident memory size (RES column in 'top') in bytes.
  419. size_t ApproximateProcessMemoryUsage( void )
  420. {
  421. size_t nRet = 0;
  422. FILE *pFile = fopen( "/proc/self/statm", "r" );
  423. if ( pFile )
  424. {
  425. size_t nSize, nResident, nShare, nText, nLib_Unused, nDataPlusStack, nDt_Unused;
  426. if ( fscanf( pFile, "%zu %zu %zu %zu %zu %zu %zu", &nSize, &nResident, &nShare, &nText, &nLib_Unused, &nDataPlusStack, &nDt_Unused ) >= 2 )
  427. {
  428. nRet = 4096 * nResident;
  429. }
  430. fclose( pFile );
  431. }
  432. return nRet;
  433. }
  434. #else
  435. size_t ApproximateProcessMemoryUsage( void )
  436. {
  437. return 0;
  438. }
  439. #endif
  440. char const * Plat_GetEnv(char const *pEnvVarName)
  441. {
  442. return getenv(pEnvVarName);
  443. }
  444. PLATFORM_INTERFACE bool Plat_GetExecutablePath( char *pBuff, size_t nBuff )
  445. {
  446. #if defined OSX
  447. uint32_t _nBuff = nBuff;
  448. bool bSuccess = _NSGetExecutablePath(pBuff, &_nBuff) == 0;
  449. pBuff[nBuff-1] = '\0';
  450. return bSuccess;
  451. #elif defined LINUX
  452. ssize_t nRead = readlink("/proc/self/exe", pBuff, nBuff-1 );
  453. if ( nRead != -1 )
  454. {
  455. pBuff[ nRead ] = 0;
  456. return true;
  457. }
  458. pBuff[0] = 0;
  459. return false;
  460. #else
  461. AssertMsg( false, "Implement Plat_GetExecutablePath" );
  462. return false;
  463. #endif
  464. }