also reject time stepping > 30 minutes (this threshold is < 1 hour to reject daylight...
[divverent/darkplaces.git] / sys_linux.c
1 #include "quakedef.h"
2
3 #ifdef WIN32
4 #include <io.h>
5 #include "conio.h"
6 #else
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <sys/time.h>
10 #include <time.h>
11 #endif
12
13 #include <signal.h>
14
15
16 #ifdef WIN32
17 cvar_t sys_usetimegettime = {CVAR_SAVE, "sys_usetimegettime", "1", "use windows timeGetTime function (which has issues on some motherboards) for timing rather than QueryPerformanceCounter timer (which has issues on multicore/multiprocessor machines and processors which are designed to conserve power)"};
18 #else
19 # ifndef MACOSX
20 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)"};
21 # endif
22 #endif
23
24
25
26 // =======================================================================
27 // General routines
28 // =======================================================================
29 void Sys_Shutdown (void)
30 {
31 #ifndef WIN32
32         fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
33 #endif
34         fflush(stdout);
35 }
36
37 void Sys_Error (const char *error, ...)
38 {
39         va_list argptr;
40         char string[MAX_INPUTLINE];
41
42 // change stdin to non blocking
43 #ifndef WIN32
44         fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
45 #endif
46
47         va_start (argptr,error);
48         dpvsnprintf (string, sizeof (string), error, argptr);
49         va_end (argptr);
50
51         Con_Printf ("Quake Error: %s\n", string);
52
53         Host_Shutdown ();
54         exit (1);
55 }
56
57 void Sys_PrintToTerminal(const char *text)
58 {
59 #ifndef WIN32
60         // BUG: for some reason, NDELAY also affects stdout (1) when used on stdin (0).
61         int origflags = fcntl (1, F_GETFL, 0);
62         fcntl (1, F_SETFL, origflags & ~FNDELAY);
63 #endif
64         while(*text)
65         {
66                 int written = (int)write(1, text, (int)strlen(text));
67                 if(written <= 0)
68                         break; // sorry, I cannot do anything about this error - without an output
69                 text += written;
70         }
71 #ifndef WIN32
72         fcntl (1, F_SETFL, origflags);
73 #endif
74         //fprintf(stdout, "%s", text);
75 }
76
77 double Sys_DoubleTime (void)
78 {
79         static int first = true;
80         static double oldtime = 0.0, curtime = 0.0;
81         double newtime;
82 #ifdef WIN32
83 #include <mmsystem.h>
84         // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
85         if (sys_usetimegettime.integer)
86         {
87                 static int firsttimegettime = true;
88                 // timeGetTime
89                 // platform:
90                 // Windows 95/98/ME/NT/2000/XP
91                 // features:
92                 // reasonable accuracy (millisecond)
93                 // issues:
94                 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
95
96                 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
97                 if (firsttimegettime)
98                 {
99                         timeBeginPeriod (1);
100                         firsttimegettime = false;
101                 }
102
103                 newtime = (double) timeGetTime () / 1000.0;
104         }
105         else
106         {
107                 // QueryPerformanceCounter
108                 // platform:
109                 // Windows 95/98/ME/NT/2000/XP
110                 // features:
111                 // very accurate (CPU cycles)
112                 // known issues:
113                 // does not necessarily match realtime too well (tends to get faster and faster in win98)
114                 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
115                 double timescale;
116                 LARGE_INTEGER PerformanceFreq;
117                 LARGE_INTEGER PerformanceCount;
118
119                 if (!QueryPerformanceFrequency (&PerformanceFreq))
120                 {
121                         Con_Printf ("No hardware timer available\n");
122                         // fall back to timeGetTime
123                         Cvar_SetValueQuick(&sys_usetimegettime, true);
124                         return Sys_DoubleTime();
125                 }
126                 QueryPerformanceCounter (&PerformanceCount);
127
128                 #ifdef __BORLANDC__
129                 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
130                 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
131                 #else
132                 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
133                 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
134                 #endif
135         }
136 #else
137 # ifndef MACOSX
138         if (sys_useclockgettime.integer)
139         {
140                 struct timespec ts;
141 #  ifdef SUNOS
142                 clock_gettime(CLOCK_HIGHRES, &ts);
143 #  else
144                 clock_gettime(CLOCK_MONOTONIC, &ts);
145 #  endif
146                 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
147         }
148         else
149 # endif
150         {
151                 struct timeval tp;
152                 gettimeofday(&tp, NULL);
153                 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
154         }
155 #endif
156
157         if (first)
158         {
159                 first = false;
160                 oldtime = newtime;
161         }
162
163         if (newtime < oldtime)
164         {
165                 // warn if it's significant
166                 if (newtime - oldtime < -0.01)
167                         Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
168         }
169         else if (newtime > oldtime + 1800)
170         {
171                 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
172         }
173         else
174                 curtime += newtime - oldtime;
175         oldtime = newtime;
176
177         return curtime;
178 }
179
180 char *Sys_ConsoleInput(void)
181 {
182         if (cls.state == ca_dedicated)
183         {
184                 static char text[MAX_INPUTLINE];
185                 static unsigned int len = 0;
186 #ifdef WIN32
187                 int c;
188
189                 // read a line out
190                 while (_kbhit ())
191                 {
192                         c = _getch ();
193                         if (c == '\r')
194                         {
195                                 text[len] = '\0';
196                                 putch ('\n');
197                                 len = 0;
198                                 return text;
199                         }
200                         if (c == '\b')
201                         {
202                                 if (len)
203                                 {
204                                         putch (c);
205                                         putch (' ');
206                                         putch (c);
207                                         len--;
208                                 }
209                                 continue;
210                         }
211                         if (len < sizeof (text) - 1)
212                         {
213                                 putch (c);
214                                 text[len] = c;
215                                 len++;
216                         }
217                 }
218 #else
219                 fd_set fdset;
220                 struct timeval timeout;
221                 FD_ZERO(&fdset);
222                 FD_SET(0, &fdset); // stdin
223                 timeout.tv_sec = 0;
224                 timeout.tv_usec = 0;
225                 if (select (1, &fdset, NULL, NULL, &timeout) != -1 && FD_ISSET(0, &fdset))
226                 {
227                         len = read (0, text, sizeof(text));
228                         if (len >= 1)
229                         {
230                                 // rip off the \n and terminate
231                                 text[len-1] = 0;
232                                 return text;
233                         }
234                 }
235 #endif
236         }
237         return NULL;
238 }
239
240 void Sys_Sleep(int microseconds)
241 {
242 #ifdef WIN32
243         Sleep(microseconds / 1000);
244 #else
245         usleep(microseconds);
246 #endif
247 }
248
249 char *Sys_GetClipboardData (void)
250 {
251         return NULL;
252 }
253
254 void Sys_InitConsole (void)
255 {
256 }
257
258 void Sys_Init_Commands (void)
259 {
260 #ifdef WIN32
261         Cvar_RegisterVariable(&sys_usetimegettime);
262 #else
263 # ifndef MACOSX
264         Cvar_RegisterVariable(&sys_useclockgettime);
265 # endif
266 #endif
267 }
268
269 int main (int argc, char **argv)
270 {
271         signal(SIGFPE, SIG_IGN);
272
273         com_argc = argc;
274         com_argv = (const char **)argv;
275
276 #ifndef WIN32
277         fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
278 #endif
279
280         Host_Main();
281
282         return 0;
283 }