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 // on Win32, select() cannot be used with all three FD list args being NULL according to MSDN
239 // (so much for POSIX...)
241 # define HAVE_SELECT 1
246 // FIXME improve this check
247 # define HAVE_USLEEP 1
250 // this one is referenced elsewhere
251 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."};
254 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
255 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
256 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
257 #if HAVE_QUERYPERFORMANCECOUNTER
258 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)"};
260 #if HAVE_CLOCKGETTIME
261 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)"};
264 static unsigned long benchmark_time;
266 void Sys_Init_Commands (void)
268 Cvar_RegisterVariable(&sys_debugsleep);
269 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
270 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
271 if(sys_supportsdlgetticks)
273 Cvar_RegisterVariable(&sys_usesdlgetticks);
274 Cvar_RegisterVariable(&sys_usesdldelay);
277 #if HAVE_QUERYPERFORMANCECOUNTER
278 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
280 #if HAVE_CLOCKGETTIME
281 Cvar_RegisterVariable(&sys_useclockgettime);
285 double Sys_DoubleTime(void)
287 static int first = true;
288 static double oldtime = 0.0, curtime = 0.0;
290 if(sys_usenoclockbutbenchmark.integer)
293 return ((double) benchmark_time) / 1e6;
296 // first all the OPTIONAL timers
298 #if HAVE_QUERYPERFORMANCECOUNTER
299 else if (sys_usequeryperformancecounter.integer)
301 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
302 // QueryPerformanceCounter
304 // Windows 95/98/ME/NT/2000/XP
306 // very accurate (CPU cycles)
308 // does not necessarily match realtime too well (tends to get faster and faster in win98)
309 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
311 LARGE_INTEGER PerformanceFreq;
312 LARGE_INTEGER PerformanceCount;
314 if (!QueryPerformanceFrequency (&PerformanceFreq))
316 Con_Printf ("No hardware timer available\n");
317 // fall back to timeGetTime
318 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
319 return Sys_DoubleTime();
321 QueryPerformanceCounter (&PerformanceCount);
324 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
325 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
327 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
328 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
333 #if HAVE_CLOCKGETTIME
334 else if (sys_useclockgettime.integer)
337 # ifdef CLOCK_MONOTONIC
339 clock_gettime(CLOCK_MONOTONIC, &ts);
342 clock_gettime(CLOCK_HIGHRES, &ts);
344 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
348 // now all the FALLBACK timers
349 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
351 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
353 #if HAVE_GETTIMEOFDAY
357 gettimeofday(&tp, NULL);
358 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
360 #elif HAVE_TIMEGETTIME
363 static int firsttimegettime = true;
366 // Windows 95/98/ME/NT/2000/XP
368 // reasonable accuracy (millisecond)
370 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
372 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
373 if (firsttimegettime)
376 firsttimegettime = false;
379 newtime = (double) timeGetTime () / 1000.0;
382 // fallback for using the SDL timer if no other timer is available
385 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
386 // this calls Sys_Error() if not linking against SDL
396 if (newtime < oldtime)
398 // warn if it's significant
399 if (newtime - oldtime < -0.01)
400 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
402 else if (newtime > oldtime + 1800)
404 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
407 curtime += newtime - oldtime;
413 void Sys_Sleep(int microseconds)
416 if(sys_usenoclockbutbenchmark.integer)
418 benchmark_time += microseconds;
421 if(sys_debugsleep.integer)
423 t = Sys_DoubleTime();
425 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
427 Sys_SDL_Delay(microseconds / 1000);
433 tv.tv_sec = microseconds / 1000000;
434 tv.tv_usec = microseconds % 1000000;
435 select(0, NULL, NULL, NULL, &tv);
440 usleep(microseconds);
445 Sleep(microseconds / 1000);
450 Sys_SDL_Delay(microseconds / 1000);
453 if(sys_debugsleep.integer)
455 t = Sys_DoubleTime() - t;
456 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
460 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
462 const char *p = PATH;
466 while((q = strchr(p, ':')))
468 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
469 if(FS_SysFileExists(buf))
473 if(!q) // none found - try the last item
475 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
476 if(FS_SysFileExists(buf))
483 const char *Sys_FindExecutableName(void)
488 static char exenamebuf[MAX_OSPATH+1];
490 #if defined(__FreeBSD__)
491 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
492 #elif defined(__linux__)
493 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
495 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
500 if(strchr(com_argv[0], '/'))
501 return com_argv[0]; // possibly a relative path
503 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
507 void Sys_ProvideSelfFD(void)
511 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);