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