fix a bunch of warnings if compiling darkplaces as C++ in MSVC2008
[divverent/darkplaces.git] / sys_shared.c
1 #include "quakedef.h"
2
3 #define SUPPORTDLL
4
5 #ifdef WIN32
6 # include <windows.h>
7 # include <mmsystem.h> // timeGetTime
8 # include <time.h> // localtime
9 #pragma comment(lib, "winmm.lib")
10 #else
11 # include <unistd.h>
12 # include <fcntl.h>
13 # include <sys/time.h>
14 # include <time.h>
15 # ifdef SUPPORTDLL
16 #  include <dlfcn.h>
17 # endif
18 #endif
19
20 static char sys_timestring[128];
21 char *Sys_TimeString(const char *timeformat)
22 {
23         time_t mytime = time(NULL);
24 #if _MSC_VER >= 1400
25         struct tm mytm;
26         localtime_s(&mytm, &mytime);
27         strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
28 #else
29         strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
30 #endif
31         return sys_timestring;
32 }
33
34
35 extern qboolean host_shuttingdown;
36 void Sys_Quit (int returnvalue)
37 {
38         if (COM_CheckParm("-profilegameonly"))
39                 Sys_AllowProfiling(false);
40         host_shuttingdown = true;
41         Host_Shutdown();
42         exit(returnvalue);
43 }
44
45 #if defined(__linux__) || defined(__FreeBSD__)
46 #ifdef __cplusplus
47 extern "C"
48 #endif
49 int moncontrol(int);
50 #endif
51
52 void Sys_AllowProfiling(qboolean enable)
53 {
54 #if defined(__linux__) || defined(__FreeBSD__)
55         moncontrol(enable);
56 #endif
57 }
58
59
60 /*
61 ===============================================================================
62
63 DLL MANAGEMENT
64
65 ===============================================================================
66 */
67
68 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
69 {
70 #ifdef SUPPORTDLL
71         const dllfunction_t *func;
72         dllhandle_t dllhandle = 0;
73         unsigned int i;
74
75         if (handle == NULL)
76                 return false;
77
78 #ifndef WIN32
79 #ifdef PREFER_PRELOAD
80         dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
81         if(dllhandle)
82         {
83                 for (func = fcts; func && func->name != NULL; func++)
84                         if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
85                         {
86                                 dlclose(dllhandle);
87                                 goto notfound;
88                         }
89                 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
90                 *handle = dllhandle;
91                 return true;
92         }
93 notfound:
94 #endif
95 #endif
96
97         // Initializations
98         for (func = fcts; func && func->name != NULL; func++)
99                 *func->funcvariable = NULL;
100
101         // Try every possible name
102         Con_DPrintf ("Trying to load library...");
103         for (i = 0; dllnames[i] != NULL; i++)
104         {
105                 Con_DPrintf (" \"%s\"", dllnames[i]);
106 #ifdef WIN32
107                 dllhandle = LoadLibrary (dllnames[i]);
108 #else
109                 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
110 #endif
111                 if (dllhandle)
112                         break;
113         }
114
115         // see if the names can be loaded relative to the executable path
116         // (this is for Mac OSX which does not check next to the executable)
117         if (!dllhandle && strrchr(com_argv[0], '/'))
118         {
119                 char path[MAX_OSPATH];
120                 strlcpy(path, com_argv[0], sizeof(path));
121                 strrchr(path, '/')[1] = 0;
122                 for (i = 0; dllnames[i] != NULL; i++)
123                 {
124                         char temp[MAX_OSPATH];
125                         strlcpy(temp, path, sizeof(temp));
126                         strlcat(temp, dllnames[i], sizeof(temp));
127                         Con_DPrintf (" \"%s\"", temp);
128 #ifdef WIN32
129                         dllhandle = LoadLibrary (temp);
130 #else
131                         dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
132 #endif
133                         if (dllhandle)
134                                 break;
135                 }
136         }
137
138         // No DLL found
139         if (! dllhandle)
140         {
141                 Con_DPrintf(" - failed.\n");
142                 return false;
143         }
144
145         Con_DPrintf(" - loaded.\n");
146
147         // Get the function adresses
148         for (func = fcts; func && func->name != NULL; func++)
149                 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
150                 {
151                         Con_DPrintf ("Missing function \"%s\" - broken library!\n", func->name);
152                         Sys_UnloadLibrary (&dllhandle);
153                         return false;
154                 }
155
156         *handle = dllhandle;
157         return true;
158 #else
159         return false;
160 #endif
161 }
162
163 void Sys_UnloadLibrary (dllhandle_t* handle)
164 {
165 #ifdef SUPPORTDLL
166         if (handle == NULL || *handle == NULL)
167                 return;
168
169 #ifdef WIN32
170         FreeLibrary (*handle);
171 #else
172         dlclose (*handle);
173 #endif
174
175         *handle = NULL;
176 #endif
177 }
178
179 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
180 {
181 #ifdef SUPPORTDLL
182 #ifdef WIN32
183         return (void *)GetProcAddress (handle, name);
184 #else
185         return (void *)dlsym (handle, name);
186 #endif
187 #else
188         return NULL;
189 #endif
190 }
191
192 #ifdef WIN32
193 # define HAVE_TIMEGETTIME 1
194 # define HAVE_QUERYPERFORMANCECOUNTER 1
195 # define HAVE_Sleep 1
196 #endif
197
198 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
199 # define HAVE_CLOCKGETTIME 1
200 #endif
201
202 #ifndef WIN32
203 // FIXME improve this check, manpage hints to DST_NONE
204 # define HAVE_GETTIMEOFDAY 1
205 #endif
206
207 #ifdef FD_SET
208 # define HAVE_SELECT 1
209 #endif
210
211 #ifndef WIN32
212 // FIXME improve this check
213 # define HAVE_USLEEP 1
214 #endif
215
216 // this one is referenced elsewhere
217 cvar_t sys_usenoclockbutbenchmark = {CVAR_SAVE, "sys_usenoclockbutbenchmark", "0", "don't use ANY real timing, and simulate a clock (for benchmarking); the game then runs as fast as possible. Run a QC mod with bots that does some stuff, then does a quit at the end, to benchmark a server. NEVER do this on a public server."};
218
219 // these are not
220 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
221 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
222 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
223 #if HAVE_QUERYPERFORMANCECOUNTER
224 static cvar_t sys_usequeryperformancecounter = {CVAR_SAVE, "sys_usequeryperformancecounter", "0", "use windows QueryPerformanceCounter timer (which has issues on multicore/multiprocessor machines and processors which are designed to conserve power) for timing rather than timeGetTime function (which has issues on some motherboards)"};
225 #endif
226 #if HAVE_CLOCKGETTIME
227 static cvar_t sys_useclockgettime = {CVAR_SAVE, "sys_useclockgettime", "0", "use POSIX clock_gettime function (which has issues if the system clock speed is far off, as it can't get fixed by NTP) for timing rather than gettimeofday (which has issues if the system time is stepped by ntpdate, or apparently on some Xen installations)"};
228 #endif
229
230 static unsigned long benchmark_time;
231
232 void Sys_Init_Commands (void)
233 {
234         Cvar_RegisterVariable(&sys_debugsleep);
235         Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
236 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
237         if(sys_supportsdlgetticks)
238         {
239                 Cvar_RegisterVariable(&sys_usesdlgetticks);
240                 Cvar_RegisterVariable(&sys_usesdldelay);
241         }
242 #endif
243 #if HAVE_QUERYPERFORMANCECOUNTER
244         Cvar_RegisterVariable(&sys_usequeryperformancecounter);
245 #endif
246 #if HAVE_CLOCKGETTIME
247         Cvar_RegisterVariable(&sys_useclockgettime);
248 #endif
249 }
250
251 double Sys_DoubleTime(void)
252 {
253         static int first = true;
254         static double oldtime = 0.0, curtime = 0.0;
255         double newtime;
256         if(sys_usenoclockbutbenchmark.integer)
257         {
258                 benchmark_time += 1;
259                 return ((double) benchmark_time) / 1e6;
260         }
261
262         // first all the OPTIONAL timers
263
264 #if HAVE_QUERYPERFORMANCECOUNTER
265         else if (sys_usequeryperformancecounter.integer)
266         {
267                 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
268                 // QueryPerformanceCounter
269                 // platform:
270                 // Windows 95/98/ME/NT/2000/XP
271                 // features:
272                 // very accurate (CPU cycles)
273                 // known issues:
274                 // does not necessarily match realtime too well (tends to get faster and faster in win98)
275                 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
276                 double timescale;
277                 LARGE_INTEGER PerformanceFreq;
278                 LARGE_INTEGER PerformanceCount;
279
280                 if (!QueryPerformanceFrequency (&PerformanceFreq))
281                 {
282                         Con_Printf ("No hardware timer available\n");
283                         // fall back to timeGetTime
284                         Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
285                         return Sys_DoubleTime();
286                 }
287                 QueryPerformanceCounter (&PerformanceCount);
288
289                 #ifdef __BORLANDC__
290                 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
291                 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
292                 #else
293                 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
294                 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
295                 #endif
296         }
297 #endif
298
299 #if HAVE_CLOCKGETTIME
300         else if (sys_useclockgettime.integer)
301         {
302                 struct timespec ts;
303 #  ifdef CLOCK_MONOTONIC
304                 // linux
305                 clock_gettime(CLOCK_MONOTONIC, &ts);
306 #  else
307                 // sunos
308                 clock_gettime(CLOCK_HIGHRES, &ts);
309 #  endif
310                 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
311         }
312 #endif
313
314         // now all the FALLBACK timers
315         else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
316         {
317                 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
318         }
319 #if HAVE_GETTIMEOFDAY
320         else
321         {
322                 struct timeval tp;
323                 gettimeofday(&tp, NULL);
324                 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
325         }
326 #elif HAVE_TIMEGETTIME
327         else
328         {
329                 static int firsttimegettime = true;
330                 // timeGetTime
331                 // platform:
332                 // Windows 95/98/ME/NT/2000/XP
333                 // features:
334                 // reasonable accuracy (millisecond)
335                 // issues:
336                 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
337
338                 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
339                 if (firsttimegettime)
340                 {
341                         timeBeginPeriod (1);
342                         firsttimegettime = false;
343                 }
344
345                 newtime = (double) timeGetTime () / 1000.0;
346         }
347 #else
348         // fallback for using the SDL timer if no other timer is available
349         else
350         {
351                 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
352                 // this calls Sys_Error() if not linking against SDL
353         }
354 #endif
355
356         if (first)
357         {
358                 first = false;
359                 oldtime = newtime;
360         }
361
362         if (newtime < oldtime)
363         {
364                 // warn if it's significant
365                 if (newtime - oldtime < -0.01)
366                         Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
367         }
368         else if (newtime > oldtime + 1800)
369         {
370                 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
371         }
372         else
373                 curtime += newtime - oldtime;
374         oldtime = newtime;
375
376         return curtime;
377 }
378
379 void Sys_Sleep(int microseconds)
380 {
381         double t = 0;
382         if(sys_usenoclockbutbenchmark.integer)
383         {
384                 benchmark_time += microseconds;
385                 return;
386         }
387         if(sys_debugsleep.integer)
388         {
389                 t = Sys_DoubleTime();
390         }
391         if(sys_supportsdlgetticks && sys_usesdldelay.integer)
392         {
393                 Sys_SDL_Delay(microseconds / 1000);
394         }
395 #if HAVE_SELECT
396         else
397         {
398                 struct timeval tv;
399                 tv.tv_sec = microseconds / 1000000;
400                 tv.tv_usec = microseconds % 1000000;
401                 select(0, NULL, NULL, NULL, &tv);
402         }
403 #elif HAVE_USLEEP
404         else
405         {
406                 usleep(microseconds);
407         }
408 #elif HAVE_Sleep
409         else
410         {
411                 Sleep(microseconds / 1000);
412         }
413 #else
414         else
415         {
416                 Sys_SDL_Delay(microseconds / 1000);
417         }
418 #endif
419         if(sys_debugsleep.integer)
420         {
421                 t = Sys_DoubleTime() - t;
422                 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
423         }
424 }
425
426 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
427 {
428         const char *p = PATH;
429         const char *q;
430         if(p && name)
431         {
432                 while((q = strchr(p, ':')))
433                 {
434                         dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
435                         if(FS_SysFileExists(buf))
436                                 return buf;
437                         p = q + 1;
438                 }
439                 if(!q) // none found - try the last item
440                 {
441                         dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
442                         if(FS_SysFileExists(buf))
443                                 return buf;
444                 }
445         }
446         return name;
447 }
448
449 const char *Sys_FindExecutableName(void)
450 {
451 #if defined(WIN32)
452         return com_argv[0];
453 #else
454         static char exenamebuf[MAX_OSPATH+1];
455         ssize_t n = -1;
456 #if defined(__FreeBSD__)
457         n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
458 #elif defined(__linux__)
459         n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
460 #endif
461         if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
462         {
463                 exenamebuf[n] = 0;
464                 return exenamebuf;
465         }
466         if(strchr(com_argv[0], '/'))
467                 return com_argv[0]; // possibly a relative path
468         else
469                 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
470 #endif
471 }
472
473 void Sys_ProvideSelfFD(void)
474 {
475         if(com_selffd != -1)
476                 return;
477         com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);
478 }