7 # include <mmsystem.h> // timeGetTime
8 # include <time.h> // localtime
12 # include <sys/time.h>
19 static char sys_timestring[128];
20 char *Sys_TimeString(const char *timeformat)
22 time_t mytime = time(NULL);
25 localtime_s(&mytm, &mytime);
26 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
28 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
30 return sys_timestring;
34 extern qboolean host_shuttingdown;
35 void Sys_Quit (int returnvalue)
37 if (COM_CheckParm("-profilegameonly"))
38 Sys_AllowProfiling(false);
39 host_shuttingdown = true;
44 #if defined(__linux__) || defined(__FreeBSD__)
51 void Sys_AllowProfiling(qboolean enable)
53 #if defined(__linux__) || defined(__FreeBSD__)
60 ===============================================================================
64 ===============================================================================
67 static qboolean Sys_LoadLibraryFunctions(dllhandle_t dllhandle, const dllfunction_t *fcts, qboolean complain, qboolean has_next)
69 const dllfunction_t *func;
72 for (func = fcts; func && func->name != NULL; func++)
73 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
77 Con_DPrintf (" - missing function \"%s\" - broken library!", func->name);
79 Con_DPrintf("\nContinuing with");
86 for (func = fcts; func && func->name != NULL; func++)
87 *func->funcvariable = NULL;
92 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
95 const dllfunction_t *func;
96 dllhandle_t dllhandle = 0;
103 #ifdef PREFER_PRELOAD
104 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
105 if(Sys_LoadLibraryFunctions(dllhandle, fcts, false, false))
107 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
112 Sys_UnloadLibrary(&dllhandle);
118 for (func = fcts; func && func->name != NULL; func++)
119 *func->funcvariable = NULL;
121 // Try every possible name
122 Con_DPrintf ("Trying to load library...");
123 for (i = 0; dllnames[i] != NULL; i++)
125 Con_DPrintf (" \"%s\"", dllnames[i]);
127 dllhandle = LoadLibrary (dllnames[i]);
129 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
131 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, (dllnames[i+1] != NULL) || (strrchr(com_argv[0], '/'))))
134 Sys_UnloadLibrary (&dllhandle);
137 // see if the names can be loaded relative to the executable path
138 // (this is for Mac OSX which does not check next to the executable)
139 if (!dllhandle && strrchr(com_argv[0], '/'))
141 char path[MAX_OSPATH];
142 strlcpy(path, com_argv[0], sizeof(path));
143 strrchr(path, '/')[1] = 0;
144 for (i = 0; dllnames[i] != NULL; i++)
146 char temp[MAX_OSPATH];
147 strlcpy(temp, path, sizeof(temp));
148 strlcat(temp, dllnames[i], sizeof(temp));
149 Con_DPrintf (" \"%s\"", temp);
151 dllhandle = LoadLibrary (temp);
153 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
155 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, dllnames[i+1] != NULL))
158 Sys_UnloadLibrary (&dllhandle);
165 Con_DPrintf(" - failed.\n");
169 Con_DPrintf(" - loaded.\n");
178 void Sys_UnloadLibrary (dllhandle_t* handle)
181 if (handle == NULL || *handle == NULL)
185 FreeLibrary (*handle);
194 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
198 return (void *)GetProcAddress (handle, name);
200 return (void *)dlsym (handle, name);
208 # define HAVE_TIMEGETTIME 1
209 # define HAVE_QUERYPERFORMANCECOUNTER 1
210 # define HAVE_Sleep 1
213 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
214 # define HAVE_CLOCKGETTIME 1
218 // FIXME improve this check, manpage hints to DST_NONE
219 # define HAVE_GETTIMEOFDAY 1
223 # define HAVE_SELECT 1
227 // FIXME improve this check
228 # define HAVE_USLEEP 1
231 // this one is referenced elsewhere
232 cvar_t sys_usenoclockbutbenchmark = {CVAR_SAVE, "sys_usenoclockbutbenchmark", "0", "don't use ANY real timing, and simulate a clock (for benchmarking); the game then runs as fast as possible. Run a QC mod with bots that does some stuff, then does a quit at the end, to benchmark a server. NEVER do this on a public server."};
235 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
236 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
237 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
238 #if HAVE_QUERYPERFORMANCECOUNTER
239 static cvar_t sys_usequeryperformancecounter = {CVAR_SAVE, "sys_usequeryperformancecounter", "0", "use windows QueryPerformanceCounter timer (which has issues on multicore/multiprocessor machines and processors which are designed to conserve power) for timing rather than timeGetTime function (which has issues on some motherboards)"};
241 #if HAVE_CLOCKGETTIME
242 static cvar_t sys_useclockgettime = {CVAR_SAVE, "sys_useclockgettime", "0", "use POSIX clock_gettime function (which has issues if the system clock speed is far off, as it can't get fixed by NTP) for timing rather than gettimeofday (which has issues if the system time is stepped by ntpdate, or apparently on some Xen installations)"};
245 static unsigned long benchmark_time;
247 void Sys_Init_Commands (void)
249 Cvar_RegisterVariable(&sys_debugsleep);
250 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
251 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
252 if(sys_supportsdlgetticks)
254 Cvar_RegisterVariable(&sys_usesdlgetticks);
255 Cvar_RegisterVariable(&sys_usesdldelay);
258 #if HAVE_QUERYPERFORMANCECOUNTER
259 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
261 #if HAVE_CLOCKGETTIME
262 Cvar_RegisterVariable(&sys_useclockgettime);
266 double Sys_DoubleTime(void)
268 static int first = true;
269 static double oldtime = 0.0, curtime = 0.0;
271 if(sys_usenoclockbutbenchmark.integer)
274 return ((double) benchmark_time) / 1e6;
277 // first all the OPTIONAL timers
279 #if HAVE_QUERYPERFORMANCECOUNTER
280 else if (sys_usequeryperformancecounter.integer)
282 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
283 // QueryPerformanceCounter
285 // Windows 95/98/ME/NT/2000/XP
287 // very accurate (CPU cycles)
289 // does not necessarily match realtime too well (tends to get faster and faster in win98)
290 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
292 LARGE_INTEGER PerformanceFreq;
293 LARGE_INTEGER PerformanceCount;
295 if (!QueryPerformanceFrequency (&PerformanceFreq))
297 Con_Printf ("No hardware timer available\n");
298 // fall back to timeGetTime
299 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
300 return Sys_DoubleTime();
302 QueryPerformanceCounter (&PerformanceCount);
305 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
306 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
308 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
309 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
314 #if HAVE_CLOCKGETTIME
315 else if (sys_useclockgettime.integer)
318 # ifdef CLOCK_MONOTONIC
320 clock_gettime(CLOCK_MONOTONIC, &ts);
323 clock_gettime(CLOCK_HIGHRES, &ts);
325 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
329 // now all the FALLBACK timers
330 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
332 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
334 #if HAVE_GETTIMEOFDAY
338 gettimeofday(&tp, NULL);
339 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
341 #elif HAVE_TIMEGETTIME
344 static int firsttimegettime = true;
347 // Windows 95/98/ME/NT/2000/XP
349 // reasonable accuracy (millisecond)
351 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
353 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
354 if (firsttimegettime)
357 firsttimegettime = false;
360 newtime = (double) timeGetTime () / 1000.0;
363 // fallback for using the SDL timer if no other timer is available
366 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
367 // this calls Sys_Error() if not linking against SDL
377 if (newtime < oldtime)
379 // warn if it's significant
380 if (newtime - oldtime < -0.01)
381 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
383 else if (newtime > oldtime + 1800)
385 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
388 curtime += newtime - oldtime;
394 void Sys_Sleep(int microseconds)
397 if(sys_usenoclockbutbenchmark.integer)
399 benchmark_time += microseconds;
402 if(sys_debugsleep.integer)
404 t = Sys_DoubleTime();
406 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
408 Sys_SDL_Delay(microseconds / 1000);
414 tv.tv_sec = microseconds / 1000000;
415 tv.tv_usec = microseconds % 1000000;
416 select(0, NULL, NULL, NULL, &tv);
421 usleep(microseconds);
426 Sleep(microseconds / 1000);
431 Sys_SDL_Delay(microseconds / 1000);
434 if(sys_debugsleep.integer)
436 t = Sys_DoubleTime() - t;
437 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
441 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
443 const char *p = PATH;
447 while((q = strchr(p, ':')))
449 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
450 if(FS_SysFileExists(buf))
454 if(!q) // none found - try the last item
456 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
457 if(FS_SysFileExists(buf))
464 const char *Sys_FindExecutableName(void)
469 static char exenamebuf[MAX_OSPATH+1];
471 #if defined(__FreeBSD__)
472 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
473 #elif defined(__linux__)
474 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
476 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
481 if(strchr(com_argv[0], '/'))
482 return com_argv[0]; // possibly a relative path
484 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
488 void Sys_ProvideSelfFD(void)
492 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);