8 # define _WIN32_WINNT 0x0502
10 // for SetDllDirectory
13 # include <mmsystem.h> // timeGetTime
14 # include <time.h> // localtime
16 #pragma comment(lib, "winmm.lib")
21 # include <sys/time.h>
28 static char sys_timestring[128];
29 char *Sys_TimeString(const char *timeformat)
31 time_t mytime = time(NULL);
34 localtime_s(&mytm, &mytime);
35 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
37 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
39 return sys_timestring;
43 extern qboolean host_shuttingdown;
44 void Sys_Quit (int returnvalue)
46 if (COM_CheckParm("-profilegameonly"))
47 Sys_AllowProfiling(false);
48 host_shuttingdown = true;
53 #if defined(__linux__) || defined(__FreeBSD__)
60 void Sys_AllowProfiling(qboolean enable)
62 #if defined(__linux__) || defined(__FreeBSD__)
69 ===============================================================================
73 ===============================================================================
76 static qboolean Sys_LoadLibraryFunctions(dllhandle_t dllhandle, const dllfunction_t *fcts, qboolean complain, qboolean has_next)
78 const dllfunction_t *func;
81 for (func = fcts; func && func->name != NULL; func++)
82 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
86 Con_DPrintf (" - missing function \"%s\" - broken library!", func->name);
88 Con_DPrintf("\nContinuing with");
95 for (func = fcts; func && func->name != NULL; func++)
96 *func->funcvariable = NULL;
101 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
104 const dllfunction_t *func;
105 dllhandle_t dllhandle = 0;
112 #ifdef PREFER_PRELOAD
113 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
114 if(Sys_LoadLibraryFunctions(dllhandle, fcts, false, false))
116 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
121 Sys_UnloadLibrary(&dllhandle);
127 for (func = fcts; func && func->name != NULL; func++)
128 *func->funcvariable = NULL;
130 // Try every possible name
131 Con_DPrintf ("Trying to load library...");
132 for (i = 0; dllnames[i] != NULL; i++)
134 Con_DPrintf (" \"%s\"", dllnames[i]);
137 SetDllDirectory("bin64");
139 dllhandle = LoadLibrary (dllnames[i]);
141 SetDllDirectory(NULL);
144 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
146 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, (dllnames[i+1] != NULL) || (strrchr(com_argv[0], '/'))))
149 Sys_UnloadLibrary (&dllhandle);
152 // see if the names can be loaded relative to the executable path
153 // (this is for Mac OSX which does not check next to the executable)
154 if (!dllhandle && strrchr(com_argv[0], '/'))
156 char path[MAX_OSPATH];
157 strlcpy(path, com_argv[0], sizeof(path));
158 strrchr(path, '/')[1] = 0;
159 for (i = 0; dllnames[i] != NULL; i++)
161 char temp[MAX_OSPATH];
162 strlcpy(temp, path, sizeof(temp));
163 strlcat(temp, dllnames[i], sizeof(temp));
164 Con_DPrintf (" \"%s\"", temp);
166 dllhandle = LoadLibrary (temp);
168 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
170 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, dllnames[i+1] != NULL))
173 Sys_UnloadLibrary (&dllhandle);
180 Con_DPrintf(" - failed.\n");
184 Con_DPrintf(" - loaded.\n");
193 void Sys_UnloadLibrary (dllhandle_t* handle)
196 if (handle == NULL || *handle == NULL)
200 FreeLibrary (*handle);
209 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
213 return (void *)GetProcAddress (handle, name);
215 return (void *)dlsym (handle, name);
223 # define HAVE_TIMEGETTIME 1
224 # define HAVE_QUERYPERFORMANCECOUNTER 1
225 # define HAVE_Sleep 1
228 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
229 # define HAVE_CLOCKGETTIME 1
233 // FIXME improve this check, manpage hints to DST_NONE
234 # define HAVE_GETTIMEOFDAY 1
238 # define HAVE_SELECT 1
242 // FIXME improve this check
243 # define HAVE_USLEEP 1
246 // this one is referenced elsewhere
247 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."};
250 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
251 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
252 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
253 #if HAVE_QUERYPERFORMANCECOUNTER
254 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)"};
256 #if HAVE_CLOCKGETTIME
257 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)"};
260 static unsigned long benchmark_time;
262 void Sys_Init_Commands (void)
264 Cvar_RegisterVariable(&sys_debugsleep);
265 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
266 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
267 if(sys_supportsdlgetticks)
269 Cvar_RegisterVariable(&sys_usesdlgetticks);
270 Cvar_RegisterVariable(&sys_usesdldelay);
273 #if HAVE_QUERYPERFORMANCECOUNTER
274 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
276 #if HAVE_CLOCKGETTIME
277 Cvar_RegisterVariable(&sys_useclockgettime);
281 double Sys_DoubleTime(void)
283 static int first = true;
284 static double oldtime = 0.0, curtime = 0.0;
286 if(sys_usenoclockbutbenchmark.integer)
289 return ((double) benchmark_time) / 1e6;
292 // first all the OPTIONAL timers
294 #if HAVE_QUERYPERFORMANCECOUNTER
295 else if (sys_usequeryperformancecounter.integer)
297 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
298 // QueryPerformanceCounter
300 // Windows 95/98/ME/NT/2000/XP
302 // very accurate (CPU cycles)
304 // does not necessarily match realtime too well (tends to get faster and faster in win98)
305 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
307 LARGE_INTEGER PerformanceFreq;
308 LARGE_INTEGER PerformanceCount;
310 if (!QueryPerformanceFrequency (&PerformanceFreq))
312 Con_Printf ("No hardware timer available\n");
313 // fall back to timeGetTime
314 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
315 return Sys_DoubleTime();
317 QueryPerformanceCounter (&PerformanceCount);
320 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
321 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
323 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
324 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
329 #if HAVE_CLOCKGETTIME
330 else if (sys_useclockgettime.integer)
333 # ifdef CLOCK_MONOTONIC
335 clock_gettime(CLOCK_MONOTONIC, &ts);
338 clock_gettime(CLOCK_HIGHRES, &ts);
340 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
344 // now all the FALLBACK timers
345 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
347 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
349 #if HAVE_GETTIMEOFDAY
353 gettimeofday(&tp, NULL);
354 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
356 #elif HAVE_TIMEGETTIME
359 static int firsttimegettime = true;
362 // Windows 95/98/ME/NT/2000/XP
364 // reasonable accuracy (millisecond)
366 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
368 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
369 if (firsttimegettime)
372 firsttimegettime = false;
375 newtime = (double) timeGetTime () / 1000.0;
378 // fallback for using the SDL timer if no other timer is available
381 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
382 // this calls Sys_Error() if not linking against SDL
392 if (newtime < oldtime)
394 // warn if it's significant
395 if (newtime - oldtime < -0.01)
396 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
398 else if (newtime > oldtime + 1800)
400 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
403 curtime += newtime - oldtime;
409 void Sys_Sleep(int microseconds)
412 if(sys_usenoclockbutbenchmark.integer)
414 benchmark_time += microseconds;
417 if(sys_debugsleep.integer)
419 t = Sys_DoubleTime();
421 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
423 Sys_SDL_Delay(microseconds / 1000);
429 tv.tv_sec = microseconds / 1000000;
430 tv.tv_usec = microseconds % 1000000;
431 select(0, NULL, NULL, NULL, &tv);
436 usleep(microseconds);
441 Sleep(microseconds / 1000);
446 Sys_SDL_Delay(microseconds / 1000);
449 if(sys_debugsleep.integer)
451 t = Sys_DoubleTime() - t;
452 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
456 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
458 const char *p = PATH;
462 while((q = strchr(p, ':')))
464 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
465 if(FS_SysFileExists(buf))
469 if(!q) // none found - try the last item
471 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
472 if(FS_SysFileExists(buf))
479 const char *Sys_FindExecutableName(void)
484 static char exenamebuf[MAX_OSPATH+1];
486 #if defined(__FreeBSD__)
487 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
488 #elif defined(__linux__)
489 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
491 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
496 if(strchr(com_argv[0], '/'))
497 return com_argv[0]; // possibly a relative path
499 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
503 void Sys_ProvideSelfFD(void)
507 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);