doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
main.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 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.
23 
24 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.
25 
26 ===========================================================================
27 */
28 #include "../../idlib/precompiled.h"
29 #include "../posix/posix_public.h"
30 #include "../sys_local.h"
31 #include "local.h"
32 
33 #include <pthread.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <fcntl.h>
39 
40 #ifdef ID_MCHECK
41 #include <mcheck.h>
42 #endif
43 
44 static idStr basepath;
45 static idStr savepath;
46 
47 /*
48 ===========
49 Sys_InitScanTable
50 ===========
51 */
52 void Sys_InitScanTable( void ) {
53  common->DPrintf( "TODO: Sys_InitScanTable\n" );
54 }
55 
56 /*
57 =================
58 Sys_AsyncThread
59 =================
60 */
61 void Sys_AsyncThread( void ) {
62  int now;
63  int next;
64  int want_sleep;
65 
66  // multi tick compensate for poor schedulers (Linux 2.4)
67  int ticked, to_ticked;
68  now = Sys_Milliseconds();
69  ticked = now >> 4;
70  while (1) {
71  // sleep
72  now = Sys_Milliseconds();
73  next = ( now & 0xFFFFFFF0 ) + 0x10;
74  want_sleep = ( next-now-1 ) * 1000;
75  if ( want_sleep > 0 ) {
76  usleep( want_sleep ); // sleep 1ms less than true target
77  }
78 
79  // compensate if we slept too long
80  now = Sys_Milliseconds();
81  to_ticked = now >> 4;
82 
83  // show ticking statistics - every 100 ticks, print a summary
84  #if 0
85  #define STAT_BUF 100
86  static int stats[STAT_BUF];
87  static int counter = 0;
88  // how many ticks to play
89  stats[counter] = to_ticked - ticked;
90  counter++;
91  if (counter == STAT_BUF) {
92  Sys_DebugPrintf("\n");
93  for( int i = 0; i < STAT_BUF; i++) {
94  if ( ! (i & 0xf) ) {
95  Sys_DebugPrintf("\n");
96  }
97  Sys_DebugPrintf( "%d ", stats[i] );
98  }
99  Sys_DebugPrintf("\n");
100  counter = 0;
101  }
102  #endif
103 
104  while ( ticked < to_ticked ) {
105  common->Async();
106  ticked++;
108  }
109  // thread exit
110  pthread_testcancel();
111  }
112 }
113 
114 /*
115  ==============
116  Sys_DefaultSavePath
117  ==============
118  */
119 const char *Sys_DefaultSavePath(void) {
120 #if defined( ID_DEMO_BUILD )
121  sprintf( savepath, "%s/.doom3-demo", getenv( "HOME" ) );
122 #else
123  sprintf( savepath, "%s/.doom3", getenv( "HOME" ) );
124 #endif
125  return savepath.c_str();
126 }
127 /*
128 ==============
129 Sys_EXEPath
130 ==============
131 */
132 const char *Sys_EXEPath( void ) {
133  static char buf[ 1024 ];
134  idStr linkpath;
135  int len;
136 
137  buf[ 0 ] = '\0';
138  sprintf( linkpath, "/proc/%d/exe", getpid() );
139  len = readlink( linkpath.c_str(), buf, sizeof( buf ) );
140  if ( len == -1 ) {
141  Sys_Printf("couldn't stat exe path link %s\n", linkpath.c_str());
142  buf[ len ] = '\0';
143  }
144  return buf;
145 }
146 
147 /*
148 ================
149 Sys_DefaultBasePath
150 
151 Get the default base path
152 - binary image path
153 - current directory
154 - hardcoded
155 Try to be intelligent: if there is no BASE_GAMEDIR, try the next path
156 ================
157 */
158 const char *Sys_DefaultBasePath(void) {
159  struct stat st;
160  idStr testbase;
161  basepath = Sys_EXEPath();
162  if ( basepath.Length() ) {
163  basepath.StripFilename();
164  testbase = basepath; testbase += "/"; testbase += BASE_GAMEDIR;
165  if ( stat( testbase.c_str(), &st ) != -1 && S_ISDIR( st.st_mode ) ) {
166  return basepath.c_str();
167  } else {
168  common->Printf( "no '%s' directory in exe path %s, skipping\n", BASE_GAMEDIR, basepath.c_str() );
169  }
170  }
171  if ( basepath != Posix_Cwd() ) {
172  basepath = Posix_Cwd();
173  testbase = basepath; testbase += "/"; testbase += BASE_GAMEDIR;
174  if ( stat( testbase.c_str(), &st ) != -1 && S_ISDIR( st.st_mode ) ) {
175  return basepath.c_str();
176  } else {
177  common->Printf("no '%s' directory in cwd path %s, skipping\n", BASE_GAMEDIR, basepath.c_str());
178  }
179  }
180  common->Printf( "WARNING: using hardcoded default base path\n" );
181  return LINUX_DEFAULT_PATH;
182 }
183 
184 /*
185 ===============
186 Sys_GetConsoleKey
187 ===============
188 */
189 unsigned char Sys_GetConsoleKey( bool shifted ) {
190  return shifted ? '~' : '`';
191 }
192 
193 /*
194 ===============
195 Sys_Shutdown
196 ===============
197 */
198 void Sys_Shutdown( void ) {
199  basepath.Clear();
200  savepath.Clear();
201  Posix_Shutdown();
202 }
203 
204 /*
205 ===============
206 Sys_GetProcessorId
207 ===============
208 */
210  return CPUID_GENERIC;
211 }
212 
213 /*
214 ===============
215 Sys_GetProcessorString
216 ===============
217 */
218 const char *Sys_GetProcessorString( void ) {
219  return "generic";
220 }
221 
222 /*
223 ===============
224 Sys_FPU_EnableExceptions
225 ===============
226 */
227 void Sys_FPU_EnableExceptions( int exceptions ) {
228 }
229 
230 /*
231 ===============
232 Sys_FPE_handler
233 ===============
234 */
235 void Sys_FPE_handler( int signum, siginfo_t *info, void *context ) {
236  assert( signum == SIGFPE );
237  Sys_Printf( "FPE\n" );
238 }
239 
240 /*
241 ===============
242 Sys_GetClockticks
243 ===============
244 */
245 double Sys_GetClockTicks( void ) {
246 #if defined( __i386__ )
247  unsigned long lo, hi;
248 
249  __asm__ __volatile__ (
250  "push %%ebx\n" \
251  "xor %%eax,%%eax\n" \
252  "cpuid\n" \
253  "rdtsc\n" \
254  "mov %%eax,%0\n" \
255  "mov %%edx,%1\n" \
256  "pop %%ebx\n"
257  : "=r" (lo), "=r" (hi) );
258  return (double) lo + (double) 0xFFFFFFFF * hi;
259 #else
260 #error unsupported CPU
261 #endif
262 }
263 
264 /*
265 ===============
266 MeasureClockTicks
267 ===============
268 */
269 double MeasureClockTicks( void ) {
270  double t0, t1;
271 
272  t0 = Sys_GetClockTicks( );
273  Sys_Sleep( 1000 );
274  t1 = Sys_GetClockTicks( );
275  return t1 - t0;
276 }
277 
278 /*
279 ===============
280 Sys_ClockTicksPerSecond
281 ===============
282 */
284  static bool init = false;
285  static double ret;
286 
287  int fd, len, pos, end;
288  char buf[ 4096 ];
289 
290  if ( init ) {
291  return ret;
292  }
293 
294  fd = open( "/proc/cpuinfo", O_RDONLY );
295  if ( fd == -1 ) {
296  common->Printf( "couldn't read /proc/cpuinfo\n" );
297  ret = MeasureClockTicks();
298  init = true;
299  common->Printf( "measured CPU frequency: %g MHz\n", ret / 1000000.0 );
300  return ret;
301  }
302  len = read( fd, buf, 4096 );
303  close( fd );
304  pos = 0;
305  while ( pos < len ) {
306  if ( !idStr::Cmpn( buf + pos, "cpu MHz", 7 ) ) {
307  pos = strchr( buf + pos, ':' ) - buf + 2;
308  end = strchr( buf + pos, '\n' ) - buf;
309  if ( pos < len && end < len ) {
310  buf[end] = '\0';
311  ret = atof( buf + pos );
312  } else {
313  common->Printf( "failed parsing /proc/cpuinfo\n" );
314  ret = MeasureClockTicks();
315  init = true;
316  common->Printf( "measured CPU frequency: %g MHz\n", ret / 1000000.0 );
317  return ret;
318  }
319  common->Printf( "/proc/cpuinfo CPU frequency: %g MHz\n", ret );
320  ret *= 1000000;
321  init = true;
322  return ret;
323  }
324  pos = strchr( buf + pos, '\n' ) - buf + 1;
325  }
326  common->Printf( "failed parsing /proc/cpuinfo\n" );
327  ret = MeasureClockTicks();
328  init = true;
329  common->Printf( "measured CPU frequency: %g MHz\n", ret / 1000000.0 );
330  return ret;
331 }
332 
333 /*
334 ================
335 Sys_GetSystemRam
336 returns in megabytes
337 ================
338 */
339 int Sys_GetSystemRam( void ) {
340  long count, page_size;
341  int mb;
342 
343  count = sysconf( _SC_PHYS_PAGES );
344  if ( count == -1 ) {
345  common->Printf( "GetSystemRam: sysconf _SC_PHYS_PAGES failed\n" );
346  return 512;
347  }
348  page_size = sysconf( _SC_PAGE_SIZE );
349  if ( page_size == -1 ) {
350  common->Printf( "GetSystemRam: sysconf _SC_PAGE_SIZE failed\n" );
351  return 512;
352  }
353  mb= (int)( (double)count * (double)page_size / ( 1024 * 1024 ) );
354  // round to the nearest 16Mb
355  mb = ( mb + 8 ) & ~15;
356  return mb;
357 }
358 
359 /*
360 ==================
361 Sys_DoStartProcess
362 if we don't fork, this function never returns
363 the no-fork lets you keep the terminal when you're about to spawn an installer
364 
365 if the command contains spaces, system() is used. Otherwise the more straightforward execl ( system() blows though )
366 ==================
367 */
368 void Sys_DoStartProcess( const char *exeName, bool dofork ) {
369  bool use_system = false;
370  if ( strchr( exeName, ' ' ) ) {
371  use_system = true;
372  } else {
373  // set exec rights when it's about a single file to execute
374  struct stat buf;
375  if ( stat( exeName, &buf ) == -1 ) {
376  printf( "stat %s failed: %s\n", exeName, strerror( errno ) );
377  } else {
378  if ( chmod( exeName, buf.st_mode | S_IXUSR ) == -1 ) {
379  printf( "cmod +x %s failed: %s\n", exeName, strerror( errno ) );
380  }
381  }
382  }
383  if ( dofork ) {
384  switch ( fork() ) {
385  case -1:
386  // main thread
387  break;
388  case 0:
389  if ( use_system ) {
390  printf( "system %s\n", exeName );
391  system( exeName );
392  _exit( 0 );
393  } else {
394  printf( "execl %s\n", exeName );
395  execl( exeName, exeName, NULL );
396  printf( "execl failed: %s\n", strerror( errno ) );
397  _exit( -1 );
398  }
399  break;
400  }
401  } else {
402  if ( use_system ) {
403  printf( "system %s\n", exeName );
404  system( exeName );
405  sleep( 1 ); // on some systems I've seen that starting the new process and exiting this one should not be too close
406  } else {
407  printf( "execl %s\n", exeName );
408  execl( exeName, exeName, NULL );
409  printf( "execl failed: %s\n", strerror( errno ) );
410  }
411  // terminate
412  _exit( 0 );
413  }
414 }
415 
416 /*
417 =================
418 Sys_OpenURL
419 =================
420 */
421 void idSysLocal::OpenURL( const char *url, bool quit ) {
422  const char *script_path;
423  idFile *script_file;
424  char cmdline[ 1024 ];
425 
426  static bool quit_spamguard = false;
427 
428  if ( quit_spamguard ) {
429  common->DPrintf( "Sys_OpenURL: already in a doexit sequence, ignoring %s\n", url );
430  return;
431  }
432 
433  common->Printf( "Open URL: %s\n", url );
434  // opening an URL on *nix can mean a lot of things ..
435  // just spawn a script instead of deciding for the user :-)
436 
437  // look in the savepath first, then in the basepath
438  script_path = fileSystem->BuildOSPath( cvarSystem->GetCVarString( "fs_savepath" ), "", "openurl.sh" );
439  script_file = fileSystem->OpenExplicitFileRead( script_path );
440  if ( !script_file ) {
441  script_path = fileSystem->BuildOSPath( cvarSystem->GetCVarString( "fs_basepath" ), "", "openurl.sh" );
442  script_file = fileSystem->OpenExplicitFileRead( script_path );
443  }
444  if ( !script_file ) {
445  common->Printf( "Can't find URL script 'openurl.sh' in either savepath or basepath\n" );
446  common->Printf( "OpenURL '%s' failed\n", url );
447  return;
448  }
449  fileSystem->CloseFile( script_file );
450 
451  // if we are going to quit, only accept a single URL before quitting and spawning the script
452  if ( quit ) {
453  quit_spamguard = true;
454  }
455 
456  common->Printf( "URL script: %s\n", script_path );
457 
458  // StartProcess is going to execute a system() call with that - hence the &
459  idStr::snPrintf( cmdline, 1024, "%s '%s' &", script_path, url );
460  sys->StartProcess( cmdline, quit );
461 }
462 
463 /*
464  ==================
465  Sys_DoPreferences
466  ==================
467  */
468 void Sys_DoPreferences( void ) { }
469 
470 /*
471 ================
472 Sys_FPU_SetDAZ
473 ================
474 */
475 void Sys_FPU_SetDAZ( bool enable ) {
476  /*
477  DWORD dwData;
478 
479  _asm {
480  movzx ecx, byte ptr enable
481  and ecx, 1
482  shl ecx, 6
483  STMXCSR dword ptr dwData
484  mov eax, dwData
485  and eax, ~(1<<6) // clear DAX bit
486  or eax, ecx // set the DAZ bit
487  mov dwData, eax
488  LDMXCSR dword ptr dwData
489  }
490  */
491 }
492 
493 /*
494 ================
495 Sys_FPU_SetFTZ
496 ================
497 */
498 void Sys_FPU_SetFTZ( bool enable ) {
499  /*
500  DWORD dwData;
501 
502  _asm {
503  movzx ecx, byte ptr enable
504  and ecx, 1
505  shl ecx, 15
506  STMXCSR dword ptr dwData
507  mov eax, dwData
508  and eax, ~(1<<15) // clear FTZ bit
509  or eax, ecx // set the FTZ bit
510  mov dwData, eax
511  LDMXCSR dword ptr dwData
512  }
513  */
514 }
515 
516 /*
517 ===============
518 mem consistency stuff
519 ===============
520 */
521 
522 #ifdef ID_MCHECK
523 
524 const char *mcheckstrings[] = {
525  "MCHECK_DISABLED",
526  "MCHECK_OK",
527  "MCHECK_FREE", // block freed twice
528  "MCHECK_HEAD", // memory before the block was clobbered
529  "MCHECK_TAIL" // memory after the block was clobbered
530 };
531 
532 void abrt_func( mcheck_status status ) {
533  Sys_Printf( "memory consistency failure: %s\n", mcheckstrings[ status + 1 ] );
535  common->Quit();
536 }
537 
538 #endif
539 
540 /*
541 ===============
542 main
543 ===============
544 */
545 int main(int argc, const char **argv) {
546 #ifdef ID_MCHECK
547  // must have -lmcheck linkage
548  mcheck( abrt_func );
549  Sys_Printf( "memory consistency checking enabled\n" );
550 #endif
551 
552  Posix_EarlyInit( );
553 
554  if ( argc > 1 ) {
555  common->Init( argc-1, &argv[1], NULL );
556  } else {
557  common->Init( 0, NULL, NULL );
558  }
559 
560  Posix_LateInit( );
561 
562  while (1) {
563  common->Frame();
564  }
565 }
static int snPrintf(char *dest, int size, const char *fmt,...) id_attribute((format(printf
Definition: Str.cpp:1465
void Sys_AsyncThread(void)
Definition: main.cpp:61
#define O_RDONLY
double Sys_ClockTicksPerSecond(void)
Definition: main.cpp:283
assert(prefInfo.fullscreenBtn)
idCVarSystem * cvarSystem
Definition: CVarSystem.cpp:487
double Sys_GetClockTicks(void)
Definition: main.cpp:245
const char * Sys_DefaultSavePath(void)
Definition: main.cpp:119
void Sys_FPU_EnableExceptions(int exceptions)
Definition: main.cpp:227
int Length(void) const
Definition: Str.h:702
void Sys_Printf(const char *msg,...)
int Sys_Milliseconds(void)
case const int
Definition: Callbacks.cpp:52
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
virtual idFile * OpenExplicitFileRead(const char *OSPath)=0
void Sys_DebugPrintf(const char *fmt,...)
Definition: posix_main.cpp:999
void Sys_FPU_SetDAZ(bool enable)
Definition: main.cpp:475
void Sys_Sleep(const int time)
Definition: macosx_sys.mm:67
GLenum GLsizei len
Definition: glext.h:3472
int i
Definition: process.py:33
int Cmpn(const char *text, int n) const
Definition: Str.h:657
void Sys_FPE_handler(int signum, siginfo_t *info, void *context)
Definition: main.cpp:235
virtual void Async(void)=0
void Sys_TriggerEvent(int index)
Definition: main.cpp:202
virtual void Frame(void)=0
Definition: File.h:50
int main(int argc, const char **argv)
Definition: main.cpp:545
GLuint GLuint GLsizei count
Definition: glext.h:2845
#define BASE_GAMEDIR
Definition: Licensee.h:46
void Posix_SetExit(int ret)
Definition: posix_main.cpp:109
GLuint GLuint end
Definition: glext.h:2845
unsigned char Sys_GetConsoleKey(bool shifted)
Definition: main.cpp:189
double MeasureClockTicks(void)
Definition: main.cpp:269
void Posix_EarlyInit(void)
Definition: posix_main.cpp:538
#define LINUX_DEFAULT_PATH
Definition: Licensee.h:104
void Sys_Shutdown(void)
Definition: main.cpp:198
#define NULL
Definition: Lib.h:88
virtual const char * GetCVarString(const char *name) const =0
cpuid_t
Definition: sys_public.h:142
int Sys_GetSystemRam(void)
Definition: main.cpp:339
void Posix_Shutdown(void)
Definition: posix_main.cpp:376
virtual void StartProcess(const char *exePath, bool quit)=0
#define EXIT_FAILURE
Definition: jerror.c:27
void Clear(void)
Definition: Str.h:724
virtual void Printf(const char *fmt,...) id_attribute((format(printf
#define context
Definition: getdate.c:236
virtual const char * BuildOSPath(const char *base, const char *game, const char *relativePath)=0
virtual void OpenURL(const char *url, bool quit)
Definition: main.cpp:421
#define STAT_BUF
const char * Sys_GetProcessorString(void)
Definition: main.cpp:218
GLfloat * st
Definition: qgl.h:89
const char * Posix_Cwd(void)
Definition: posix_main.cpp:337
Definition: Str.h:116
const char * c_str(void) const
Definition: Str.h:487
void Sys_DoPreferences(void)
Definition: main.cpp:468
void Sys_FPU_SetFTZ(bool enable)
Definition: main.cpp:498
void Sys_DoStartProcess(const char *exeName, bool dofork)
Definition: main.cpp:368
virtual void Quit(void)=0
void Sys_InitScanTable(void)
Definition: main.cpp:52
virtual void CloseFile(idFile *f)=0
virtual void DPrintf(const char *fmt,...) id_attribute((format(printf
idCommon * common
Definition: main.cpp:96
idSys * sys
Definition: main.cpp:243
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
virtual void Init(int argc, const char **argv, const char *cmdline)=0
idStr & StripFilename(void)
Definition: Str.cpp:864
const char * Sys_EXEPath(void)
Definition: main.cpp:132
cpuid_t Sys_GetProcessorId(void)
Definition: main.cpp:209
const char * Sys_DefaultBasePath(void)
Definition: main.cpp:158
void Posix_LateInit(void)
Definition: posix_main.cpp:552