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