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
242 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
243 # define HAVE_CLOCKGETTIME 1
245 // FIXME improve this check, manpage hints to DST_NONE
246 # define HAVE_GETTIMEOFDAY 1
250 // on Win32, select() cannot be used with all three FD list args being NULL according to MSDN
251 // (so much for POSIX...)
253 # define HAVE_SELECT 1
258 // FIXME improve this check
259 # define HAVE_USLEEP 1
262 // this one is referenced elsewhere
263 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."};
266 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
267 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
268 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
269 #if HAVE_QUERYPERFORMANCECOUNTER
270 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)"};
272 #if HAVE_CLOCKGETTIME
273 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)"};
276 static double benchmark_time; // actually always contains an integer amount of milliseconds, will eventually "overflow"
278 void Sys_Init_Commands (void)
280 Cvar_RegisterVariable(&sys_debugsleep);
281 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
282 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
283 if(sys_supportsdlgetticks)
285 Cvar_RegisterVariable(&sys_usesdlgetticks);
286 Cvar_RegisterVariable(&sys_usesdldelay);
289 #if HAVE_QUERYPERFORMANCECOUNTER
290 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
292 #if HAVE_CLOCKGETTIME
293 Cvar_RegisterVariable(&sys_useclockgettime);
297 double Sys_DirtyTime(void)
299 // first all the OPTIONAL timers
301 // benchmark timer (fake clock)
302 if(sys_usenoclockbutbenchmark.integer)
304 double old_benchmark_time = benchmark_time;
306 if(benchmark_time == old_benchmark_time)
307 Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry");
308 return benchmark_time * 0.000001;
310 #if HAVE_QUERYPERFORMANCECOUNTER
311 if (sys_usequeryperformancecounter.integer)
313 // LadyHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
314 // QueryPerformanceCounter
316 // Windows 95/98/ME/NT/2000/XP
318 // very accurate (CPU cycles)
320 // does not necessarily match realtime too well (tends to get faster and faster in win98)
321 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
323 LARGE_INTEGER PerformanceFreq;
324 LARGE_INTEGER PerformanceCount;
326 if (QueryPerformanceFrequency (&PerformanceFreq))
328 QueryPerformanceCounter (&PerformanceCount);
331 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
332 return ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
334 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
335 return ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
340 Con_Printf("No hardware timer available\n");
341 // fall back to other clock sources
342 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
347 #if HAVE_CLOCKGETTIME
348 if (sys_useclockgettime.integer)
351 # ifdef CLOCK_MONOTONIC
353 clock_gettime(CLOCK_MONOTONIC, &ts);
356 clock_gettime(CLOCK_HIGHRES, &ts);
358 return (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
362 // now all the FALLBACK timers
363 if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
364 return (double) Sys_SDL_GetTicks() / 1000.0;
365 #if HAVE_GETTIMEOFDAY
368 gettimeofday(&tp, NULL);
369 return (double) tp.tv_sec + tp.tv_usec / 1000000.0;
371 #elif HAVE_TIMEGETTIME
373 static int firsttimegettime = true;
376 // Windows 95/98/ME/NT/2000/XP
378 // reasonable accuracy (millisecond)
380 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
382 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
383 if (firsttimegettime)
386 firsttimegettime = false;
389 return (double) timeGetTime() / 1000.0;
392 // fallback for using the SDL timer if no other timer is available
393 // this calls Sys_Error() if not linking against SDL
394 return (double) Sys_SDL_GetTicks() / 1000.0;
398 void Sys_Sleep(int microseconds)
401 if(sys_usenoclockbutbenchmark.integer)
405 double old_benchmark_time = benchmark_time;
406 benchmark_time += microseconds;
407 if(benchmark_time == old_benchmark_time)
408 Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry");
412 if(sys_debugsleep.integer)
416 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
418 Sys_SDL_Delay(microseconds / 1000);
424 tv.tv_sec = microseconds / 1000000;
425 tv.tv_usec = microseconds % 1000000;
426 select(0, NULL, NULL, NULL, &tv);
431 usleep(microseconds);
436 Sleep(microseconds / 1000);
441 Sys_SDL_Delay(microseconds / 1000);
444 if(sys_debugsleep.integer)
446 t = Sys_DirtyTime() - t;
447 Sys_PrintfToTerminal("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
451 void Sys_PrintfToTerminal(const char *fmt, ...)
454 char msg[MAX_INPUTLINE];
456 va_start(argptr,fmt);
457 dpvsnprintf(msg,sizeof(msg),fmt,argptr);
460 Sys_PrintToTerminal(msg);
464 static const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
466 const char *p = PATH;
470 while((q = strchr(p, ':')))
472 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
473 if(FS_SysFileExists(buf))
477 if(!q) // none found - try the last item
479 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
480 if(FS_SysFileExists(buf))
488 static const char *Sys_FindExecutableName(void)
493 static char exenamebuf[MAX_OSPATH+1];
495 #if defined(__FreeBSD__)
496 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
497 #elif defined(__linux__)
498 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
500 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
505 if(strchr(com_argv[0], '/'))
506 return com_argv[0]; // possibly a relative path
508 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
512 void Sys_ProvideSelfFD(void)
516 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);
519 // for x86 cpus only... (x64 has SSE2_PRESENT)
520 #if defined(SSE_POSSIBLE) && !defined(SSE2_PRESENT)
521 // code from SDL, shortened as we can expect CPUID to work
522 static int CPUID_Features(void)
525 # if defined(__GNUC__) && defined(__i386__)
527 " movl %%ebx,%%edi\n"
528 " xorl %%eax,%%eax \n"
530 " cpuid # Get family/model/stepping/features\n"
532 " movl %%edi,%%ebx\n"
535 : "%eax", "%ecx", "%edx", "%edi"
537 # elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
541 cpuid ; Get family/model/stepping/features
545 # error SSE_POSSIBLE set but no CPUID implementation
552 qboolean Sys_HaveSSE(void)
554 // COMMANDLINEOPTION: SSE: -nosse disables SSE support and detection
555 if(COM_CheckParm("-nosse"))
560 // COMMANDLINEOPTION: SSE: -forcesse enables SSE support and disables detection
561 if(COM_CheckParm("-forcesse") || COM_CheckParm("-forcesse2"))
563 if(CPUID_Features() & (1 << 25))
569 qboolean Sys_HaveSSE2(void)
571 // COMMANDLINEOPTION: SSE2: -nosse2 disables SSE2 support and detection
572 if(COM_CheckParm("-nosse") || COM_CheckParm("-nosse2"))
577 // COMMANDLINEOPTION: SSE2: -forcesse2 enables SSE2 support and disables detection
578 if(COM_CheckParm("-forcesse2"))
580 if((CPUID_Features() & (3 << 25)) == (3 << 25)) // SSE is 1<<25, SSE2 is 1<<26
587 /// called to set process priority for dedicated servers
588 #if defined(__linux__)
589 #include <sys/resource.h>
591 static int nicelevel;
592 static qboolean nicepossible;
593 static qboolean isnice;
594 void Sys_InitProcessNice (void)
597 nicepossible = false;
598 if(COM_CheckParm("-nonice"))
601 nicelevel = getpriority(PRIO_PROCESS, 0);
604 Con_Printf("Kernel does not support reading process priority - cannot use niceness\n");
607 if(getrlimit(RLIMIT_NICE, &lim))
609 Con_Printf("Kernel does not support lowering nice level again - cannot use niceness\n");
612 if(lim.rlim_cur != RLIM_INFINITY && nicelevel < (int) (20 - lim.rlim_cur))
614 Con_Printf("Current nice level is below the soft limit - cannot use niceness\n");
620 void Sys_MakeProcessNice (void)
626 Con_DPrintf("Process is becoming 'nice'...\n");
627 if(setpriority(PRIO_PROCESS, 0, 19))
628 Con_Printf("Failed to raise nice level to %d\n", 19);
631 void Sys_MakeProcessMean (void)
637 Con_DPrintf("Process is becoming 'mean'...\n");
638 if(setpriority(PRIO_PROCESS, 0, nicelevel))
639 Con_Printf("Failed to lower nice level to %d\n", nicelevel);
643 void Sys_InitProcessNice (void)
646 void Sys_MakeProcessNice (void)
649 void Sys_MakeProcessMean (void)