7 # include <mmsystem.h> // timeGetTime
8 # include <time.h> // localtime
9 #pragma comment(lib, "winmm.lib")
13 # include <sys/time.h>
20 static char sys_timestring[128];
21 char *Sys_TimeString(const char *timeformat)
23 time_t mytime = time(NULL);
26 localtime_s(&mytm, &mytime);
27 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
29 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
31 return sys_timestring;
35 extern qboolean host_shuttingdown;
36 void Sys_Quit (int returnvalue)
38 if (COM_CheckParm("-profilegameonly"))
39 Sys_AllowProfiling(false);
40 host_shuttingdown = true;
45 #if defined(__linux__) || defined(__FreeBSD__)
52 void Sys_AllowProfiling(qboolean enable)
54 #if defined(__linux__) || defined(__FreeBSD__)
61 ===============================================================================
65 ===============================================================================
68 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
71 const dllfunction_t *func;
72 dllhandle_t dllhandle = 0;
80 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
83 for (func = fcts; func && func->name != NULL; func++)
84 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
89 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
98 for (func = fcts; func && func->name != NULL; func++)
99 *func->funcvariable = NULL;
101 // Try every possible name
102 Con_DPrintf ("Trying to load library...");
103 for (i = 0; dllnames[i] != NULL; i++)
105 Con_DPrintf (" \"%s\"", dllnames[i]);
107 dllhandle = LoadLibrary (dllnames[i]);
109 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
115 // see if the names can be loaded relative to the executable path
116 // (this is for Mac OSX which does not check next to the executable)
117 if (!dllhandle && strrchr(com_argv[0], '/'))
119 char path[MAX_OSPATH];
120 strlcpy(path, com_argv[0], sizeof(path));
121 strrchr(path, '/')[1] = 0;
122 for (i = 0; dllnames[i] != NULL; i++)
124 char temp[MAX_OSPATH];
125 strlcpy(temp, path, sizeof(temp));
126 strlcat(temp, dllnames[i], sizeof(temp));
127 Con_DPrintf (" \"%s\"", temp);
129 dllhandle = LoadLibrary (temp);
131 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
141 Con_DPrintf(" - failed.\n");
145 Con_DPrintf(" - loaded.\n");
147 // Get the function adresses
148 for (func = fcts; func && func->name != NULL; func++)
149 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
151 Con_DPrintf ("Missing function \"%s\" - broken library!\n", func->name);
152 Sys_UnloadLibrary (&dllhandle);
163 void Sys_UnloadLibrary (dllhandle_t* handle)
166 if (handle == NULL || *handle == NULL)
170 FreeLibrary (*handle);
179 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
183 return (void *)GetProcAddress (handle, name);
185 return (void *)dlsym (handle, name);
193 # define HAVE_TIMEGETTIME 1
194 # define HAVE_QUERYPERFORMANCECOUNTER 1
195 # define HAVE_Sleep 1
198 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
199 # define HAVE_CLOCKGETTIME 1
203 // FIXME improve this check, manpage hints to DST_NONE
204 # define HAVE_GETTIMEOFDAY 1
208 # define HAVE_SELECT 1
212 // FIXME improve this check
213 # define HAVE_USLEEP 1
216 // this one is referenced elsewhere
217 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."};
220 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
221 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
222 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
223 #if HAVE_QUERYPERFORMANCECOUNTER
224 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)"};
226 #if HAVE_CLOCKGETTIME
227 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)"};
230 static unsigned long benchmark_time;
232 void Sys_Init_Commands (void)
234 Cvar_RegisterVariable(&sys_debugsleep);
235 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
236 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
237 if(sys_supportsdlgetticks)
239 Cvar_RegisterVariable(&sys_usesdlgetticks);
240 Cvar_RegisterVariable(&sys_usesdldelay);
243 #if HAVE_QUERYPERFORMANCECOUNTER
244 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
246 #if HAVE_CLOCKGETTIME
247 Cvar_RegisterVariable(&sys_useclockgettime);
251 double Sys_DoubleTime(void)
253 static int first = true;
254 static double oldtime = 0.0, curtime = 0.0;
256 if(sys_usenoclockbutbenchmark.integer)
259 return ((double) benchmark_time) / 1e6;
262 // first all the OPTIONAL timers
264 #if HAVE_QUERYPERFORMANCECOUNTER
265 else if (sys_usequeryperformancecounter.integer)
267 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
268 // QueryPerformanceCounter
270 // Windows 95/98/ME/NT/2000/XP
272 // very accurate (CPU cycles)
274 // does not necessarily match realtime too well (tends to get faster and faster in win98)
275 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
277 LARGE_INTEGER PerformanceFreq;
278 LARGE_INTEGER PerformanceCount;
280 if (!QueryPerformanceFrequency (&PerformanceFreq))
282 Con_Printf ("No hardware timer available\n");
283 // fall back to timeGetTime
284 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
285 return Sys_DoubleTime();
287 QueryPerformanceCounter (&PerformanceCount);
290 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
291 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
293 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
294 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
299 #if HAVE_CLOCKGETTIME
300 else if (sys_useclockgettime.integer)
303 # ifdef CLOCK_MONOTONIC
305 clock_gettime(CLOCK_MONOTONIC, &ts);
308 clock_gettime(CLOCK_HIGHRES, &ts);
310 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
314 // now all the FALLBACK timers
315 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
317 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
319 #if HAVE_GETTIMEOFDAY
323 gettimeofday(&tp, NULL);
324 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
326 #elif HAVE_TIMEGETTIME
329 static int firsttimegettime = true;
332 // Windows 95/98/ME/NT/2000/XP
334 // reasonable accuracy (millisecond)
336 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
338 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
339 if (firsttimegettime)
342 firsttimegettime = false;
345 newtime = (double) timeGetTime () / 1000.0;
348 // fallback for using the SDL timer if no other timer is available
351 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
352 // this calls Sys_Error() if not linking against SDL
362 if (newtime < oldtime)
364 // warn if it's significant
365 if (newtime - oldtime < -0.01)
366 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
368 else if (newtime > oldtime + 1800)
370 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
373 curtime += newtime - oldtime;
379 void Sys_Sleep(int microseconds)
382 if(sys_usenoclockbutbenchmark.integer)
384 benchmark_time += microseconds;
387 if(sys_debugsleep.integer)
389 t = Sys_DoubleTime();
391 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
393 Sys_SDL_Delay(microseconds / 1000);
399 tv.tv_sec = microseconds / 1000000;
400 tv.tv_usec = microseconds % 1000000;
401 select(0, NULL, NULL, NULL, &tv);
406 usleep(microseconds);
411 Sleep(microseconds / 1000);
416 Sys_SDL_Delay(microseconds / 1000);
419 if(sys_debugsleep.integer)
421 t = Sys_DoubleTime() - t;
422 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
426 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
428 const char *p = PATH;
432 while((q = strchr(p, ':')))
434 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
435 if(FS_SysFileExists(buf))
439 if(!q) // none found - try the last item
441 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
442 if(FS_SysFileExists(buf))
449 const char *Sys_FindExecutableName(void)
454 static char exenamebuf[MAX_OSPATH+1];
456 #if defined(__FreeBSD__)
457 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
458 #elif defined(__linux__)
459 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
461 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
466 if(strchr(com_argv[0], '/'))
467 return com_argv[0]; // possibly a relative path
469 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
473 void Sys_ProvideSelfFD(void)
477 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);