7 # define _WIN32_WINNT 0x0502
11 # include <mmsystem.h> // timeGetTime
12 # include <time.h> // localtime
14 #pragma comment(lib, "winmm.lib")
19 # include <sys/time.h>
26 static char sys_timestring[128];
27 char *Sys_TimeString(const char *timeformat)
29 time_t mytime = time(NULL);
32 localtime_s(&mytm, &mytime);
33 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
35 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
37 return sys_timestring;
41 extern qboolean host_shuttingdown;
42 void Sys_Quit (int returnvalue)
44 if (COM_CheckParm("-profilegameonly"))
45 Sys_AllowProfiling(false);
46 host_shuttingdown = true;
51 #if defined(__linux__) || defined(__FreeBSD__)
58 void Sys_AllowProfiling(qboolean enable)
60 #if defined(__linux__) || defined(__FreeBSD__)
67 ===============================================================================
71 ===============================================================================
74 static qboolean Sys_LoadLibraryFunctions(dllhandle_t dllhandle, const dllfunction_t *fcts, qboolean complain, qboolean has_next)
76 const dllfunction_t *func;
79 for (func = fcts; func && func->name != NULL; func++)
80 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
84 Con_DPrintf (" - missing function \"%s\" - broken library!", func->name);
86 Con_DPrintf("\nContinuing with");
93 for (func = fcts; func && func->name != NULL; func++)
94 *func->funcvariable = NULL;
99 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
102 const dllfunction_t *func;
103 dllhandle_t dllhandle = 0;
110 #ifdef PREFER_PRELOAD
111 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
112 if(Sys_LoadLibraryFunctions(dllhandle, fcts, false, false))
114 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
119 Sys_UnloadLibrary(&dllhandle);
125 for (func = fcts; func && func->name != NULL; func++)
126 *func->funcvariable = NULL;
128 // Try every possible name
129 Con_DPrintf ("Trying to load library...");
130 for (i = 0; dllnames[i] != NULL; i++)
132 Con_DPrintf (" \"%s\"", dllnames[i]);
135 SetDllDirectory("bin64");
137 dllhandle = LoadLibrary (dllnames[i]);
139 SetDllDirectory(NULL);
142 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
144 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, (dllnames[i+1] != NULL) || (strrchr(com_argv[0], '/'))))
147 Sys_UnloadLibrary (&dllhandle);
150 // see if the names can be loaded relative to the executable path
151 // (this is for Mac OSX which does not check next to the executable)
152 if (!dllhandle && strrchr(com_argv[0], '/'))
154 char path[MAX_OSPATH];
155 strlcpy(path, com_argv[0], sizeof(path));
156 strrchr(path, '/')[1] = 0;
157 for (i = 0; dllnames[i] != NULL; i++)
159 char temp[MAX_OSPATH];
160 strlcpy(temp, path, sizeof(temp));
161 strlcat(temp, dllnames[i], sizeof(temp));
162 Con_DPrintf (" \"%s\"", temp);
164 dllhandle = LoadLibrary (temp);
166 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
168 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, dllnames[i+1] != NULL))
171 Sys_UnloadLibrary (&dllhandle);
178 Con_DPrintf(" - failed.\n");
182 Con_DPrintf(" - loaded.\n");
191 void Sys_UnloadLibrary (dllhandle_t* handle)
194 if (handle == NULL || *handle == NULL)
198 FreeLibrary (*handle);
207 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
211 return (void *)GetProcAddress (handle, name);
213 return (void *)dlsym (handle, name);
221 # define HAVE_TIMEGETTIME 1
222 # define HAVE_QUERYPERFORMANCECOUNTER 1
223 # define HAVE_Sleep 1
226 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
227 # define HAVE_CLOCKGETTIME 1
231 // FIXME improve this check, manpage hints to DST_NONE
232 # define HAVE_GETTIMEOFDAY 1
236 # define HAVE_SELECT 1
240 // FIXME improve this check
241 # define HAVE_USLEEP 1
244 // this one is referenced elsewhere
245 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."};
248 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
249 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
250 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
251 #if HAVE_QUERYPERFORMANCECOUNTER
252 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)"};
254 #if HAVE_CLOCKGETTIME
255 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)"};
258 static unsigned long benchmark_time;
260 void Sys_Init_Commands (void)
262 Cvar_RegisterVariable(&sys_debugsleep);
263 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
264 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
265 if(sys_supportsdlgetticks)
267 Cvar_RegisterVariable(&sys_usesdlgetticks);
268 Cvar_RegisterVariable(&sys_usesdldelay);
271 #if HAVE_QUERYPERFORMANCECOUNTER
272 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
274 #if HAVE_CLOCKGETTIME
275 Cvar_RegisterVariable(&sys_useclockgettime);
279 double Sys_DoubleTime(void)
281 static int first = true;
282 static double oldtime = 0.0, curtime = 0.0;
284 if(sys_usenoclockbutbenchmark.integer)
287 return ((double) benchmark_time) / 1e6;
290 // first all the OPTIONAL timers
292 #if HAVE_QUERYPERFORMANCECOUNTER
293 else if (sys_usequeryperformancecounter.integer)
295 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
296 // QueryPerformanceCounter
298 // Windows 95/98/ME/NT/2000/XP
300 // very accurate (CPU cycles)
302 // does not necessarily match realtime too well (tends to get faster and faster in win98)
303 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
305 LARGE_INTEGER PerformanceFreq;
306 LARGE_INTEGER PerformanceCount;
308 if (!QueryPerformanceFrequency (&PerformanceFreq))
310 Con_Printf ("No hardware timer available\n");
311 // fall back to timeGetTime
312 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
313 return Sys_DoubleTime();
315 QueryPerformanceCounter (&PerformanceCount);
318 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
319 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
321 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
322 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
327 #if HAVE_CLOCKGETTIME
328 else if (sys_useclockgettime.integer)
331 # ifdef CLOCK_MONOTONIC
333 clock_gettime(CLOCK_MONOTONIC, &ts);
336 clock_gettime(CLOCK_HIGHRES, &ts);
338 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
342 // now all the FALLBACK timers
343 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
345 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
347 #if HAVE_GETTIMEOFDAY
351 gettimeofday(&tp, NULL);
352 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
354 #elif HAVE_TIMEGETTIME
357 static int firsttimegettime = true;
360 // Windows 95/98/ME/NT/2000/XP
362 // reasonable accuracy (millisecond)
364 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
366 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
367 if (firsttimegettime)
370 firsttimegettime = false;
373 newtime = (double) timeGetTime () / 1000.0;
376 // fallback for using the SDL timer if no other timer is available
379 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
380 // this calls Sys_Error() if not linking against SDL
390 if (newtime < oldtime)
392 // warn if it's significant
393 if (newtime - oldtime < -0.01)
394 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
396 else if (newtime > oldtime + 1800)
398 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
401 curtime += newtime - oldtime;
407 void Sys_Sleep(int microseconds)
410 if(sys_usenoclockbutbenchmark.integer)
412 benchmark_time += microseconds;
415 if(sys_debugsleep.integer)
417 t = Sys_DoubleTime();
419 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
421 Sys_SDL_Delay(microseconds / 1000);
427 tv.tv_sec = microseconds / 1000000;
428 tv.tv_usec = microseconds % 1000000;
429 select(0, NULL, NULL, NULL, &tv);
434 usleep(microseconds);
439 Sleep(microseconds / 1000);
444 Sys_SDL_Delay(microseconds / 1000);
447 if(sys_debugsleep.integer)
449 t = Sys_DoubleTime() - t;
450 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
454 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
456 const char *p = PATH;
460 while((q = strchr(p, ':')))
462 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
463 if(FS_SysFileExists(buf))
467 if(!q) // none found - try the last item
469 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
470 if(FS_SysFileExists(buf))
477 const char *Sys_FindExecutableName(void)
482 static char exenamebuf[MAX_OSPATH+1];
484 #if defined(__FreeBSD__)
485 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
486 #elif defined(__linux__)
487 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
489 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
494 if(strchr(com_argv[0], '/'))
495 return com_argv[0]; // possibly a relative path
497 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
501 void Sys_ProvideSelfFD(void)
505 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);