2 # ifndef DONT_USE_SETDLLDIRECTORY
3 # define _WIN32_WINNT 0x0502
14 # include <mmsystem.h> // timeGetTime
15 # include <time.h> // localtime
17 #pragma comment(lib, "winmm.lib")
22 # include <sys/time.h>
29 static char sys_timestring[128];
30 char *Sys_TimeString(const char *timeformat)
32 time_t mytime = time(NULL);
35 localtime_s(&mytm, &mytime);
36 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
38 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
40 return sys_timestring;
44 extern qboolean host_shuttingdown;
45 void Sys_Quit (int returnvalue)
47 // Unlock mutexes because the quit command may jump directly here, causing a deadlock
48 Cbuf_UnlockThreadMutex();
49 SV_UnlockThreadMutex();
51 if (COM_CheckParm("-profilegameonly"))
52 Sys_AllowProfiling(false);
53 host_shuttingdown = true;
61 void Sys_AllowProfiling(qboolean enable)
65 extern void monstartup(const char *libname);
66 extern void moncleanup(void);
68 monstartup("libmain.so");
72 #elif defined(__linux__) || defined(__FreeBSD__)
73 extern int moncontrol(int);
80 ===============================================================================
84 ===============================================================================
87 static qboolean Sys_LoadLibraryFunctions(dllhandle_t dllhandle, const dllfunction_t *fcts, qboolean complain, qboolean has_next)
89 const dllfunction_t *func;
92 for (func = fcts; func && func->name != NULL; func++)
93 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
97 Con_DPrintf (" - missing function \"%s\" - broken library!", func->name);
99 Con_DPrintf("\nContinuing with");
106 for (func = fcts; func && func->name != NULL; func++)
107 *func->funcvariable = NULL;
112 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
115 const dllfunction_t *func;
116 dllhandle_t dllhandle = 0;
123 #ifdef PREFER_PRELOAD
124 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
125 if(Sys_LoadLibraryFunctions(dllhandle, fcts, false, false))
127 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
132 Sys_UnloadLibrary(&dllhandle);
138 for (func = fcts; func && func->name != NULL; func++)
139 *func->funcvariable = NULL;
141 // Try every possible name
142 Con_DPrintf ("Trying to load library...");
143 for (i = 0; dllnames[i] != NULL; i++)
145 Con_DPrintf (" \"%s\"", dllnames[i]);
147 # ifndef DONT_USE_SETDLLDIRECTORY
149 SetDllDirectory("bin64");
151 SetDllDirectory("bin32");
154 dllhandle = LoadLibrary (dllnames[i]);
155 // no need to unset this - we want ALL dlls to be loaded from there, anyway
157 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
159 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, (dllnames[i+1] != NULL) || (strrchr(com_argv[0], '/'))))
162 Sys_UnloadLibrary (&dllhandle);
165 // see if the names can be loaded relative to the executable path
166 // (this is for Mac OSX which does not check next to the executable)
167 if (!dllhandle && strrchr(com_argv[0], '/'))
169 char path[MAX_OSPATH];
170 strlcpy(path, com_argv[0], sizeof(path));
171 strrchr(path, '/')[1] = 0;
172 for (i = 0; dllnames[i] != NULL; i++)
174 char temp[MAX_OSPATH];
175 strlcpy(temp, path, sizeof(temp));
176 strlcat(temp, dllnames[i], sizeof(temp));
177 Con_DPrintf (" \"%s\"", temp);
179 dllhandle = LoadLibrary (temp);
181 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
183 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, dllnames[i+1] != NULL))
186 Sys_UnloadLibrary (&dllhandle);
193 Con_DPrintf(" - failed.\n");
197 Con_DPrintf(" - loaded.\n");
206 void Sys_UnloadLibrary (dllhandle_t* handle)
209 if (handle == NULL || *handle == NULL)
213 FreeLibrary (*handle);
222 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
226 return (void *)GetProcAddress (handle, name);
228 return (void *)dlsym (handle, name);
236 # define HAVE_TIMEGETTIME 1
237 # define HAVE_QUERYPERFORMANCECOUNTER 1
238 # define HAVE_Sleep 1
241 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
242 # define HAVE_CLOCKGETTIME 1
246 // FIXME improve this check, manpage hints to DST_NONE
247 # define HAVE_GETTIMEOFDAY 1
251 // on Win32, select() cannot be used with all three FD list args being NULL according to MSDN
252 // (so much for POSIX...)
254 # define HAVE_SELECT 1
259 // FIXME improve this check
260 # define HAVE_USLEEP 1
263 // this one is referenced elsewhere
264 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."};
267 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
268 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
269 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
270 #if HAVE_QUERYPERFORMANCECOUNTER
271 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)"};
273 #if HAVE_CLOCKGETTIME
274 static cvar_t sys_useclockgettime = {CVAR_SAVE, "sys_useclockgettime", "1", "use POSIX clock_gettime function (not adjusted by NTP on some older Linux kernels) for timing rather than gettimeofday (which has issues if the system time is stepped by ntpdate, or apparently on some Xen installations)"};
277 static double benchmark_time; // actually always contains an integer amount of milliseconds, will eventually "overflow"
279 void Sys_Init_Commands (void)
281 Cvar_RegisterVariable(&sys_debugsleep);
282 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
283 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
284 if(sys_supportsdlgetticks)
286 Cvar_RegisterVariable(&sys_usesdlgetticks);
287 Cvar_RegisterVariable(&sys_usesdldelay);
290 #if HAVE_QUERYPERFORMANCECOUNTER
291 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
293 #if HAVE_CLOCKGETTIME
294 Cvar_RegisterVariable(&sys_useclockgettime);
298 double Sys_DirtyTime(void)
300 // first all the OPTIONAL timers
302 // benchmark timer (fake clock)
303 if(sys_usenoclockbutbenchmark.integer)
305 double old_benchmark_time = benchmark_time;
307 if(benchmark_time == old_benchmark_time)
308 Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry");
309 return benchmark_time * 0.000001;
311 #if HAVE_QUERYPERFORMANCECOUNTER
312 if (sys_usequeryperformancecounter.integer)
314 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
315 // QueryPerformanceCounter
317 // Windows 95/98/ME/NT/2000/XP
319 // very accurate (CPU cycles)
321 // does not necessarily match realtime too well (tends to get faster and faster in win98)
322 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
324 LARGE_INTEGER PerformanceFreq;
325 LARGE_INTEGER PerformanceCount;
327 if (QueryPerformanceFrequency (&PerformanceFreq))
329 QueryPerformanceCounter (&PerformanceCount);
332 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
333 return ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
335 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
336 return ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
341 Con_Printf("No hardware timer available\n");
342 // fall back to other clock sources
343 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
348 #if HAVE_CLOCKGETTIME
349 if (sys_useclockgettime.integer)
352 # ifdef CLOCK_MONOTONIC
354 clock_gettime(CLOCK_MONOTONIC, &ts);
357 clock_gettime(CLOCK_HIGHRES, &ts);
359 return (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
363 // now all the FALLBACK timers
364 if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
365 return (double) Sys_SDL_GetTicks() / 1000.0;
366 #if HAVE_GETTIMEOFDAY
369 gettimeofday(&tp, NULL);
370 return (double) tp.tv_sec + tp.tv_usec / 1000000.0;
372 #elif HAVE_TIMEGETTIME
374 static int firsttimegettime = true;
377 // Windows 95/98/ME/NT/2000/XP
379 // reasonable accuracy (millisecond)
381 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
383 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
384 if (firsttimegettime)
387 firsttimegettime = false;
390 return (double) timeGetTime() / 1000.0;
393 // fallback for using the SDL timer if no other timer is available
394 // this calls Sys_Error() if not linking against SDL
395 return (double) Sys_SDL_GetTicks() / 1000.0;
399 void Sys_Sleep(int microseconds)
402 if(sys_usenoclockbutbenchmark.integer)
406 double old_benchmark_time = benchmark_time;
407 benchmark_time += microseconds;
408 if(benchmark_time == old_benchmark_time)
409 Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry");
413 if(sys_debugsleep.integer)
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_DirtyTime() - t;
448 Sys_PrintfToTerminal("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
452 void Sys_PrintfToTerminal(const char *fmt, ...)
455 char msg[MAX_INPUTLINE];
457 va_start(argptr,fmt);
458 dpvsnprintf(msg,sizeof(msg),fmt,argptr);
461 Sys_PrintToTerminal(msg);
465 static const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
467 const char *p = PATH;
471 while((q = strchr(p, ':')))
473 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
474 if(FS_SysFileExists(buf))
478 if(!q) // none found - try the last item
480 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
481 if(FS_SysFileExists(buf))
489 static const char *Sys_FindExecutableName(void)
494 static char exenamebuf[MAX_OSPATH+1];
496 #if defined(__FreeBSD__)
497 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
498 #elif defined(__linux__)
499 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
501 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
506 if(strchr(com_argv[0], '/'))
507 return com_argv[0]; // possibly a relative path
509 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
513 void Sys_ProvideSelfFD(void)
517 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);
520 // for x86 cpus only... (x64 has SSE2_PRESENT)
521 #if defined(SSE_POSSIBLE) && !defined(SSE2_PRESENT)
522 // code from SDL, shortened as we can expect CPUID to work
523 static int CPUID_Features(void)
526 # if defined(__GNUC__) && defined(__i386__)
528 " movl %%ebx,%%edi\n"
529 " xorl %%eax,%%eax \n"
531 " cpuid # Get family/model/stepping/features\n"
533 " movl %%edi,%%ebx\n"
536 : "%eax", "%ecx", "%edx", "%edi"
538 # elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
542 cpuid ; Get family/model/stepping/features
546 # error SSE_POSSIBLE set but no CPUID implementation
553 qboolean Sys_HaveSSE(void)
555 // COMMANDLINEOPTION: SSE: -nosse disables SSE support and detection
556 if(COM_CheckParm("-nosse"))
561 // COMMANDLINEOPTION: SSE: -forcesse enables SSE support and disables detection
562 if(COM_CheckParm("-forcesse") || COM_CheckParm("-forcesse2"))
564 if(CPUID_Features() & (1 << 25))
570 qboolean Sys_HaveSSE2(void)
572 // COMMANDLINEOPTION: SSE2: -nosse2 disables SSE2 support and detection
573 if(COM_CheckParm("-nosse") || COM_CheckParm("-nosse2"))
578 // COMMANDLINEOPTION: SSE2: -forcesse2 enables SSE2 support and disables detection
579 if(COM_CheckParm("-forcesse2"))
581 if((CPUID_Features() & (3 << 25)) == (3 << 25)) // SSE is 1<<25, SSE2 is 1<<26
588 /// called to set process priority for dedicated servers
589 #if defined(__linux__)
590 #include <sys/resource.h>
592 static int nicelevel;
593 static qboolean nicepossible;
594 static qboolean isnice;
595 void Sys_InitProcessNice (void)
598 nicepossible = false;
599 if(COM_CheckParm("-nonice"))
602 nicelevel = getpriority(PRIO_PROCESS, 0);
605 Con_Printf("Kernel does not support reading process priority - cannot use niceness\n");
608 if(getrlimit(RLIMIT_NICE, &lim))
610 Con_Printf("Kernel does not support lowering nice level again - cannot use niceness\n");
613 if(lim.rlim_cur != RLIM_INFINITY && nicelevel < (int) (20 - lim.rlim_cur))
615 Con_Printf("Current nice level is below the soft limit - cannot use niceness\n");
621 void Sys_MakeProcessNice (void)
627 Con_DPrintf("Process is becoming 'nice'...\n");
628 if(setpriority(PRIO_PROCESS, 0, 19))
629 Con_Printf("Failed to raise nice level to %d\n", 19);
632 void Sys_MakeProcessMean (void)
638 Con_DPrintf("Process is becoming 'mean'...\n");
639 if(setpriority(PRIO_PROCESS, 0, nicelevel))
640 Con_Printf("Failed to lower nice level to %d\n", nicelevel);
644 void Sys_InitProcessNice (void)
647 void Sys_MakeProcessNice (void)
650 void Sys_MakeProcessMean (void)