123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "../../idlib/precompiled.h"
- #include "../posix/posix_public.h"
- #include "../sys_local.h"
- #include "local.h"
- #include <pthread.h>
- #include <errno.h>
- #include <unistd.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <fcntl.h>
- #ifdef ID_MCHECK
- #include <mcheck.h>
- #endif
- static idStr basepath;
- static idStr savepath;
- #ifndef USE_SDL
- /*
- ===========
- Sys_InitScanTable
- ===========
- */
- void Sys_InitScanTable( void ) {
- common->DPrintf( "TODO: Sys_InitScanTable\n" );
- }
- #endif
- /*
- =================
- Sys_AsyncThread
- =================
- */
- void Sys_AsyncThread( void ) {
- int now;
- int next;
- int want_sleep;
- // multi tick compensate for poor schedulers (Linux 2.4)
- int ticked, to_ticked;
- now = Sys_Milliseconds();
- ticked = now >> 4;
- while (1) {
- // sleep
- now = Sys_Milliseconds();
- next = ( now & 0xFFFFFFF0 ) + 0x10;
- want_sleep = ( next-now-1 ) * 1000;
- if ( want_sleep > 0 ) {
- usleep( want_sleep ); // sleep 1ms less than true target
- }
-
- // compensate if we slept too long
- now = Sys_Milliseconds();
- to_ticked = now >> 4;
-
- // show ticking statistics - every 100 ticks, print a summary
- #if 0
- #define STAT_BUF 100
- static int stats[STAT_BUF];
- static int counter = 0;
- // how many ticks to play
- stats[counter] = to_ticked - ticked;
- counter++;
- if (counter == STAT_BUF) {
- Sys_DebugPrintf("\n");
- for( int i = 0; i < STAT_BUF; i++) {
- if ( ! (i & 0xf) ) {
- Sys_DebugPrintf("\n");
- }
- Sys_DebugPrintf( "%d ", stats[i] );
- }
- Sys_DebugPrintf("\n");
- counter = 0;
- }
- #endif
-
- while ( ticked < to_ticked ) {
- common->Async();
- ticked++;
- Sys_TriggerEvent( TRIGGER_EVENT_ONE );
- }
- // thread exit
- pthread_testcancel();
- }
- }
- /*
- ==============
- Sys_DefaultSavePath
- ==============
- */
- const char *Sys_DefaultSavePath(void) {
- // TODO: use sdl2 path methods
- #if defined( ID_DEMO_BUILD )
- sprintf( savepath, "%s/.local/share/BlendoGames/QuadrilateralCowboy-demo", getenv( "HOME" ) );
- #else
- sprintf( savepath, "%s/.local/share/BlendoGames/QuadrilateralCowboy", getenv( "HOME" ) );
- #endif
- return savepath.c_str();
- }
- /*
- ==============
- Sys_EXEPath
- ==============
- */
- const char *Sys_EXEPath( void ) {
- static char buf[ 1024 ];
- idStr linkpath;
- int len;
- buf[ 0 ] = '\0';
- sprintf( linkpath, "/proc/%d/exe", getpid() );
- len = readlink( linkpath.c_str(), buf, sizeof( buf ) );
- if ( len == -1 ) {
- Sys_Printf("couldn't stat exe path link %s\n", linkpath.c_str());
- buf[ len ] = '\0';
- }
- return buf;
- }
- /*
- ================
- Sys_DefaultBasePath
- Get the default base path
- - binary image path
- - current directory
- - hardcoded
- Try to be intelligent: if there is no BASE_GAMEDIR, try the next path
- ================
- */
- const char *Sys_DefaultBasePath(void) {
- struct stat st;
- idStr testbase;
- basepath = Sys_EXEPath();
- if ( basepath.Length() ) {
- basepath.StripFilename();
- testbase = basepath; testbase += "/"; testbase += BASE_GAMEDIR;
- if ( stat( testbase.c_str(), &st ) != -1 && S_ISDIR( st.st_mode ) ) {
- return basepath.c_str();
- } else {
- common->Printf( "no '%s' directory in exe path %s, skipping\n", BASE_GAMEDIR, basepath.c_str() );
- }
- }
- if ( basepath != Posix_Cwd() ) {
- basepath = Posix_Cwd();
- testbase = basepath; testbase += "/"; testbase += BASE_GAMEDIR;
- if ( stat( testbase.c_str(), &st ) != -1 && S_ISDIR( st.st_mode ) ) {
- return basepath.c_str();
- } else {
- common->Printf("no '%s' directory in cwd path %s, skipping\n", BASE_GAMEDIR, basepath.c_str());
- }
- }
- common->Printf( "WARNING: using hardcoded default base path\n" );
- return LINUX_DEFAULT_PATH;
- }
- #ifndef USE_SDL
- /*
- ===============
- Sys_GetConsoleKey
- ===============
- */
- unsigned char Sys_GetConsoleKey( bool shifted ) {
- return shifted ? '~' : '`';
- }
- #endif
- /*
- ===============
- Sys_Shutdown
- ===============
- */
- void Sys_Shutdown( void ) {
- basepath.Clear();
- savepath.Clear();
- Posix_Shutdown();
- }
- /*
- ===============
- Sys_GetProcessorId
- ===============
- */
- cpuid_t Sys_GetProcessorId( void ) {
- return CPUID_GENERIC;
- }
- /*
- ===============
- Sys_GetProcessorString
- ===============
- */
- const char *Sys_GetProcessorString( void ) {
- return "generic";
- }
- /*
- ===============
- Sys_FPU_EnableExceptions
- ===============
- */
- void Sys_FPU_EnableExceptions( int exceptions ) {
- }
- /*
- ===============
- Sys_FPE_handler
- ===============
- */
- void Sys_FPE_handler( int signum, siginfo_t *info, void *context ) {
- assert( signum == SIGFPE );
- Sys_Printf( "FPE\n" );
- }
- /*
- ===============
- Sys_GetClockticks
- ===============
- */
- double Sys_GetClockTicks( void ) {
- #if defined( __i386__ )
- unsigned long lo, hi;
- __asm__ __volatile__ (
- "push %%ebx\n" \
- "xor %%eax,%%eax\n" \
- "cpuid\n" \
- "rdtsc\n" \
- "mov %%eax,%0\n" \
- "mov %%edx,%1\n" \
- "pop %%ebx\n"
- : "=r" (lo), "=r" (hi) );
- return (double) lo + (double) 0xFFFFFFFF * hi;
- #else
- #error unsupported CPU
- #endif
- }
- /*
- ===============
- MeasureClockTicks
- ===============
- */
- double MeasureClockTicks( void ) {
- double t0, t1;
- t0 = Sys_GetClockTicks( );
- Sys_Sleep( 1000 );
- t1 = Sys_GetClockTicks( );
- return t1 - t0;
- }
- /*
- ===============
- Sys_ClockTicksPerSecond
- ===============
- */
- double Sys_ClockTicksPerSecond(void) {
- static bool init = false;
- static double ret;
- int fd, len, pos, end;
- char buf[ 4096 ];
- if ( init ) {
- return ret;
- }
- fd = open( "/proc/cpuinfo", O_RDONLY );
- if ( fd == -1 ) {
- common->Printf( "couldn't read /proc/cpuinfo\n" );
- ret = MeasureClockTicks();
- init = true;
- common->Printf( "measured CPU frequency: %g MHz\n", ret / 1000000.0 );
- return ret;
- }
- len = read( fd, buf, 4096 );
- close( fd );
- pos = 0;
- while ( pos < len ) {
- if ( !idStr::Cmpn( buf + pos, "cpu MHz", 7 ) ) {
- pos = strchr( buf + pos, ':' ) - buf + 2;
- end = strchr( buf + pos, '\n' ) - buf;
- if ( pos < len && end < len ) {
- buf[end] = '\0';
- ret = atof( buf + pos );
- } else {
- common->Printf( "failed parsing /proc/cpuinfo\n" );
- ret = MeasureClockTicks();
- init = true;
- common->Printf( "measured CPU frequency: %g MHz\n", ret / 1000000.0 );
- return ret;
- }
- common->Printf( "/proc/cpuinfo CPU frequency: %g MHz\n", ret );
- ret *= 1000000;
- init = true;
- return ret;
- }
- pos = strchr( buf + pos, '\n' ) - buf + 1;
- }
- common->Printf( "failed parsing /proc/cpuinfo\n" );
- ret = MeasureClockTicks();
- init = true;
- common->Printf( "measured CPU frequency: %g MHz\n", ret / 1000000.0 );
- return ret;
- }
- /*
- ================
- Sys_GetSystemRam
- returns in megabytes
- ================
- */
- int Sys_GetSystemRam( void ) {
- long count, page_size;
- int mb;
- count = sysconf( _SC_PHYS_PAGES );
- if ( count == -1 ) {
- common->Printf( "GetSystemRam: sysconf _SC_PHYS_PAGES failed\n" );
- return 512;
- }
- page_size = sysconf( _SC_PAGE_SIZE );
- if ( page_size == -1 ) {
- common->Printf( "GetSystemRam: sysconf _SC_PAGE_SIZE failed\n" );
- return 512;
- }
- mb= (int)( (double)count * (double)page_size / ( 1024 * 1024 ) );
- // round to the nearest 16Mb
- mb = ( mb + 8 ) & ~15;
- return mb;
- }
- /*
- ==================
- Sys_DoStartProcess
- if we don't fork, this function never returns
- the no-fork lets you keep the terminal when you're about to spawn an installer
- if the command contains spaces, system() is used. Otherwise the more straightforward execl ( system() blows though )
- ==================
- */
- void Sys_DoStartProcess( const char *exeName, bool dofork ) {
- bool use_system = false;
- if ( strchr( exeName, ' ' ) ) {
- use_system = true;
- } else {
- // set exec rights when it's about a single file to execute
- struct stat buf;
- if ( stat( exeName, &buf ) == -1 ) {
- printf( "stat %s failed: %s\n", exeName, strerror( errno ) );
- } else {
- if ( chmod( exeName, buf.st_mode | S_IXUSR ) == -1 ) {
- printf( "cmod +x %s failed: %s\n", exeName, strerror( errno ) );
- }
- }
- }
- if ( dofork ) {
- switch ( fork() ) {
- case -1:
- // main thread
- break;
- case 0:
- if ( use_system ) {
- printf( "system %s\n", exeName );
- system( exeName );
- _exit( 0 );
- } else {
- printf( "execl %s\n", exeName );
- execl( exeName, exeName, NULL );
- printf( "execl failed: %s\n", strerror( errno ) );
- _exit( -1 );
- }
- break;
- }
- } else {
- if ( use_system ) {
- printf( "system %s\n", exeName );
- system( exeName );
- sleep( 1 ); // on some systems I've seen that starting the new process and exiting this one should not be too close
- } else {
- printf( "execl %s\n", exeName );
- execl( exeName, exeName, NULL );
- printf( "execl failed: %s\n", strerror( errno ) );
- }
- // terminate
- _exit( 0 );
- }
- }
- /*
- =================
- Sys_OpenURL
- =================
- */
- void idSysLocal::OpenURL( const char *url, bool quit ) {
- const char *script_path;
- idFile *script_file;
- char cmdline[ 1024 ];
- static bool quit_spamguard = false;
- if ( quit_spamguard ) {
- common->DPrintf( "Sys_OpenURL: already in a doexit sequence, ignoring %s\n", url );
- return;
- }
- common->Printf( "Open URL: %s\n", url );
- // opening an URL on *nix can mean a lot of things ..
- // just spawn a script instead of deciding for the user :-)
- // look in the savepath first, then in the basepath
- script_path = fileSystem->BuildOSPath( cvarSystem->GetCVarString( "fs_savepath" ), "", "openurl.sh" );
- script_file = fileSystem->OpenExplicitFileRead( script_path );
- if ( !script_file ) {
- script_path = fileSystem->BuildOSPath( cvarSystem->GetCVarString( "fs_basepath" ), "", "openurl.sh" );
- script_file = fileSystem->OpenExplicitFileRead( script_path );
- }
- if ( !script_file ) {
- common->Printf( "Can't find URL script 'openurl.sh' in either savepath or basepath\n" );
- common->Printf( "OpenURL '%s' failed\n", url );
- return;
- }
- fileSystem->CloseFile( script_file );
- // if we are going to quit, only accept a single URL before quitting and spawning the script
- if ( quit ) {
- quit_spamguard = true;
- }
- common->Printf( "URL script: %s\n", script_path );
- // StartProcess is going to execute a system() call with that - hence the &
- idStr::snPrintf( cmdline, 1024, "%s '%s' &", script_path, url );
- sys->StartProcess( cmdline, quit );
- }
- /*
- ==================
- Sys_DoPreferences
- ==================
- */
- void Sys_DoPreferences( void ) { }
- /*
- ================
- Sys_FPU_SetDAZ
- ================
- */
- void Sys_FPU_SetDAZ( bool enable ) {
- /*
- DWORD dwData;
- _asm {
- movzx ecx, byte ptr enable
- and ecx, 1
- shl ecx, 6
- STMXCSR dword ptr dwData
- mov eax, dwData
- and eax, ~(1<<6) // clear DAX bit
- or eax, ecx // set the DAZ bit
- mov dwData, eax
- LDMXCSR dword ptr dwData
- }
- */
- }
- /*
- ================
- Sys_FPU_SetFTZ
- ================
- */
- void Sys_FPU_SetFTZ( bool enable ) {
- /*
- DWORD dwData;
- _asm {
- movzx ecx, byte ptr enable
- and ecx, 1
- shl ecx, 15
- STMXCSR dword ptr dwData
- mov eax, dwData
- and eax, ~(1<<15) // clear FTZ bit
- or eax, ecx // set the FTZ bit
- mov dwData, eax
- LDMXCSR dword ptr dwData
- }
- */
- }
- /*
- ===============
- mem consistency stuff
- ===============
- */
- #ifdef ID_MCHECK
- const char *mcheckstrings[] = {
- "MCHECK_DISABLED",
- "MCHECK_OK",
- "MCHECK_FREE", // block freed twice
- "MCHECK_HEAD", // memory before the block was clobbered
- "MCHECK_TAIL" // memory after the block was clobbered
- };
- void abrt_func( mcheck_status status ) {
- Sys_Printf( "memory consistency failure: %s\n", mcheckstrings[ status + 1 ] );
- Posix_SetExit( EXIT_FAILURE );
- common->Quit();
- }
- #endif
- /*
- ===============
- main
- ===============
- */
- int main(int argc, const char **argv) {
- #ifdef ID_MCHECK
- // must have -lmcheck linkage
- mcheck( abrt_func );
- Sys_Printf( "memory consistency checking enabled\n" );
- #endif
-
- Posix_EarlyInit( );
- if ( argc > 1 ) {
- common->Init( argc-1, &argv[1], NULL );
- } else {
- common->Init( 0, NULL, NULL );
- }
- Posix_LateInit( );
- while (1) {
- common->Frame();
- }
- }
|