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