7 # define _WIN32_WINNT 0x0502
11 # include <mmsystem.h> // timeGetTime
12 # include <time.h> // localtime
16 # include <sys/time.h>
23 static char sys_timestring[128];
24 char *Sys_TimeString(const char *timeformat)
26 time_t mytime = time(NULL);
29 localtime_s(&mytm, &mytime);
30 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
32 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
34 return sys_timestring;
38 extern qboolean host_shuttingdown;
39 void Sys_Quit (int returnvalue)
41 if (COM_CheckParm("-profilegameonly"))
42 Sys_AllowProfiling(false);
43 host_shuttingdown = true;
48 #if defined(__linux__) || defined(__FreeBSD__)
55 void Sys_AllowProfiling(qboolean enable)
57 #if defined(__linux__) || defined(__FreeBSD__)
64 ===============================================================================
68 ===============================================================================
71 static qboolean Sys_LoadLibraryFunctions(dllhandle_t dllhandle, const dllfunction_t *fcts, qboolean complain, qboolean has_next)
73 const dllfunction_t *func;
76 for (func = fcts; func && func->name != NULL; func++)
77 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
81 Con_DPrintf (" - missing function \"%s\" - broken library!", func->name);
83 Con_DPrintf("\nContinuing with");
90 for (func = fcts; func && func->name != NULL; func++)
91 *func->funcvariable = NULL;
96 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
99 const dllfunction_t *func;
100 dllhandle_t dllhandle = 0;
107 #ifdef PREFER_PRELOAD
108 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
109 if(Sys_LoadLibraryFunctions(dllhandle, fcts, false, false))
111 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
116 Sys_UnloadLibrary(&dllhandle);
122 for (func = fcts; func && func->name != NULL; func++)
123 *func->funcvariable = NULL;
125 // Try every possible name
126 Con_DPrintf ("Trying to load library...");
127 for (i = 0; dllnames[i] != NULL; i++)
129 Con_DPrintf (" \"%s\"", dllnames[i]);
132 SetDllDirectory("bin64");
134 dllhandle = LoadLibrary (dllnames[i]);
136 SetDllDirectory(NULL);
139 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
141 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, (dllnames[i+1] != NULL) || (strrchr(com_argv[0], '/'))))
144 Sys_UnloadLibrary (&dllhandle);
147 // see if the names can be loaded relative to the executable path
148 // (this is for Mac OSX which does not check next to the executable)
149 if (!dllhandle && strrchr(com_argv[0], '/'))
151 char path[MAX_OSPATH];
152 strlcpy(path, com_argv[0], sizeof(path));
153 strrchr(path, '/')[1] = 0;
154 for (i = 0; dllnames[i] != NULL; i++)
156 char temp[MAX_OSPATH];
157 strlcpy(temp, path, sizeof(temp));
158 strlcat(temp, dllnames[i], sizeof(temp));
159 Con_DPrintf (" \"%s\"", temp);
161 dllhandle = LoadLibrary (temp);
163 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
165 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, dllnames[i+1] != NULL))
168 Sys_UnloadLibrary (&dllhandle);
175 Con_DPrintf(" - failed.\n");
179 Con_DPrintf(" - loaded.\n");
188 void Sys_UnloadLibrary (dllhandle_t* handle)
191 if (handle == NULL || *handle == NULL)
195 FreeLibrary (*handle);
204 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
208 return (void *)GetProcAddress (handle, name);
210 return (void *)dlsym (handle, name);
218 # define HAVE_TIMEGETTIME 1
219 # define HAVE_QUERYPERFORMANCECOUNTER 1
220 # define HAVE_Sleep 1
223 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
224 # define HAVE_CLOCKGETTIME 1
228 // FIXME improve this check, manpage hints to DST_NONE
229 # define HAVE_GETTIMEOFDAY 1
233 # define HAVE_SELECT 1
237 // FIXME improve this check
238 # define HAVE_USLEEP 1
241 // this one is referenced elsewhere
242 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."};
245 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
246 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
247 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
248 #if HAVE_QUERYPERFORMANCECOUNTER
249 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)"};
251 #if HAVE_CLOCKGETTIME
252 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)"};
255 static unsigned long benchmark_time;
257 void Sys_Init_Commands (void)
259 Cvar_RegisterVariable(&sys_debugsleep);
260 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
261 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
262 if(sys_supportsdlgetticks)
264 Cvar_RegisterVariable(&sys_usesdlgetticks);
265 Cvar_RegisterVariable(&sys_usesdldelay);
268 #if HAVE_QUERYPERFORMANCECOUNTER
269 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
271 #if HAVE_CLOCKGETTIME
272 Cvar_RegisterVariable(&sys_useclockgettime);
276 double Sys_DoubleTime(void)
278 static int first = true;
279 static double oldtime = 0.0, curtime = 0.0;
281 if(sys_usenoclockbutbenchmark.integer)
284 return ((double) benchmark_time) / 1e6;
287 // first all the OPTIONAL timers
289 #if HAVE_QUERYPERFORMANCECOUNTER
290 else if (sys_usequeryperformancecounter.integer)
292 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
293 // QueryPerformanceCounter
295 // Windows 95/98/ME/NT/2000/XP
297 // very accurate (CPU cycles)
299 // does not necessarily match realtime too well (tends to get faster and faster in win98)
300 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
302 LARGE_INTEGER PerformanceFreq;
303 LARGE_INTEGER PerformanceCount;
305 if (!QueryPerformanceFrequency (&PerformanceFreq))
307 Con_Printf ("No hardware timer available\n");
308 // fall back to timeGetTime
309 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
310 return Sys_DoubleTime();
312 QueryPerformanceCounter (&PerformanceCount);
315 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
316 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
318 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
319 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
324 #if HAVE_CLOCKGETTIME
325 else if (sys_useclockgettime.integer)
328 # ifdef CLOCK_MONOTONIC
330 clock_gettime(CLOCK_MONOTONIC, &ts);
333 clock_gettime(CLOCK_HIGHRES, &ts);
335 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
339 // now all the FALLBACK timers
340 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
342 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
344 #if HAVE_GETTIMEOFDAY
348 gettimeofday(&tp, NULL);
349 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
351 #elif HAVE_TIMEGETTIME
354 static int firsttimegettime = true;
357 // Windows 95/98/ME/NT/2000/XP
359 // reasonable accuracy (millisecond)
361 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
363 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
364 if (firsttimegettime)
367 firsttimegettime = false;
370 newtime = (double) timeGetTime () / 1000.0;
373 // fallback for using the SDL timer if no other timer is available
376 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
377 // this calls Sys_Error() if not linking against SDL
387 if (newtime < oldtime)
389 // warn if it's significant
390 if (newtime - oldtime < -0.01)
391 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
393 else if (newtime > oldtime + 1800)
395 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
398 curtime += newtime - oldtime;
404 void Sys_Sleep(int microseconds)
407 if(sys_usenoclockbutbenchmark.integer)
409 benchmark_time += microseconds;
412 if(sys_debugsleep.integer)
414 t = Sys_DoubleTime();
416 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
418 Sys_SDL_Delay(microseconds / 1000);
424 tv.tv_sec = microseconds / 1000000;
425 tv.tv_usec = microseconds % 1000000;
426 select(0, NULL, NULL, NULL, &tv);
431 usleep(microseconds);
436 Sleep(microseconds / 1000);
441 Sys_SDL_Delay(microseconds / 1000);
444 if(sys_debugsleep.integer)
446 t = Sys_DoubleTime() - t;
447 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
451 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
453 const char *p = PATH;
457 while((q = strchr(p, ':')))
459 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
460 if(FS_SysFileExists(buf))
464 if(!q) // none found - try the last item
466 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
467 if(FS_SysFileExists(buf))
474 const char *Sys_FindExecutableName(void)
479 static char exenamebuf[MAX_OSPATH+1];
481 #if defined(__FreeBSD__)
482 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
483 #elif defined(__linux__)
484 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
486 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
491 if(strchr(com_argv[0], '/'))
492 return com_argv[0]; // possibly a relative path
494 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
498 void Sys_ProvideSelfFD(void)
502 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);