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