new cvar sys_useclockgettime (default 0) that makes DP use clock_gettime as time...
[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
170                 curtime += newtime - oldtime;
171         oldtime = newtime;
172
173         return curtime;
174 }
175
176 char *Sys_ConsoleInput(void)
177 {
178         if (cls.state == ca_dedicated)
179         {
180                 static char text[MAX_INPUTLINE];
181                 static unsigned int len = 0;
182 #ifdef WIN32
183                 int c;
184
185                 // read a line out
186                 while (_kbhit ())
187                 {
188                         c = _getch ();
189                         if (c == '\r')
190                         {
191                                 text[len] = '\0';
192                                 putch ('\n');
193                                 len = 0;
194                                 return text;
195                         }
196                         if (c == '\b')
197                         {
198                                 if (len)
199                                 {
200                                         putch (c);
201                                         putch (' ');
202                                         putch (c);
203                                         len--;
204                                 }
205                                 continue;
206                         }
207                         if (len < sizeof (text) - 1)
208                         {
209                                 putch (c);
210                                 text[len] = c;
211                                 len++;
212                         }
213                 }
214 #else
215                 fd_set fdset;
216                 struct timeval timeout;
217                 FD_ZERO(&fdset);
218                 FD_SET(0, &fdset); // stdin
219                 timeout.tv_sec = 0;
220                 timeout.tv_usec = 0;
221                 if (select (1, &fdset, NULL, NULL, &timeout) != -1 && FD_ISSET(0, &fdset))
222                 {
223                         len = read (0, text, sizeof(text));
224                         if (len >= 1)
225                         {
226                                 // rip off the \n and terminate
227                                 text[len-1] = 0;
228                                 return text;
229                         }
230                 }
231 #endif
232         }
233         return NULL;
234 }
235
236 void Sys_Sleep(int microseconds)
237 {
238 #ifdef WIN32
239         Sleep(microseconds / 1000);
240 #else
241         usleep(microseconds);
242 #endif
243 }
244
245 char *Sys_GetClipboardData (void)
246 {
247         return NULL;
248 }
249
250 void Sys_InitConsole (void)
251 {
252 }
253
254 void Sys_Init_Commands (void)
255 {
256 #ifdef WIN32
257         Cvar_RegisterVariable(&sys_usetimegettime);
258 #else
259 # ifndef MACOSX
260         Cvar_RegisterVariable(&sys_useclockgettime);
261 # endif
262 #endif
263 }
264
265 int main (int argc, char **argv)
266 {
267         signal(SIGFPE, SIG_IGN);
268
269         com_argc = argc;
270         com_argv = (const char **)argv;
271
272 #ifndef WIN32
273         fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
274 #endif
275
276         Host_Main();
277
278         return 0;
279 }