]> git.xonotic.org Git - xonotic/darkplaces.git/blob - sys_shared.c
2149dff6c71e8c0a3f1f81e1b307f3861c0d6bc4
[xonotic/darkplaces.git] / sys_shared.c
1 #ifdef WIN32
2 # ifndef DONT_USE_SETDLLDIRECTORY
3 #  define _WIN32_WINNT 0x0502
4 # endif
5 #endif
6
7 #include "quakedef.h"
8 #include "taskqueue.h"
9 #include "thread.h"
10
11 #define SUPPORTDLL
12
13 #ifdef WIN32
14 # include <windows.h>
15 # include <mmsystem.h> // timeGetTime
16 # include <time.h> // localtime
17 #ifdef _MSC_VER
18 #pragma comment(lib, "winmm.lib")
19 #endif
20 #else
21 # ifdef __FreeBSD__
22 #  include <sys/sysctl.h>
23 # endif
24 # include <unistd.h>
25 # include <fcntl.h>
26 # include <sys/time.h>
27 # include <time.h>
28 # ifdef SUPPORTDLL
29 #  include <dlfcn.h>
30 # endif
31 #endif
32
33 static char sys_timestring[128];
34 char *Sys_TimeString(const char *timeformat)
35 {
36         time_t mytime = time(NULL);
37 #if _MSC_VER >= 1400
38         struct tm mytm;
39         localtime_s(&mytm, &mytime);
40         strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
41 #else
42         strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
43 #endif
44         return sys_timestring;
45 }
46
47
48 void Sys_Quit (int returnvalue)
49 {
50         // Unlock mutexes because the quit command may jump directly here, causing a deadlock
51         if ((&cmd_client)->cbuf->lock)
52                 Cbuf_Unlock((&cmd_client)->cbuf);
53         if ((&cmd_server)->cbuf->lock)
54                 Cbuf_Unlock((&cmd_server)->cbuf);
55         SV_UnlockThreadMutex();
56         TaskQueue_Frame(true);
57
58         if (Sys_CheckParm("-profilegameonly"))
59                 Sys_AllowProfiling(false);
60         host.state = host_shutdown;
61         Host_Shutdown();
62         exit(returnvalue);
63 }
64
65 #ifdef __cplusplus
66 extern "C"
67 #endif
68 void Sys_AllowProfiling(qbool enable)
69 {
70 #ifdef __ANDROID__
71 #ifdef USE_PROFILER
72         extern void monstartup(const char *libname);
73         extern void moncleanup(void);
74         if (enable)
75                 monstartup("libmain.so");
76         else
77                 moncleanup();
78 #endif
79 #elif (defined(__linux__) && (defined(__GLIBC__) || defined(__GNU_LIBRARY__))) || defined(__FreeBSD__)
80         extern int moncontrol(int);
81         moncontrol(enable);
82 #endif
83 }
84
85
86 /*
87 ===============================================================================
88
89 DLL MANAGEMENT
90
91 ===============================================================================
92 */
93
94 static qbool Sys_LoadLibraryFunctions(dllhandle_t dllhandle, const dllfunction_t *fcts, qbool complain, qbool has_next)
95 {
96         const dllfunction_t *func;
97         if(dllhandle)
98         {
99                 for (func = fcts; func && func->name != NULL; func++)
100                         if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
101                         {
102                                 if(complain)
103                                 {
104                                         Con_DPrintf (" - missing function \"%s\" - broken library!", func->name);
105                                         if(has_next)
106                                                 Con_DPrintf("\nContinuing with");
107                                 }
108                                 goto notfound;
109                         }
110                 return true;
111
112         notfound:
113                 for (func = fcts; func && func->name != NULL; func++)
114                         *func->funcvariable = NULL;
115         }
116         return false;
117 }
118
119 qbool Sys_LoadSelf(dllhandle_t *handle)
120 {
121         dllhandle_t dllhandle = 0;
122
123         if (handle == NULL)
124                 return false;
125 #ifdef WIN32
126         dllhandle = LoadLibrary (NULL);
127 #else
128         dllhandle = dlopen (NULL, RTLD_NOW | RTLD_GLOBAL);
129 #endif
130         *handle = dllhandle;
131         return true;
132 }
133
134 qbool Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
135 {
136 #ifdef SUPPORTDLL
137         const dllfunction_t *func;
138         dllhandle_t dllhandle = 0;
139         unsigned int i;
140
141         if (handle == NULL)
142                 return false;
143
144 #ifndef WIN32
145 #ifdef PREFER_PRELOAD
146         dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
147         if(Sys_LoadLibraryFunctions(dllhandle, fcts, false, false))
148         {
149                 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
150                 *handle = dllhandle;
151                 return true;
152         }
153         else
154                 Sys_UnloadLibrary(&dllhandle);
155 notfound:
156 #endif
157 #endif
158
159         // Initializations
160         for (func = fcts; func && func->name != NULL; func++)
161                 *func->funcvariable = NULL;
162
163         // Try every possible name
164         Con_DPrintf ("Trying to load library...");
165         for (i = 0; dllnames[i] != NULL; i++)
166         {
167                 Con_DPrintf (" \"%s\"", dllnames[i]);
168 #ifdef WIN32
169 # ifndef DONT_USE_SETDLLDIRECTORY
170 #  ifdef _WIN64
171                 SetDllDirectory("bin64");
172 #  else
173                 SetDllDirectory("bin32");
174 #  endif
175 # endif
176                 dllhandle = LoadLibrary (dllnames[i]);
177                 // no need to unset this - we want ALL dlls to be loaded from there, anyway
178 #else
179                 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
180 #endif
181                 if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, (dllnames[i+1] != NULL) || (strrchr(sys.argv[0], '/'))))
182                         break;
183                 else
184                         Sys_UnloadLibrary (&dllhandle);
185         }
186
187         // see if the names can be loaded relative to the executable path
188         // (this is for Mac OSX which does not check next to the executable)
189         if (!dllhandle && strrchr(sys.argv[0], '/'))
190         {
191                 char path[MAX_OSPATH];
192                 strlcpy(path, sys.argv[0], sizeof(path));
193                 strrchr(path, '/')[1] = 0;
194                 for (i = 0; dllnames[i] != NULL; i++)
195                 {
196                         char temp[MAX_OSPATH];
197                         strlcpy(temp, path, sizeof(temp));
198                         strlcat(temp, dllnames[i], sizeof(temp));
199                         Con_DPrintf (" \"%s\"", temp);
200 #ifdef WIN32
201                         dllhandle = LoadLibrary (temp);
202 #else
203                         dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
204 #endif
205                         if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, dllnames[i+1] != NULL))
206                                 break;
207                         else
208                                 Sys_UnloadLibrary (&dllhandle);
209                 }
210         }
211
212         // No DLL found
213         if (! dllhandle)
214         {
215                 Con_DPrintf(" - failed.\n");
216                 return false;
217         }
218
219         Con_DPrintf(" - loaded.\n");
220         Con_Printf("Loaded library \"%s\"\n", dllnames[i]);
221
222         *handle = dllhandle;
223         return true;
224 #else
225         return false;
226 #endif
227 }
228
229 void Sys_UnloadLibrary (dllhandle_t* handle)
230 {
231 #ifdef SUPPORTDLL
232         if (handle == NULL || *handle == NULL)
233                 return;
234
235 #ifdef WIN32
236         FreeLibrary (*handle);
237 #else
238         dlclose (*handle);
239 #endif
240
241         *handle = NULL;
242 #endif
243 }
244
245 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
246 {
247 #ifdef SUPPORTDLL
248 #ifdef WIN32
249         return (void *)GetProcAddress (handle, name);
250 #else
251         return (void *)dlsym (handle, name);
252 #endif
253 #else
254         return NULL;
255 #endif
256 }
257
258 #ifdef WIN32
259 # define HAVE_TIMEGETTIME 1
260 # define HAVE_QUERYPERFORMANCECOUNTER 1
261 # define HAVE_Sleep 1
262 #endif
263
264 #ifndef WIN32
265 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
266 # define HAVE_CLOCKGETTIME 1
267 #endif
268 // FIXME improve this check, manpage hints to DST_NONE
269 # define HAVE_GETTIMEOFDAY 1
270 #endif
271
272 #ifndef WIN32
273 // on Win32, select() cannot be used with all three FD list args being NULL according to MSDN
274 // (so much for POSIX...)
275 # ifdef FD_SET
276 #  define HAVE_SELECT 1
277 # endif
278 #endif
279
280 #ifndef WIN32
281 // FIXME improve this check
282 # define HAVE_USLEEP 1
283 #endif
284
285 // this one is referenced elsewhere
286 cvar_t sys_usenoclockbutbenchmark = {CF_CLIENT | CF_SERVER | CF_ARCHIVE, "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."};
287
288 // these are not
289 static cvar_t sys_debugsleep = {CF_CLIENT | CF_SERVER, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
290 static cvar_t sys_usesdlgetticks = {CF_CLIENT | CF_SERVER | CF_ARCHIVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
291 static cvar_t sys_usesdldelay = {CF_CLIENT | CF_SERVER | CF_ARCHIVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
292 #if HAVE_QUERYPERFORMANCECOUNTER
293 static cvar_t sys_usequeryperformancecounter = {CF_CLIENT | CF_SERVER | CF_ARCHIVE, "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)"};
294 #endif
295 #if HAVE_CLOCKGETTIME
296 static cvar_t sys_useclockgettime = {CF_CLIENT | CF_SERVER | CF_ARCHIVE, "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)"};
297 #endif
298
299 static double benchmark_time; // actually always contains an integer amount of milliseconds, will eventually "overflow"
300
301 /*
302 ================
303 Sys_CheckParm
304
305 Returns the position (1 to argc-1) in the program's argument list
306 where the given parameter apears, or 0 if not present
307 ================
308 */
309 int Sys_CheckParm (const char *parm)
310 {
311         int i;
312
313         for (i=1 ; i<sys.argc ; i++)
314         {
315                 if (!sys.argv[i])
316                         continue;               // NEXTSTEP sometimes clears appkit vars.
317                 if (!strcmp (parm,sys.argv[i]))
318                         return i;
319         }
320
321         return 0;
322 }
323
324 void Sys_Init_Commands (void)
325 {
326         Cvar_RegisterVariable(&sys_debugsleep);
327         Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
328 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
329         if(sys_supportsdlgetticks)
330         {
331                 Cvar_RegisterVariable(&sys_usesdlgetticks);
332                 Cvar_RegisterVariable(&sys_usesdldelay);
333         }
334 #endif
335 #if HAVE_QUERYPERFORMANCECOUNTER
336         Cvar_RegisterVariable(&sys_usequeryperformancecounter);
337 #endif
338 #if HAVE_CLOCKGETTIME
339         Cvar_RegisterVariable(&sys_useclockgettime);
340 #endif
341 }
342
343 double Sys_DirtyTime(void)
344 {
345         // first all the OPTIONAL timers
346
347         // benchmark timer (fake clock)
348         if(sys_usenoclockbutbenchmark.integer)
349         {
350                 double old_benchmark_time = benchmark_time;
351                 benchmark_time += 1;
352                 if(benchmark_time == old_benchmark_time)
353                         Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry");
354                 return benchmark_time * 0.000001;
355         }
356 #if HAVE_QUERYPERFORMANCECOUNTER
357         if (sys_usequeryperformancecounter.integer)
358         {
359                 // LadyHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
360                 // QueryPerformanceCounter
361                 // platform:
362                 // Windows 95/98/ME/NT/2000/XP
363                 // features:
364                 // very accurate (CPU cycles)
365                 // known issues:
366                 // does not necessarily match realtime too well (tends to get faster and faster in win98)
367                 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
368                 double timescale;
369                 LARGE_INTEGER PerformanceFreq;
370                 LARGE_INTEGER PerformanceCount;
371
372                 if (QueryPerformanceFrequency (&PerformanceFreq))
373                 {
374                         QueryPerformanceCounter (&PerformanceCount);
375         
376                         timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
377                         return ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
378                 }
379                 else
380                 {
381                         Con_Printf("No hardware timer available\n");
382                         // fall back to other clock sources
383                         Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
384                 }
385         }
386 #endif
387
388 #if HAVE_CLOCKGETTIME
389         if (sys_useclockgettime.integer)
390         {
391                 struct timespec ts;
392 #  ifdef CLOCK_MONOTONIC
393                 // linux
394                 clock_gettime(CLOCK_MONOTONIC, &ts);
395 #  else
396                 // sunos
397                 clock_gettime(CLOCK_HIGHRES, &ts);
398 #  endif
399                 return (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
400         }
401 #endif
402
403         // now all the FALLBACK timers
404         if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
405                 return (double) Sys_SDL_GetTicks() / 1000.0;
406 #if HAVE_GETTIMEOFDAY
407         {
408                 struct timeval tp;
409                 gettimeofday(&tp, NULL);
410                 return (double) tp.tv_sec + tp.tv_usec / 1000000.0;
411         }
412 #elif HAVE_TIMEGETTIME
413         {
414                 static int firsttimegettime = true;
415                 // timeGetTime
416                 // platform:
417                 // Windows 95/98/ME/NT/2000/XP
418                 // features:
419                 // reasonable accuracy (millisecond)
420                 // issues:
421                 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
422
423                 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
424                 if (firsttimegettime)
425                 {
426                         timeBeginPeriod(1);
427                         firsttimegettime = false;
428                 }
429
430                 return (double) timeGetTime() / 1000.0;
431         }
432 #else
433         // fallback for using the SDL timer if no other timer is available
434         // this calls Sys_Error() if not linking against SDL
435         return (double) Sys_SDL_GetTicks() / 1000.0;
436 #endif
437 }
438
439 void Sys_Sleep(int microseconds)
440 {
441         double t = 0;
442         if(sys_usenoclockbutbenchmark.integer)
443         {
444                 if(microseconds)
445                 {
446                         double old_benchmark_time = benchmark_time;
447                         benchmark_time += microseconds;
448                         if(benchmark_time == old_benchmark_time)
449                                 Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry");
450                 }
451                 return;
452         }
453         if(sys_debugsleep.integer)
454         {
455                 t = Sys_DirtyTime();
456         }
457         if(sys_supportsdlgetticks && sys_usesdldelay.integer)
458         {
459                 Sys_SDL_Delay(microseconds / 1000);
460         }
461 #if HAVE_SELECT
462         else
463         {
464                 struct timeval tv;
465                 tv.tv_sec = microseconds / 1000000;
466                 tv.tv_usec = microseconds % 1000000;
467                 select(0, NULL, NULL, NULL, &tv);
468         }
469 #elif HAVE_USLEEP
470         else
471         {
472                 usleep(microseconds);
473         }
474 #elif HAVE_Sleep
475         else
476         {
477                 Sleep(microseconds / 1000);
478         }
479 #else
480         else
481         {
482                 Sys_SDL_Delay(microseconds / 1000);
483         }
484 #endif
485         if(sys_debugsleep.integer)
486         {
487                 t = Sys_DirtyTime() - t;
488                 Sys_PrintfToTerminal("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
489         }
490 }
491
492 void Sys_PrintfToTerminal(const char *fmt, ...)
493 {
494         va_list argptr;
495         char msg[MAX_INPUTLINE];
496
497         va_start(argptr,fmt);
498         dpvsnprintf(msg,sizeof(msg),fmt,argptr);
499         va_end(argptr);
500
501         Sys_PrintToTerminal(msg);
502 }
503
504 #ifndef WIN32
505 static const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
506 {
507         const char *p = PATH;
508         const char *q;
509         if(p && name)
510         {
511                 while((q = strchr(p, ':')))
512                 {
513                         dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
514                         if(FS_SysFileExists(buf))
515                                 return buf;
516                         p = q + 1;
517                 }
518                 if(!q) // none found - try the last item
519                 {
520                         dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
521                         if(FS_SysFileExists(buf))
522                                 return buf;
523                 }
524         }
525         return name;
526 }
527 #endif
528
529 static const char *Sys_FindExecutableName(void)
530 {
531 #if defined(WIN32)
532         return sys.argv[0];
533 #else
534         static char exenamebuf[MAX_OSPATH+1];
535         ssize_t n = -1;
536 #if defined(__FreeBSD__)
537         int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
538         size_t exenamebuflen = sizeof(exenamebuf)-1;
539         if (sysctl(mib, 4, exenamebuf, &exenamebuflen, NULL, 0) == 0)
540         {
541                 n = exenamebuflen;
542         }
543 #elif defined(__linux__)
544         n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
545 #endif
546         if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
547         {
548                 exenamebuf[n] = 0;
549                 return exenamebuf;
550         }
551         if(strchr(sys.argv[0], '/'))
552                 return sys.argv[0]; // possibly a relative path
553         else
554                 return Sys_FindInPATH(sys.argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
555 #endif
556 }
557
558 void Sys_ProvideSelfFD(void)
559 {
560         if(sys.selffd != -1)
561                 return;
562         sys.selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);
563 }
564
565 // for x86 cpus only...  (x64 has SSE2_PRESENT)
566 #if defined(SSE_POSSIBLE) && !defined(SSE2_PRESENT)
567 // code from SDL, shortened as we can expect CPUID to work
568 static int CPUID_Features(void)
569 {
570         int features = 0;
571 # if (defined(__GNUC__) || defined(__clang__) || defined(__TINYC__)) && defined(__i386__)
572         __asm__ (
573 "        movl    %%ebx,%%edi\n"
574 "        xorl    %%eax,%%eax                                           \n"
575 "        incl    %%eax                                                 \n"
576 "        cpuid                       # Get family/model/stepping/features\n"
577 "        movl    %%edx,%0                                              \n"
578 "        movl    %%edi,%%ebx\n"
579         : "=m" (features)
580         :
581         : "%eax", "%ecx", "%edx", "%edi"
582         );
583 # elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
584         __asm {
585         xor     eax, eax
586         inc     eax
587         cpuid                       ; Get family/model/stepping/features
588         mov     features, edx
589         }
590 # else
591 #  error SSE_POSSIBLE set but no CPUID implementation
592 # endif
593         return features;
594 }
595 #endif
596
597 #ifdef SSE_POSSIBLE
598 qbool Sys_HaveSSE(void)
599 {
600         // COMMANDLINEOPTION: SSE: -nosse disables SSE support and detection
601         if(Sys_CheckParm("-nosse"))
602                 return false;
603 #ifdef SSE_PRESENT
604         return true;
605 #else
606         // COMMANDLINEOPTION: SSE: -forcesse enables SSE support and disables detection
607         if(Sys_CheckParm("-forcesse") || Sys_CheckParm("-forcesse2"))
608                 return true;
609         if(CPUID_Features() & (1 << 25))
610                 return true;
611         return false;
612 #endif
613 }
614
615 qbool Sys_HaveSSE2(void)
616 {
617         // COMMANDLINEOPTION: SSE2: -nosse2 disables SSE2 support and detection
618         if(Sys_CheckParm("-nosse") || Sys_CheckParm("-nosse2"))
619                 return false;
620 #ifdef SSE2_PRESENT
621         return true;
622 #else
623         // COMMANDLINEOPTION: SSE2: -forcesse2 enables SSE2 support and disables detection
624         if(Sys_CheckParm("-forcesse2"))
625                 return true;
626         if((CPUID_Features() & (3 << 25)) == (3 << 25)) // SSE is 1<<25, SSE2 is 1<<26
627                 return true;
628         return false;
629 #endif
630 }
631 #endif
632
633 /// called to set process priority for dedicated servers
634 #if defined(__linux__)
635 #include <sys/resource.h>
636 #include <errno.h>
637
638 void Sys_InitProcessNice (void)
639 {
640         struct rlimit lim;
641         sys.nicepossible = false;
642         if(Sys_CheckParm("-nonice"))
643                 return;
644         errno = 0;
645         sys.nicelevel = getpriority(PRIO_PROCESS, 0);
646         if(errno)
647         {
648                 Con_Printf("Kernel does not support reading process priority - cannot use niceness\n");
649                 return;
650         }
651         if(getrlimit(RLIMIT_NICE, &lim))
652         {
653                 Con_Printf("Kernel does not support lowering nice level again - cannot use niceness\n");
654                 return;
655         }
656         if(lim.rlim_cur != RLIM_INFINITY && sys.nicelevel < (int) (20 - lim.rlim_cur))
657         {
658                 Con_Printf("Current nice level is below the soft limit - cannot use niceness\n");
659                 return;
660         }
661         sys.nicepossible = true;
662         sys.isnice = false;
663 }
664 void Sys_MakeProcessNice (void)
665 {
666         if(!sys.nicepossible)
667                 return;
668         if(sys.isnice)
669                 return;
670         Con_DPrintf("Process is becoming 'nice'...\n");
671         if(setpriority(PRIO_PROCESS, 0, 19))
672                 Con_Printf(CON_ERROR "Failed to raise nice level to %d\n", 19);
673         sys.isnice = true;
674 }
675 void Sys_MakeProcessMean (void)
676 {
677         if(!sys.nicepossible)
678                 return;
679         if(!sys.isnice)
680                 return;
681         Con_DPrintf("Process is becoming 'mean'...\n");
682         if(setpriority(PRIO_PROCESS, 0, sys.nicelevel))
683                 Con_Printf(CON_ERROR "Failed to lower nice level to %d\n", sys.nicelevel);
684         sys.isnice = false;
685 }
686 #else
687 void Sys_InitProcessNice (void)
688 {
689 }
690 void Sys_MakeProcessNice (void)
691 {
692 }
693 void Sys_MakeProcessMean (void)
694 {
695 }
696 #endif