7 # define _WIN32_WINNT 0x0502
11 # include <mmsystem.h> // timeGetTime
12 # include <time.h> // localtime
13 #pragma comment(lib, "winmm.lib")
17 # include <sys/time.h>
24 static char sys_timestring[128];
25 char *Sys_TimeString(const char *timeformat)
27 time_t mytime = time(NULL);
30 localtime_s(&mytm, &mytime);
31 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
33 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
35 return sys_timestring;
39 extern qboolean host_shuttingdown;
40 void Sys_Quit (int returnvalue)
42 if (COM_CheckParm("-profilegameonly"))
43 Sys_AllowProfiling(false);
44 host_shuttingdown = true;
49 #if defined(__linux__) || defined(__FreeBSD__)
56 void Sys_AllowProfiling(qboolean enable)
58 #if defined(__linux__) || defined(__FreeBSD__)
65 ===============================================================================
69 ===============================================================================
72 static qboolean Sys_LoadLibraryFunctions(dllhandle_t dllhandle, const dllfunction_t *fcts, qboolean complain, qboolean has_next)
74 const dllfunction_t *func;
77 for (func = fcts; func && func->name != NULL; func++)
78 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
82 Con_DPrintf (" - missing function \"%s\" - broken library!", func->name);
84 Con_DPrintf("\nContinuing with");
91 for (func = fcts; func && func->name != NULL; func++)
92 *func->funcvariable = NULL;
97 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
100 const dllfunction_t *func;
101 dllhandle_t dllhandle = 0;
108 #ifdef PREFER_PRELOAD
109 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
110 if(Sys_LoadLibraryFunctions(dllhandle, fcts, false, false))
112 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
117 Sys_UnloadLibrary(&dllhandle);
123 for (func = fcts; func && func->name != NULL; func++)
124 *func->funcvariable = NULL;
126 // Try every possible name
127 Con_DPrintf ("Trying to load library...");
128 for (i = 0; dllnames[i] != NULL; i++)
130 Con_DPrintf (" \"%s\"", dllnames[i]);
133 SetDllDirectory("bin64");
135 dllhandle = LoadLibrary (dllnames[i]);
137 SetDllDirectory(NULL);
140 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
142 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, (dllnames[i+1] != NULL) || (strrchr(com_argv[0], '/'))))
145 Sys_UnloadLibrary (&dllhandle);
148 // see if the names can be loaded relative to the executable path
149 // (this is for Mac OSX which does not check next to the executable)
150 if (!dllhandle && strrchr(com_argv[0], '/'))
152 char path[MAX_OSPATH];
153 strlcpy(path, com_argv[0], sizeof(path));
154 strrchr(path, '/')[1] = 0;
155 for (i = 0; dllnames[i] != NULL; i++)
157 char temp[MAX_OSPATH];
158 strlcpy(temp, path, sizeof(temp));
159 strlcat(temp, dllnames[i], sizeof(temp));
160 Con_DPrintf (" \"%s\"", temp);
162 dllhandle = LoadLibrary (temp);
164 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
166 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, dllnames[i+1] != NULL))
169 Sys_UnloadLibrary (&dllhandle);
176 Con_DPrintf(" - failed.\n");
180 Con_DPrintf(" - loaded.\n");
189 void Sys_UnloadLibrary (dllhandle_t* handle)
192 if (handle == NULL || *handle == NULL)
196 FreeLibrary (*handle);
205 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
209 return (void *)GetProcAddress (handle, name);
211 return (void *)dlsym (handle, name);
219 # define HAVE_TIMEGETTIME 1
220 # define HAVE_QUERYPERFORMANCECOUNTER 1
221 # define HAVE_Sleep 1
224 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
225 # define HAVE_CLOCKGETTIME 1
229 // FIXME improve this check, manpage hints to DST_NONE
230 # define HAVE_GETTIMEOFDAY 1
234 # define HAVE_SELECT 1
238 // FIXME improve this check
239 # define HAVE_USLEEP 1
242 // this one is referenced elsewhere
243 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."};
246 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
247 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
248 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
249 #if HAVE_QUERYPERFORMANCECOUNTER
250 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)"};
252 #if HAVE_CLOCKGETTIME
253 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)"};
256 static unsigned long benchmark_time;
258 void Sys_Init_Commands (void)
260 Cvar_RegisterVariable(&sys_debugsleep);
261 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
262 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
263 if(sys_supportsdlgetticks)
265 Cvar_RegisterVariable(&sys_usesdlgetticks);
266 Cvar_RegisterVariable(&sys_usesdldelay);
269 #if HAVE_QUERYPERFORMANCECOUNTER
270 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
272 #if HAVE_CLOCKGETTIME
273 Cvar_RegisterVariable(&sys_useclockgettime);
277 double Sys_DoubleTime(void)
279 static int first = true;
280 static double oldtime = 0.0, curtime = 0.0;
282 if(sys_usenoclockbutbenchmark.integer)
285 return ((double) benchmark_time) / 1e6;
288 // first all the OPTIONAL timers
290 #if HAVE_QUERYPERFORMANCECOUNTER
291 else if (sys_usequeryperformancecounter.integer)
293 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
294 // QueryPerformanceCounter
296 // Windows 95/98/ME/NT/2000/XP
298 // very accurate (CPU cycles)
300 // does not necessarily match realtime too well (tends to get faster and faster in win98)
301 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
303 LARGE_INTEGER PerformanceFreq;
304 LARGE_INTEGER PerformanceCount;
306 if (!QueryPerformanceFrequency (&PerformanceFreq))
308 Con_Printf ("No hardware timer available\n");
309 // fall back to timeGetTime
310 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
311 return Sys_DoubleTime();
313 QueryPerformanceCounter (&PerformanceCount);
316 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
317 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
319 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
320 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
325 #if HAVE_CLOCKGETTIME
326 else if (sys_useclockgettime.integer)
329 # ifdef CLOCK_MONOTONIC
331 clock_gettime(CLOCK_MONOTONIC, &ts);
334 clock_gettime(CLOCK_HIGHRES, &ts);
336 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
340 // now all the FALLBACK timers
341 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
343 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
345 #if HAVE_GETTIMEOFDAY
349 gettimeofday(&tp, NULL);
350 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
352 #elif HAVE_TIMEGETTIME
355 static int firsttimegettime = true;
358 // Windows 95/98/ME/NT/2000/XP
360 // reasonable accuracy (millisecond)
362 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
364 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
365 if (firsttimegettime)
368 firsttimegettime = false;
371 newtime = (double) timeGetTime () / 1000.0;
374 // fallback for using the SDL timer if no other timer is available
377 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
378 // this calls Sys_Error() if not linking against SDL
388 if (newtime < oldtime)
390 // warn if it's significant
391 if (newtime - oldtime < -0.01)
392 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
394 else if (newtime > oldtime + 1800)
396 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
399 curtime += newtime - oldtime;
405 void Sys_Sleep(int microseconds)
408 if(sys_usenoclockbutbenchmark.integer)
410 benchmark_time += microseconds;
413 if(sys_debugsleep.integer)
415 t = Sys_DoubleTime();
417 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
419 Sys_SDL_Delay(microseconds / 1000);
425 tv.tv_sec = microseconds / 1000000;
426 tv.tv_usec = microseconds % 1000000;
427 select(0, NULL, NULL, NULL, &tv);
432 usleep(microseconds);
437 Sleep(microseconds / 1000);
442 Sys_SDL_Delay(microseconds / 1000);
445 if(sys_debugsleep.integer)
447 t = Sys_DoubleTime() - t;
448 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
452 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
454 const char *p = PATH;
458 while((q = strchr(p, ':')))
460 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
461 if(FS_SysFileExists(buf))
465 if(!q) // none found - try the last item
467 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
468 if(FS_SysFileExists(buf))
475 const char *Sys_FindExecutableName(void)
480 static char exenamebuf[MAX_OSPATH+1];
482 #if defined(__FreeBSD__)
483 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
484 #elif defined(__linux__)
485 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
487 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
492 if(strchr(com_argv[0], '/'))
493 return com_argv[0]; // possibly a relative path
495 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
499 void Sys_ProvideSelfFD(void)
503 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);