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 // on Win32, select() cannot be used with all three FD list args being NULL according to MSDN
234 // (so much for POSIX...)
236 # define HAVE_SELECT 1
241 // FIXME improve this check
242 # define HAVE_USLEEP 1
245 // this one is referenced elsewhere
246 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."};
249 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
250 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
251 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
252 #if HAVE_QUERYPERFORMANCECOUNTER
253 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)"};
255 #if HAVE_CLOCKGETTIME
256 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)"};
259 static unsigned long benchmark_time;
261 void Sys_Init_Commands (void)
263 Cvar_RegisterVariable(&sys_debugsleep);
264 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
265 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
266 if(sys_supportsdlgetticks)
268 Cvar_RegisterVariable(&sys_usesdlgetticks);
269 Cvar_RegisterVariable(&sys_usesdldelay);
272 #if HAVE_QUERYPERFORMANCECOUNTER
273 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
275 #if HAVE_CLOCKGETTIME
276 Cvar_RegisterVariable(&sys_useclockgettime);
280 double Sys_DoubleTime(void)
282 static int first = true;
283 static double oldtime = 0.0, curtime = 0.0;
285 if(sys_usenoclockbutbenchmark.integer)
288 return ((double) benchmark_time) / 1e6;
291 // first all the OPTIONAL timers
293 #if HAVE_QUERYPERFORMANCECOUNTER
294 else if (sys_usequeryperformancecounter.integer)
296 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
297 // QueryPerformanceCounter
299 // Windows 95/98/ME/NT/2000/XP
301 // very accurate (CPU cycles)
303 // does not necessarily match realtime too well (tends to get faster and faster in win98)
304 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
306 LARGE_INTEGER PerformanceFreq;
307 LARGE_INTEGER PerformanceCount;
309 if (!QueryPerformanceFrequency (&PerformanceFreq))
311 Con_Printf ("No hardware timer available\n");
312 // fall back to timeGetTime
313 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
314 return Sys_DoubleTime();
316 QueryPerformanceCounter (&PerformanceCount);
319 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
320 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
322 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
323 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
328 #if HAVE_CLOCKGETTIME
329 else if (sys_useclockgettime.integer)
332 # ifdef CLOCK_MONOTONIC
334 clock_gettime(CLOCK_MONOTONIC, &ts);
337 clock_gettime(CLOCK_HIGHRES, &ts);
339 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
343 // now all the FALLBACK timers
344 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
346 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
348 #if HAVE_GETTIMEOFDAY
352 gettimeofday(&tp, NULL);
353 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
355 #elif HAVE_TIMEGETTIME
358 static int firsttimegettime = true;
361 // Windows 95/98/ME/NT/2000/XP
363 // reasonable accuracy (millisecond)
365 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
367 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
368 if (firsttimegettime)
371 firsttimegettime = false;
374 newtime = (double) timeGetTime () / 1000.0;
377 // fallback for using the SDL timer if no other timer is available
380 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
381 // this calls Sys_Error() if not linking against SDL
391 if (newtime < oldtime)
393 // warn if it's significant
394 if (newtime - oldtime < -0.01)
395 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
397 else if (newtime > oldtime + 1800)
399 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
402 curtime += newtime - oldtime;
408 void Sys_Sleep(int microseconds)
411 if(sys_usenoclockbutbenchmark.integer)
413 benchmark_time += microseconds;
416 if(sys_debugsleep.integer)
418 t = Sys_DoubleTime();
420 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
422 Sys_SDL_Delay(microseconds / 1000);
428 tv.tv_sec = microseconds / 1000000;
429 tv.tv_usec = microseconds % 1000000;
430 select(0, NULL, NULL, NULL, &tv);
435 usleep(microseconds);
440 Sleep(microseconds / 1000);
445 Sys_SDL_Delay(microseconds / 1000);
448 if(sys_debugsleep.integer)
450 t = Sys_DoubleTime() - t;
451 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
455 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
457 const char *p = PATH;
461 while((q = strchr(p, ':')))
463 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
464 if(FS_SysFileExists(buf))
468 if(!q) // none found - try the last item
470 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
471 if(FS_SysFileExists(buf))
478 const char *Sys_FindExecutableName(void)
483 static char exenamebuf[MAX_OSPATH+1];
485 #if defined(__FreeBSD__)
486 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
487 #elif defined(__linux__)
488 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
490 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
495 if(strchr(com_argv[0], '/'))
496 return com_argv[0]; // possibly a relative path
498 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
502 void Sys_ProvideSelfFD(void)
506 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);