7 # include <mmsystem.h> // timeGetTime
8 # include <time.h> // localtime
10 #pragma comment(lib, "winmm.lib")
15 # include <sys/time.h>
22 static char sys_timestring[128];
23 char *Sys_TimeString(const char *timeformat)
25 time_t mytime = time(NULL);
28 localtime_s(&mytm, &mytime);
29 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
31 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
33 return sys_timestring;
37 extern qboolean host_shuttingdown;
38 void Sys_Quit (int returnvalue)
40 if (COM_CheckParm("-profilegameonly"))
41 Sys_AllowProfiling(false);
42 host_shuttingdown = true;
47 #if defined(__linux__) || defined(__FreeBSD__)
54 void Sys_AllowProfiling(qboolean enable)
56 #if defined(__linux__) || defined(__FreeBSD__)
63 ===============================================================================
67 ===============================================================================
70 static qboolean Sys_LoadLibraryFunctions(dllhandle_t dllhandle, const dllfunction_t *fcts, qboolean complain, qboolean has_next)
72 const dllfunction_t *func;
75 for (func = fcts; func && func->name != NULL; func++)
76 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
80 Con_DPrintf (" - missing function \"%s\" - broken library!", func->name);
82 Con_DPrintf("\nContinuing with");
89 for (func = fcts; func && func->name != NULL; func++)
90 *func->funcvariable = NULL;
95 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
98 const dllfunction_t *func;
99 dllhandle_t dllhandle = 0;
106 #ifdef PREFER_PRELOAD
107 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
108 if(Sys_LoadLibraryFunctions(dllhandle, fcts, false, false))
110 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
115 Sys_UnloadLibrary(&dllhandle);
121 for (func = fcts; func && func->name != NULL; func++)
122 *func->funcvariable = NULL;
124 // Try every possible name
125 Con_DPrintf ("Trying to load library...");
126 for (i = 0; dllnames[i] != NULL; i++)
128 Con_DPrintf (" \"%s\"", dllnames[i]);
130 dllhandle = LoadLibrary (dllnames[i]);
132 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
134 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, (dllnames[i+1] != NULL) || (strrchr(com_argv[0], '/'))))
137 Sys_UnloadLibrary (&dllhandle);
140 // see if the names can be loaded relative to the executable path
141 // (this is for Mac OSX which does not check next to the executable)
142 if (!dllhandle && strrchr(com_argv[0], '/'))
144 char path[MAX_OSPATH];
145 strlcpy(path, com_argv[0], sizeof(path));
146 strrchr(path, '/')[1] = 0;
147 for (i = 0; dllnames[i] != NULL; i++)
149 char temp[MAX_OSPATH];
150 strlcpy(temp, path, sizeof(temp));
151 strlcat(temp, dllnames[i], sizeof(temp));
152 Con_DPrintf (" \"%s\"", temp);
154 dllhandle = LoadLibrary (temp);
156 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
158 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, dllnames[i+1] != NULL))
161 Sys_UnloadLibrary (&dllhandle);
168 Con_DPrintf(" - failed.\n");
172 Con_DPrintf(" - loaded.\n");
181 void Sys_UnloadLibrary (dllhandle_t* handle)
184 if (handle == NULL || *handle == NULL)
188 FreeLibrary (*handle);
197 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
201 return (void *)GetProcAddress (handle, name);
203 return (void *)dlsym (handle, name);
211 # define HAVE_TIMEGETTIME 1
212 # define HAVE_QUERYPERFORMANCECOUNTER 1
213 # define HAVE_Sleep 1
216 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
217 # define HAVE_CLOCKGETTIME 1
221 // FIXME improve this check, manpage hints to DST_NONE
222 # define HAVE_GETTIMEOFDAY 1
226 # define HAVE_SELECT 1
230 // FIXME improve this check
231 # define HAVE_USLEEP 1
234 // this one is referenced elsewhere
235 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."};
238 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
239 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
240 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
241 #if HAVE_QUERYPERFORMANCECOUNTER
242 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)"};
244 #if HAVE_CLOCKGETTIME
245 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)"};
248 static unsigned long benchmark_time;
250 void Sys_Init_Commands (void)
252 Cvar_RegisterVariable(&sys_debugsleep);
253 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
254 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
255 if(sys_supportsdlgetticks)
257 Cvar_RegisterVariable(&sys_usesdlgetticks);
258 Cvar_RegisterVariable(&sys_usesdldelay);
261 #if HAVE_QUERYPERFORMANCECOUNTER
262 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
264 #if HAVE_CLOCKGETTIME
265 Cvar_RegisterVariable(&sys_useclockgettime);
269 double Sys_DoubleTime(void)
271 static int first = true;
272 static double oldtime = 0.0, curtime = 0.0;
274 if(sys_usenoclockbutbenchmark.integer)
277 return ((double) benchmark_time) / 1e6;
280 // first all the OPTIONAL timers
282 #if HAVE_QUERYPERFORMANCECOUNTER
283 else if (sys_usequeryperformancecounter.integer)
285 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
286 // QueryPerformanceCounter
288 // Windows 95/98/ME/NT/2000/XP
290 // very accurate (CPU cycles)
292 // does not necessarily match realtime too well (tends to get faster and faster in win98)
293 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
295 LARGE_INTEGER PerformanceFreq;
296 LARGE_INTEGER PerformanceCount;
298 if (!QueryPerformanceFrequency (&PerformanceFreq))
300 Con_Printf ("No hardware timer available\n");
301 // fall back to timeGetTime
302 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
303 return Sys_DoubleTime();
305 QueryPerformanceCounter (&PerformanceCount);
308 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
309 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
311 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
312 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
317 #if HAVE_CLOCKGETTIME
318 else if (sys_useclockgettime.integer)
321 # ifdef CLOCK_MONOTONIC
323 clock_gettime(CLOCK_MONOTONIC, &ts);
326 clock_gettime(CLOCK_HIGHRES, &ts);
328 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
332 // now all the FALLBACK timers
333 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
335 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
337 #if HAVE_GETTIMEOFDAY
341 gettimeofday(&tp, NULL);
342 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
344 #elif HAVE_TIMEGETTIME
347 static int firsttimegettime = true;
350 // Windows 95/98/ME/NT/2000/XP
352 // reasonable accuracy (millisecond)
354 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
356 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
357 if (firsttimegettime)
360 firsttimegettime = false;
363 newtime = (double) timeGetTime () / 1000.0;
366 // fallback for using the SDL timer if no other timer is available
369 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
370 // this calls Sys_Error() if not linking against SDL
380 if (newtime < oldtime)
382 // warn if it's significant
383 if (newtime - oldtime < -0.01)
384 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
386 else if (newtime > oldtime + 1800)
388 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
391 curtime += newtime - oldtime;
397 void Sys_Sleep(int microseconds)
400 if(sys_usenoclockbutbenchmark.integer)
402 benchmark_time += microseconds;
405 if(sys_debugsleep.integer)
407 t = Sys_DoubleTime();
409 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
411 Sys_SDL_Delay(microseconds / 1000);
417 tv.tv_sec = microseconds / 1000000;
418 tv.tv_usec = microseconds % 1000000;
419 select(0, NULL, NULL, NULL, &tv);
424 usleep(microseconds);
429 Sleep(microseconds / 1000);
434 Sys_SDL_Delay(microseconds / 1000);
437 if(sys_debugsleep.integer)
439 t = Sys_DoubleTime() - t;
440 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
444 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
446 const char *p = PATH;
450 while((q = strchr(p, ':')))
452 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
453 if(FS_SysFileExists(buf))
457 if(!q) // none found - try the last item
459 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
460 if(FS_SysFileExists(buf))
467 const char *Sys_FindExecutableName(void)
472 static char exenamebuf[MAX_OSPATH+1];
474 #if defined(__FreeBSD__)
475 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
476 #elif defined(__linux__)
477 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
479 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
484 if(strchr(com_argv[0], '/'))
485 return com_argv[0]; // possibly a relative path
487 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
491 void Sys_ProvideSelfFD(void)
495 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);