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