Team Fortress 2 Source Code as on 22/4/2020
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.

478 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "pch_tier0.h"
  8. #include <time.h>
  9. #if defined(_WIN32) && !defined(_X360)
  10. #include <errno.h>
  11. #endif
  12. #include <assert.h>
  13. #include "tier0/platform.h"
  14. #include "tier0/minidump.h"
  15. #ifdef _X360
  16. #include "xbox/xbox_console.h"
  17. #include "xbox/xbox_win32stubs.h"
  18. #else
  19. #include "tier0/vcrmode.h"
  20. #endif
  21. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  22. #include "tier0/memalloc.h"
  23. // memdbgon must be the last include file in a .cpp file!!!
  24. #include "tier0/memdbgon.h"
  25. #endif
  26. //our global error callback function. Note that this is not initialized, but static space guarantees this is NULL at app start.
  27. //If you initialize, it will set to zero again when the CPP runs its static initializers, which could stomp the value if another
  28. //CPP sets this value while initializing its static space
  29. static ExitProcessWithErrorCBFn g_pfnExitProcessWithErrorCB; //= NULL
  30. #ifndef _X360
  31. extern VCRMode_t g_VCRMode;
  32. #endif
  33. static LARGE_INTEGER g_PerformanceFrequency;
  34. static double g_PerformanceCounterToS;
  35. static double g_PerformanceCounterToMS;
  36. static double g_PerformanceCounterToUS;
  37. static LARGE_INTEGER g_ClockStart;
  38. static bool s_bTimeInitted;
  39. // Benchmark mode uses this heavy-handed method
  40. static bool g_bBenchmarkMode = false;
  41. static double g_FakeBenchmarkTime = 0;
  42. static double g_FakeBenchmarkTimeInc = 1.0 / 66.0;
  43. static void InitTime()
  44. {
  45. if( !s_bTimeInitted )
  46. {
  47. s_bTimeInitted = true;
  48. QueryPerformanceFrequency(&g_PerformanceFrequency);
  49. g_PerformanceCounterToS = 1.0 / g_PerformanceFrequency.QuadPart;
  50. g_PerformanceCounterToMS = 1e3 / g_PerformanceFrequency.QuadPart;
  51. g_PerformanceCounterToUS = 1e6 / g_PerformanceFrequency.QuadPart;
  52. QueryPerformanceCounter(&g_ClockStart);
  53. }
  54. }
  55. bool Plat_IsInBenchmarkMode()
  56. {
  57. return g_bBenchmarkMode;
  58. }
  59. void Plat_SetBenchmarkMode( bool bBenchmark )
  60. {
  61. g_bBenchmarkMode = bBenchmark;
  62. }
  63. double Plat_FloatTime()
  64. {
  65. if (! s_bTimeInitted )
  66. InitTime();
  67. if ( g_bBenchmarkMode )
  68. {
  69. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  70. return g_FakeBenchmarkTime;
  71. }
  72. LARGE_INTEGER CurrentTime;
  73. QueryPerformanceCounter( &CurrentTime );
  74. double fRawSeconds = (double)( CurrentTime.QuadPart - g_ClockStart.QuadPart ) * g_PerformanceCounterToS;
  75. return fRawSeconds;
  76. }
  77. uint32 Plat_MSTime()
  78. {
  79. if (! s_bTimeInitted )
  80. InitTime();
  81. if ( g_bBenchmarkMode )
  82. {
  83. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  84. return (uint32)(g_FakeBenchmarkTime * 1000.0);
  85. }
  86. LARGE_INTEGER CurrentTime;
  87. QueryPerformanceCounter( &CurrentTime );
  88. return (uint32) ( ( CurrentTime.QuadPart - g_ClockStart.QuadPart ) * g_PerformanceCounterToMS );
  89. }
  90. uint64 Plat_USTime()
  91. {
  92. if (! s_bTimeInitted )
  93. InitTime();
  94. if ( g_bBenchmarkMode )
  95. {
  96. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  97. return (uint64)(g_FakeBenchmarkTime * 1e6);
  98. }
  99. LARGE_INTEGER CurrentTime;
  100. QueryPerformanceCounter( &CurrentTime );
  101. return (uint64) ( ( CurrentTime.QuadPart - g_ClockStart.QuadPart ) * g_PerformanceCounterToUS );
  102. }
  103. void GetCurrentDate( int *pDay, int *pMonth, int *pYear )
  104. {
  105. struct tm *pNewTime;
  106. time_t long_time;
  107. time( &long_time ); /* Get time as long integer. */
  108. pNewTime = localtime( &long_time ); /* Convert to local time. */
  109. *pDay = pNewTime->tm_mday;
  110. *pMonth = pNewTime->tm_mon + 1;
  111. *pYear = pNewTime->tm_year + 1900;
  112. }
  113. // Wraps the thread-safe versions of ctime. buf must be at least 26 bytes
  114. char *Plat_ctime( const time_t *timep, char *buf, size_t bufsize )
  115. {
  116. if ( EINVAL == ctime_s( buf, bufsize, timep ) )
  117. return NULL;
  118. else
  119. return buf;
  120. }
  121. void Plat_GetModuleFilename( char *pOut, int nMaxBytes )
  122. {
  123. #ifdef PLATFORM_WINDOWS_PC
  124. SetLastError( ERROR_SUCCESS ); // clear the error code
  125. GetModuleFileName( NULL, pOut, nMaxBytes );
  126. if ( GetLastError() != ERROR_SUCCESS )
  127. Error( "Plat_GetModuleFilename: The buffer given is too small (%d bytes).", nMaxBytes );
  128. #elif PLATFORM_X360
  129. pOut[0] = 0x00; // return null string on Xbox 360
  130. #else
  131. // We shouldn't need this on POSIX.
  132. Assert( false );
  133. pOut[0] = 0x00; // Null the returned string in release builds
  134. #endif
  135. }
  136. void Plat_ExitProcess( int nCode )
  137. {
  138. #if defined( _WIN32 ) && !defined( _X360 )
  139. // We don't want global destructors in our process OR in any DLL to get executed.
  140. // _exit() avoids calling global destructors in our module, but not in other DLLs.
  141. const char *pchCmdLineA = Plat_GetCommandLineA();
  142. if ( nCode || ( strstr( pchCmdLineA, "gc.exe" ) && strstr( pchCmdLineA, "gc.dll" ) && strstr( pchCmdLineA, "-gc" ) ) )
  143. {
  144. int *x = NULL; *x = 1; // cause a hard crash, GC is not allowed to exit voluntarily from gc.dll
  145. }
  146. TerminateProcess( GetCurrentProcess(), nCode );
  147. #elif defined(_PS3)
  148. // We do not use this path to exit on PS3 (naturally), rather we want a clear crash:
  149. int *x = NULL; *x = 1;
  150. #else
  151. _exit( nCode );
  152. #endif
  153. }
  154. void Plat_ExitProcessWithError( int nCode, bool bGenerateMinidump )
  155. {
  156. //try to delegate out if they have registered a callback
  157. if( g_pfnExitProcessWithErrorCB )
  158. {
  159. if( g_pfnExitProcessWithErrorCB( nCode ) )
  160. return;
  161. }
  162. //handle default behavior
  163. if( bGenerateMinidump )
  164. {
  165. //don't generate mini dumps in the debugger
  166. if( !Plat_IsInDebugSession() )
  167. {
  168. WriteMiniDump();
  169. }
  170. }
  171. //and exit our process
  172. Plat_ExitProcess( nCode );
  173. }
  174. void Plat_SetExitProcessWithErrorCB( ExitProcessWithErrorCBFn pfnCB )
  175. {
  176. g_pfnExitProcessWithErrorCB = pfnCB;
  177. }
  178. // Wraps the thread-safe versions of gmtime
  179. struct tm *Plat_gmtime( const time_t *timep, struct tm *result )
  180. {
  181. if ( EINVAL == gmtime_s( result, timep ) )
  182. return NULL;
  183. else
  184. return result;
  185. }
  186. time_t Plat_timegm( struct tm *timeptr )
  187. {
  188. return _mkgmtime( timeptr );
  189. }
  190. // Wraps the thread-safe versions of localtime
  191. struct tm *Plat_localtime( const time_t *timep, struct tm *result )
  192. {
  193. if ( EINVAL == localtime_s( result, timep ) )
  194. return NULL;
  195. else
  196. return result;
  197. }
  198. bool vtune( bool resume )
  199. {
  200. #ifndef _X360
  201. static bool bInitialized = false;
  202. static void (__cdecl *VTResume)(void) = NULL;
  203. static void (__cdecl *VTPause) (void) = NULL;
  204. // Grab the Pause and Resume function pointers from the VTune DLL the first time through:
  205. if( !bInitialized )
  206. {
  207. bInitialized = true;
  208. HINSTANCE pVTuneDLL = LoadLibrary( "vtuneapi.dll" );
  209. if( pVTuneDLL )
  210. {
  211. VTResume = (void(__cdecl *)())GetProcAddress( pVTuneDLL, "VTResume" );
  212. VTPause = (void(__cdecl *)())GetProcAddress( pVTuneDLL, "VTPause" );
  213. }
  214. }
  215. // Call the appropriate function, as indicated by the argument:
  216. if( resume && VTResume )
  217. {
  218. VTResume();
  219. return true;
  220. }
  221. else if( !resume && VTPause )
  222. {
  223. VTPause();
  224. return true;
  225. }
  226. #endif
  227. return false;
  228. }
  229. bool Plat_IsInDebugSession()
  230. {
  231. #if defined( _WIN32 ) && !defined( _X360 )
  232. return (IsDebuggerPresent() != 0);
  233. #elif defined( _WIN32 ) && defined( _X360 )
  234. return (XBX_IsDebuggerPresent() != 0);
  235. #elif defined( LINUX )
  236. #error This code is implemented in platform_posix.cpp
  237. #else
  238. return false;
  239. #endif
  240. }
  241. void Plat_DebugString( const char * psz )
  242. {
  243. #if defined( _WIN32 ) && !defined( _X360 )
  244. ::OutputDebugStringA( psz );
  245. #elif defined( _WIN32 ) && defined( _X360 )
  246. XBX_OutputDebugString( psz );
  247. #endif
  248. }
  249. const tchar *Plat_GetCommandLine()
  250. {
  251. #ifdef TCHAR_IS_WCHAR
  252. return GetCommandLineW();
  253. #else
  254. return GetCommandLine();
  255. #endif
  256. }
  257. bool GetMemoryInformation( MemoryInformation *pOutMemoryInfo )
  258. {
  259. if ( !pOutMemoryInfo )
  260. return false;
  261. MEMORYSTATUSEX memStat;
  262. ZeroMemory( &memStat, sizeof( MEMORYSTATUSEX ) );
  263. memStat.dwLength = sizeof( MEMORYSTATUSEX );
  264. if ( !GlobalMemoryStatusEx( &memStat ) )
  265. return false;
  266. const uint cOneMb = 1024 * 1024;
  267. switch ( pOutMemoryInfo->m_nStructVersion )
  268. {
  269. case 0:
  270. ( *pOutMemoryInfo ).m_nPhysicalRamMbTotal = memStat.ullTotalPhys / cOneMb;
  271. ( *pOutMemoryInfo ).m_nPhysicalRamMbAvailable = memStat.ullAvailPhys / cOneMb;
  272. ( *pOutMemoryInfo ).m_nVirtualRamMbTotal = memStat.ullTotalVirtual / cOneMb;
  273. ( *pOutMemoryInfo ).m_nVirtualRamMbAvailable = memStat.ullAvailVirtual / cOneMb;
  274. break;
  275. default:
  276. return false;
  277. };
  278. return true;
  279. }
  280. const char *Plat_GetCommandLineA()
  281. {
  282. return GetCommandLineA();
  283. }
  284. //--------------------------------------------------------------------------------------------------
  285. // Watchdog timer
  286. //--------------------------------------------------------------------------------------------------
  287. void Plat_BeginWatchdogTimer( int nSecs )
  288. {
  289. }
  290. void Plat_EndWatchdogTimer( void )
  291. {
  292. }
  293. int Plat_GetWatchdogTime( void )
  294. {
  295. return 0;
  296. }
  297. void Plat_SetWatchdogHandlerFunction( Plat_WatchDogHandlerFunction_t function )
  298. {
  299. }
  300. bool Is64BitOS()
  301. {
  302. typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
  303. static LPFN_ISWOW64PROCESS pfnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( GetModuleHandle("kernel32"), "IsWow64Process" );
  304. static BOOL bIs64bit = FALSE;
  305. static bool bInitialized = false;
  306. if ( bInitialized )
  307. return bIs64bit == (BOOL)TRUE;
  308. else
  309. {
  310. bInitialized = true;
  311. return pfnIsWow64Process && pfnIsWow64Process(GetCurrentProcess(), &bIs64bit) && bIs64bit;
  312. }
  313. }
  314. // -------------------------------------------------------------------------------------------------- //
  315. // Memory stuff.
  316. //
  317. // DEPRECATED. Still here to support binary back compatability of tier0.dll
  318. //
  319. // -------------------------------------------------------------------------------------------------- //
  320. #ifndef _X360
  321. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  322. typedef void (*Plat_AllocErrorFn)( unsigned long size );
  323. void Plat_DefaultAllocErrorFn( unsigned long size )
  324. {
  325. }
  326. Plat_AllocErrorFn g_AllocError = Plat_DefaultAllocErrorFn;
  327. #endif
  328. #ifndef _X360
  329. CRITICAL_SECTION g_AllocCS;
  330. class CAllocCSInit
  331. {
  332. public:
  333. CAllocCSInit()
  334. {
  335. InitializeCriticalSection( &g_AllocCS );
  336. }
  337. } g_AllocCSInit;
  338. #endif
  339. #ifndef _X360
  340. PLATFORM_INTERFACE void* Plat_Alloc( unsigned long size )
  341. {
  342. EnterCriticalSection( &g_AllocCS );
  343. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  344. void *pRet = g_pMemAlloc->Alloc( size );
  345. #else
  346. void *pRet = malloc( size );
  347. #endif
  348. LeaveCriticalSection( &g_AllocCS );
  349. if ( pRet )
  350. {
  351. return pRet;
  352. }
  353. else
  354. {
  355. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  356. g_AllocError( size );
  357. #endif
  358. return 0;
  359. }
  360. }
  361. #endif
  362. #ifndef _X360
  363. PLATFORM_INTERFACE void* Plat_Realloc( void *ptr, unsigned long size )
  364. {
  365. EnterCriticalSection( &g_AllocCS );
  366. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  367. void *pRet = g_pMemAlloc->Realloc( ptr, size );
  368. #else
  369. void *pRet = realloc( ptr, size );
  370. #endif
  371. LeaveCriticalSection( &g_AllocCS );
  372. if ( pRet )
  373. {
  374. return pRet;
  375. }
  376. else
  377. {
  378. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  379. g_AllocError( size );
  380. #endif
  381. return 0;
  382. }
  383. }
  384. #endif
  385. #ifndef _X360
  386. PLATFORM_INTERFACE void Plat_Free( void *ptr )
  387. {
  388. EnterCriticalSection( &g_AllocCS );
  389. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  390. g_pMemAlloc->Free( ptr );
  391. #else
  392. free( ptr );
  393. #endif
  394. LeaveCriticalSection( &g_AllocCS );
  395. }
  396. #endif
  397. #ifndef _X360
  398. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  399. PLATFORM_INTERFACE void Plat_SetAllocErrorFn( Plat_AllocErrorFn fn )
  400. {
  401. g_AllocError = fn;
  402. }
  403. #endif
  404. #endif
  405. #endif