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.

558 lines
12 KiB

  1. //===== Copyright 1996-2005, 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. #define WINDOWS_LEAN_AND_MEAN
  11. #define _WIN32_WINNT 0x0403
  12. #include <windows.h>
  13. #endif
  14. #include <errno.h>
  15. #include <assert.h>
  16. #include "tier0/platform.h"
  17. #if defined( _X360 )
  18. #include "xbox/xbox_console.h"
  19. #endif
  20. #include "tier0/threadtools.h"
  21. #include "tier0/memalloc.h"
  22. #if defined( _PS3 )
  23. #include <cell/fios/fios_common.h>
  24. #include <cell/fios/fios_memory.h>
  25. #include <cell/fios/fios_configuration.h>
  26. #include <sys/process.h>
  27. #if !defined(_CERT)
  28. #include "sn/LibSN.h"
  29. #endif
  30. /*
  31. #include <sys/types.h>
  32. #include <sys/process.h>
  33. #include <sys/prx.h>
  34. #include <sysutil/sysutil_syscache.h>
  35. #include <cell/sysmodule.h>
  36. */
  37. #include <cell/fios/fios_time.h>
  38. #endif // _PS3
  39. // memdbgon must be the last include file in a .cpp file!!!
  40. #include "tier0/memdbgon.h"
  41. #ifdef _WIN32
  42. static LARGE_INTEGER g_PerformanceFrequency;
  43. static LARGE_INTEGER g_MSPerformanceFrequency;
  44. static LARGE_INTEGER g_ClockStart;
  45. static bool s_bTimeInitted;
  46. #endif
  47. // Benchmark mode uses this heavy-handed method
  48. static bool g_bBenchmarkMode = false;
  49. #ifdef _WIN32
  50. static double g_FakeBenchmarkTime = 0;
  51. static double g_FakeBenchmarkTimeInc = 1.0 / 66.0;
  52. #endif
  53. static CThreadFastMutex g_LocalTimeMutex;
  54. #ifdef _WIN32
  55. static void InitTime()
  56. {
  57. if( !s_bTimeInitted )
  58. {
  59. s_bTimeInitted = true;
  60. QueryPerformanceFrequency(&g_PerformanceFrequency);
  61. g_MSPerformanceFrequency.QuadPart = g_PerformanceFrequency.QuadPart / 1000;
  62. QueryPerformanceCounter(&g_ClockStart);
  63. }
  64. }
  65. #endif
  66. bool Plat_IsInBenchmarkMode()
  67. {
  68. return g_bBenchmarkMode;
  69. }
  70. void Plat_SetBenchmarkMode( bool bBenchmark )
  71. {
  72. g_bBenchmarkMode = bBenchmark;
  73. }
  74. #ifdef _PS3
  75. cell::fios::abstime_t g_fiosLaunchTime = 0;
  76. #endif
  77. double Plat_FloatTime()
  78. {
  79. #ifdef _WIN32
  80. if (! s_bTimeInitted )
  81. InitTime();
  82. if ( g_bBenchmarkMode )
  83. {
  84. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  85. return g_FakeBenchmarkTime;
  86. }
  87. LARGE_INTEGER CurrentTime;
  88. QueryPerformanceCounter( &CurrentTime );
  89. double fRawSeconds = (double)( CurrentTime.QuadPart - g_ClockStart.QuadPart ) / (double)(g_PerformanceFrequency.QuadPart);
  90. return fRawSeconds;
  91. #else
  92. return cell::fios::FIOSAbstimeToMicroseconds( cell::fios::FIOSGetCurrentTime() - g_fiosLaunchTime ) * 1e-6;
  93. #endif
  94. }
  95. uint32 Plat_MSTime()
  96. {
  97. #ifdef _WIN32
  98. if (! s_bTimeInitted )
  99. InitTime();
  100. if ( g_bBenchmarkMode )
  101. {
  102. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  103. return (uint32)(g_FakeBenchmarkTime * 1000.0);
  104. }
  105. LARGE_INTEGER CurrentTime;
  106. QueryPerformanceCounter( &CurrentTime );
  107. return (uint32) ( ( CurrentTime.QuadPart - g_ClockStart.QuadPart ) / g_MSPerformanceFrequency.QuadPart);
  108. #elif defined(_PS3)
  109. return (uint32) cell::fios::FIOSAbstimeToMilliseconds( cell::fios::FIOSGetCurrentTime() - g_fiosLaunchTime );
  110. #else
  111. #error
  112. #endif
  113. }
  114. uint64 Timer_GetTimeUS()
  115. {
  116. #ifdef _PS3
  117. return cell::fios::FIOSAbstimeToMicroseconds( cell::fios::FIOSGetCurrentTime() - g_fiosLaunchTime );
  118. #else
  119. return uint64( Plat_FloatTime() * 1000000 );
  120. #endif
  121. }
  122. uint64 Plat_GetClockStart()
  123. {
  124. #if defined( _WIN32 )
  125. if ( !s_bTimeInitted )
  126. InitTime();
  127. return g_ClockStart.QuadPart;
  128. #elif defined( _PS3 )
  129. return g_fiosLaunchTime;
  130. #else
  131. return 0;
  132. #endif
  133. }
  134. void Plat_GetLocalTime( struct tm *pNow )
  135. {
  136. // We just provide a wrapper on this function so we can protect access to time() everywhere.
  137. time_t ltime;
  138. time( &ltime );
  139. Plat_ConvertToLocalTime( ltime, pNow );
  140. }
  141. void Plat_ConvertToLocalTime( uint64 nTime, struct tm *pNow )
  142. {
  143. // Since localtime() returns a global, we need to protect against multiple threads stomping it.
  144. g_LocalTimeMutex.Lock();
  145. time_t ltime = (time_t)nTime;
  146. tm *pTime = localtime( &ltime );
  147. if ( pTime )
  148. *pNow = *pTime;
  149. else
  150. memset( pNow, 0, sizeof( *pNow ) );
  151. g_LocalTimeMutex.Unlock();
  152. }
  153. void Plat_GetTimeString( struct tm *pTime, char *pOut, int nMaxBytes )
  154. {
  155. g_LocalTimeMutex.Lock();
  156. char *pStr = asctime( pTime );
  157. strncpy( pOut, pStr, nMaxBytes );
  158. pOut[nMaxBytes-1] = 0;
  159. g_LocalTimeMutex.Unlock();
  160. }
  161. void Plat_gmtime( uint64 nTime, struct tm *pTime )
  162. {
  163. time_t tmtTime = nTime;
  164. #ifdef _PS3
  165. struct tm * tmp = gmtime( &tmtTime );
  166. * pTime = * tmp;
  167. #else
  168. gmtime_s( pTime, &tmtTime );
  169. #endif
  170. }
  171. time_t Plat_timegm( struct tm *timeptr )
  172. {
  173. #ifndef _GAMECONSOLE
  174. return _mkgmtime( timeptr );
  175. #else
  176. int *pnCrashHereBecauseConsolesDontSupportMkGmTime = 0;
  177. *pnCrashHereBecauseConsolesDontSupportMkGmTime = 0;
  178. return 0;
  179. #endif
  180. }
  181. void Plat_GetModuleFilename( char *pOut, int nMaxBytes )
  182. {
  183. #ifdef PLATFORM_WINDOWS_PC
  184. GetModuleFileName( NULL, pOut, nMaxBytes );
  185. if ( GetLastError() != ERROR_SUCCESS )
  186. Error( "Plat_GetModuleFilename: The buffer given is too small (%d bytes).", nMaxBytes );
  187. #elif PLATFORM_X360
  188. pOut[0] = 0x00; // return null string on Xbox 360
  189. #else
  190. // We shouldn't need this on POSIX.
  191. Assert( false );
  192. pOut[0] = 0x00; // Null the returned string in release builds
  193. #endif
  194. }
  195. void Plat_ExitProcess( int nCode )
  196. {
  197. #if defined( _WIN32 ) && !defined( _X360 )
  198. // We don't want global destructors in our process OR in any DLL to get executed.
  199. // _exit() avoids calling global destructors in our module, but not in other DLLs.
  200. TerminateProcess( GetCurrentProcess(), nCode );
  201. #elif defined(_PS3)
  202. // We do not use this path to exit on PS3 (naturally), rather we want a clear crash:
  203. int *x = NULL; *x = 1;
  204. #else
  205. _exit( nCode );
  206. #endif
  207. }
  208. void GetCurrentDate( int *pDay, int *pMonth, int *pYear )
  209. {
  210. struct tm long_time;
  211. Plat_GetLocalTime( &long_time );
  212. *pDay = long_time.tm_mday;
  213. *pMonth = long_time.tm_mon + 1;
  214. *pYear = long_time.tm_year + 1900;
  215. }
  216. // Wraps the thread-safe versions of asctime. buf must be at least 26 bytes
  217. char *Plat_asctime( const struct tm *tm, char *buf, size_t bufsize )
  218. {
  219. #ifdef _PS3
  220. snprintf( buf, bufsize, "%s", asctime(tm) );
  221. return buf;
  222. #else
  223. if ( EINVAL == asctime_s( buf, bufsize, tm ) )
  224. return NULL;
  225. else
  226. return buf;
  227. #endif
  228. }
  229. // Wraps the thread-safe versions of ctime. buf must be at least 26 bytes
  230. char *Plat_ctime( const time_t *timep, char *buf, size_t bufsize )
  231. {
  232. #ifdef _PS3
  233. snprintf( buf, bufsize, "%s", ctime( timep ) );
  234. return buf;
  235. #else
  236. if ( EINVAL == ctime_s( buf, bufsize, timep ) )
  237. return NULL;
  238. else
  239. return buf;
  240. #endif
  241. }
  242. // Wraps the thread-safe versions of gmtime
  243. struct tm *Plat_gmtime( const time_t *timep, struct tm *result )
  244. {
  245. #ifdef _PS3
  246. *result = *gmtime( timep );
  247. return result;
  248. #else
  249. if ( EINVAL == gmtime_s( result, timep ) )
  250. return NULL;
  251. else
  252. return result;
  253. #endif
  254. }
  255. // Wraps the thread-safe versions of localtime
  256. struct tm *Plat_localtime( const time_t *timep, struct tm *result )
  257. {
  258. #ifdef _PS3
  259. *result = *localtime( timep );
  260. return result;
  261. #else
  262. if ( EINVAL == localtime_s( result, timep ) )
  263. return NULL;
  264. else
  265. return result;
  266. #endif
  267. }
  268. bool vtune( bool resume )
  269. {
  270. #if IS_WINDOWS_PC
  271. static bool bInitialized = false;
  272. static void (__cdecl *VTResume)(void) = NULL;
  273. static void (__cdecl *VTPause) (void) = NULL;
  274. // Grab the Pause and Resume function pointers from the VTune DLL the first time through:
  275. if( !bInitialized )
  276. {
  277. bInitialized = true;
  278. HINSTANCE pVTuneDLL = LoadLibrary( "vtuneapi.dll" );
  279. if( pVTuneDLL )
  280. {
  281. VTResume = (void(__cdecl *)())GetProcAddress( pVTuneDLL, "VTResume" );
  282. VTPause = (void(__cdecl *)())GetProcAddress( pVTuneDLL, "VTPause" );
  283. }
  284. }
  285. // Call the appropriate function, as indicated by the argument:
  286. if( resume && VTResume )
  287. {
  288. VTResume();
  289. return true;
  290. }
  291. else if( !resume && VTPause )
  292. {
  293. VTPause();
  294. return true;
  295. }
  296. #endif
  297. return false;
  298. }
  299. bool Plat_IsInDebugSession()
  300. {
  301. #if defined( _X360 )
  302. return (XBX_IsDebuggerPresent() != 0);
  303. #elif defined( _WIN32 )
  304. return (IsDebuggerPresent() != 0);
  305. #elif defined( _PS3 ) && !defined(_CERT)
  306. return snIsDebuggerPresent();
  307. #else
  308. return false;
  309. #endif
  310. }
  311. void Plat_DebugString( const char * psz )
  312. {
  313. #ifdef _CERT
  314. return; // do nothing!
  315. #endif
  316. #if defined( _X360 )
  317. XBX_OutputDebugString( psz );
  318. #elif defined( _WIN32 )
  319. ::OutputDebugStringA( psz );
  320. #elif defined(_PS3)
  321. printf("%s",psz);
  322. #else
  323. // do nothing?
  324. #endif
  325. }
  326. #if defined( PLATFORM_WINDOWS_PC )
  327. void Plat_MessageBox( const char *pTitle, const char *pMessage )
  328. {
  329. MessageBox( NULL, pMessage, pTitle, MB_OK );
  330. }
  331. #endif
  332. PlatOSVersion_t Plat_GetOSVersion()
  333. {
  334. #ifdef PLATFORM_WINDOWS_PC
  335. OSVERSIONINFO info;
  336. info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  337. if ( GetVersionEx( &info ) )
  338. return (PlatOSVersion_t)info.dwMajorVersion;
  339. return PLAT_OS_VERSION_UNKNOWN;
  340. #elif defined( PLATFORM_X360 )
  341. return PLAT_OS_VERSION_XBOX360;
  342. #else
  343. return PLAT_OS_VERSION_UNKNOWN;
  344. #endif
  345. }
  346. #if defined( PLATFORM_PS3 )
  347. //copied from platform_posix.cpp
  348. static char g_CmdLine[ 2048 ] = "";
  349. PLATFORM_INTERFACE void Plat_SetCommandLine( const char *cmdLine )
  350. {
  351. strncpy( g_CmdLine, cmdLine, sizeof(g_CmdLine) );
  352. g_CmdLine[ sizeof(g_CmdLine) -1 ] = 0;
  353. }
  354. #endif
  355. PLATFORM_INTERFACE const tchar *Plat_GetCommandLine()
  356. {
  357. #if defined( _PS3 )
  358. #pragma message("Plat_GetCommandLine() not implemented on PS3") // ****
  359. return g_CmdLine;
  360. #elif defined( TCHAR_IS_WCHAR )
  361. return GetCommandLineW();
  362. #else
  363. return GetCommandLine();
  364. #endif
  365. }
  366. PLATFORM_INTERFACE const char *Plat_GetCommandLineA()
  367. {
  368. #if defined( _PS3 )
  369. #pragma message("Plat_GetCommandLineA() not implemented on PS3") // ****
  370. return g_CmdLine;
  371. #else
  372. return GetCommandLineA();
  373. #endif
  374. }
  375. //-----------------------------------------------------------------------------
  376. // Dynamically load a function
  377. //-----------------------------------------------------------------------------
  378. #ifdef PLATFORM_WINDOWS
  379. void *Plat_GetProcAddress( const char *pszModule, const char *pszName )
  380. {
  381. HMODULE hModule = ::LoadLibrary( pszModule );
  382. return ( hModule ) ? ::GetProcAddress( hModule, pszName ) : NULL;
  383. }
  384. #endif
  385. // -------------------------------------------------------------------------------------------------- //
  386. // Memory stuff.
  387. //
  388. // DEPRECATED. Still here to support binary back compatability of tier0.dll
  389. //
  390. // -------------------------------------------------------------------------------------------------- //
  391. #ifndef _X360
  392. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  393. typedef void (*Plat_AllocErrorFn)( unsigned long size );
  394. void Plat_DefaultAllocErrorFn( unsigned long size )
  395. {
  396. }
  397. Plat_AllocErrorFn g_AllocError = Plat_DefaultAllocErrorFn;
  398. #endif
  399. #if !defined( _X360 ) && !defined( _PS3 )
  400. CRITICAL_SECTION g_AllocCS;
  401. class CAllocCSInit
  402. {
  403. public:
  404. CAllocCSInit()
  405. {
  406. InitializeCriticalSection( &g_AllocCS );
  407. }
  408. } g_AllocCSInit;
  409. PLATFORM_INTERFACE void* Plat_Alloc( unsigned long size )
  410. {
  411. EnterCriticalSection( &g_AllocCS );
  412. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  413. void *pRet = MemAlloc_Alloc( size );
  414. #else
  415. void *pRet = malloc( size );
  416. #endif
  417. LeaveCriticalSection( &g_AllocCS );
  418. if ( pRet )
  419. {
  420. return pRet;
  421. }
  422. else
  423. {
  424. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  425. g_AllocError( size );
  426. #endif
  427. return 0;
  428. }
  429. }
  430. PLATFORM_INTERFACE void* Plat_Realloc( void *ptr, unsigned long size )
  431. {
  432. EnterCriticalSection( &g_AllocCS );
  433. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  434. void *pRet = g_pMemAlloc->Realloc( ptr, size );
  435. #else
  436. void *pRet = realloc( ptr, size );
  437. #endif
  438. LeaveCriticalSection( &g_AllocCS );
  439. if ( pRet )
  440. {
  441. return pRet;
  442. }
  443. else
  444. {
  445. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  446. g_AllocError( size );
  447. #endif
  448. return 0;
  449. }
  450. }
  451. PLATFORM_INTERFACE void Plat_Free( void *ptr )
  452. {
  453. EnterCriticalSection( &g_AllocCS );
  454. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  455. g_pMemAlloc->Free( ptr );
  456. #else
  457. free( ptr );
  458. #endif
  459. LeaveCriticalSection( &g_AllocCS );
  460. }
  461. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  462. PLATFORM_INTERFACE void Plat_SetAllocErrorFn( Plat_AllocErrorFn fn )
  463. {
  464. g_AllocError = fn;
  465. }
  466. #endif
  467. #endif
  468. #endif