Add patch that contain Mali fixes.
[deb_xorg-server.git] / os / WaitFor.c
1 /***********************************************************
2
3 Copyright 1987, 1998 The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27 All Rights Reserved
28
29 Permission to use, copy, modify, and distribute this software and its
30 documentation for any purpose and without fee is hereby granted,
31 provided that the above copyright notice appear in all copies and that
32 both that copyright notice and this permission notice appear in
33 supporting documentation, and that the name of Digital not be
34 used in advertising or publicity pertaining to distribution of the
35 software without specific, written prior permission.
36
37 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43 SOFTWARE.
44
45 ******************************************************************/
46
47 /*****************************************************************
48 * OS Dependent input routines:
49 *
50 * WaitForSomething
51 * TimerForce, TimerSet, TimerCheck, TimerFree
52 *
53 *****************************************************************/
54
55 #ifdef HAVE_DIX_CONFIG_H
56 #include <dix-config.h>
57 #endif
58
59 #ifdef WIN32
60 #include <X11/Xwinsock.h>
61 #endif
62 #include <X11/Xos.h> /* for strings, fcntl, time */
63 #include <errno.h>
64 #include <stdio.h>
65 #include <X11/X.h>
66 #include "misc.h"
67
68 #include "osdep.h"
69 #include <X11/Xpoll.h>
70 #include "dixstruct.h"
71 #include "opaque.h"
72 #ifdef DPMSExtension
73 #include "dpmsproc.h"
74 #endif
75 #include "busfault.h"
76
77 #ifdef WIN32
78 /* Error codes from windows sockets differ from fileio error codes */
79 #undef EINTR
80 #define EINTR WSAEINTR
81 #undef EINVAL
82 #define EINVAL WSAEINVAL
83 #undef EBADF
84 #define EBADF WSAENOTSOCK
85 /* Windows select does not set errno. Use GetErrno as wrapper for
86 WSAGetLastError */
87 #define GetErrno WSAGetLastError
88 #else
89 /* This is just a fallback to errno to hide the differences between unix and
90 Windows in the code */
91 #define GetErrno() errno
92 #endif
93
94 /* like ffs, but uses fd_mask instead of int as argument, so it works
95 when fd_mask is longer than an int, such as common 64-bit platforms */
96 /* modifications by raphael */
97 int
98 mffs(fd_mask mask)
99 {
100 int i;
101
102 if (!mask)
103 return 0;
104 i = 1;
105 while (!(mask & 1)) {
106 i++;
107 mask >>= 1;
108 }
109 return i;
110 }
111
112 #ifdef DPMSExtension
113 #include <X11/extensions/dpmsconst.h>
114 #endif
115
116 struct _OsTimerRec {
117 OsTimerPtr next;
118 CARD32 expires;
119 CARD32 delta;
120 OsTimerCallback callback;
121 pointer arg;
122 };
123
124 static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev);
125 static void CheckAllTimers(void);
126 static OsTimerPtr timers = NULL;
127
128 /*****************
129 * WaitForSomething:
130 * Make the server suspend until there is
131 * 1. data from clients or
132 * 2. input events available or
133 * 3. ddx notices something of interest (graphics
134 * queue ready, etc.) or
135 * 4. clients that have buffered replies/events are ready
136 *
137 * If the time between INPUT events is
138 * greater than ScreenSaverTime, the display is turned off (or
139 * saved, depending on the hardware). So, WaitForSomething()
140 * has to handle this also (that's why the select() has a timeout.
141 * For more info on ClientsWithInput, see ReadRequestFromClient().
142 * pClientsReady is an array to store ready client->index values into.
143 *****************/
144
145 int
146 WaitForSomething(int *pClientsReady)
147 {
148 int i;
149 struct timeval waittime, *wt;
150 INT32 timeout = 0;
151 fd_set clientsReadable;
152 fd_set clientsWritable;
153 int curclient;
154 int selecterr;
155 static int nready;
156 fd_set devicesReadable;
157 CARD32 now = 0;
158 Bool someReady = FALSE;
159
160 FD_ZERO(&clientsReadable);
161
162 if (nready)
163 SmartScheduleStopTimer();
164 nready = 0;
165
166 #ifdef BUSFAULT
167 busfault_check();
168 #endif
169
170 /* We need a while loop here to handle
171 crashed connections and the screen saver timeout */
172 while (1) {
173 /* deal with any blocked jobs */
174 if (workQueue)
175 ProcessWorkQueue();
176 if (XFD_ANYSET(&ClientsWithInput)) {
177 if (!SmartScheduleDisable) {
178 someReady = TRUE;
179 waittime.tv_sec = 0;
180 waittime.tv_usec = 0;
181 wt = &waittime;
182 }
183 else {
184 XFD_COPYSET(&ClientsWithInput, &clientsReadable);
185 break;
186 }
187 }
188 if (someReady) {
189 XFD_COPYSET(&AllSockets, &LastSelectMask);
190 XFD_UNSET(&LastSelectMask, &ClientsWithInput);
191 }
192 else {
193 wt = NULL;
194 if (timers) {
195 now = GetTimeInMillis();
196 timeout = timers->expires - now;
197 if (timeout > 0 && timeout > timers->delta + 250) {
198 /* time has rewound. reset the timers. */
199 CheckAllTimers();
200 }
201
202 if (timers) {
203 timeout = timers->expires - now;
204 if (timeout < 0)
205 timeout = 0;
206 waittime.tv_sec = timeout / MILLI_PER_SECOND;
207 waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
208 (1000000 / MILLI_PER_SECOND);
209 wt = &waittime;
210 }
211 }
212 XFD_COPYSET(&AllSockets, &LastSelectMask);
213 }
214
215 BlockHandler((pointer) &wt, (pointer) &LastSelectMask);
216 if (NewOutputPending)
217 FlushAllOutput();
218 /* keep this check close to select() call to minimize race */
219 if (dispatchException)
220 i = -1;
221 else if (AnyClientsWriteBlocked) {
222 XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable);
223 i = Select(MaxClients, &LastSelectMask, &clientsWritable, NULL, wt);
224 }
225 else {
226 i = Select(MaxClients, &LastSelectMask, NULL, NULL, wt);
227 }
228 selecterr = GetErrno();
229 WakeupHandler(i, (pointer) &LastSelectMask);
230 if (i <= 0) { /* An error or timeout occurred */
231 if (dispatchException)
232 return 0;
233 if (i < 0) {
234 if (selecterr == EBADF) { /* Some client disconnected */
235 CheckConnections();
236 if (!XFD_ANYSET(&AllClients))
237 return 0;
238 }
239 else if (selecterr == EINVAL) {
240 FatalError("WaitForSomething(): select: %s\n",
241 strerror(selecterr));
242 }
243 else if (selecterr != EINTR && selecterr != EAGAIN) {
244 ErrorF("WaitForSomething(): select: %s\n",
245 strerror(selecterr));
246 }
247 }
248 else if (someReady) {
249 /*
250 * If no-one else is home, bail quickly
251 */
252 XFD_COPYSET(&ClientsWithInput, &LastSelectMask);
253 XFD_COPYSET(&ClientsWithInput, &clientsReadable);
254 break;
255 }
256 if (*checkForInput[0] != *checkForInput[1])
257 return 0;
258
259 if (timers) {
260 int expired = 0;
261
262 now = GetTimeInMillis();
263 if ((int) (timers->expires - now) <= 0)
264 expired = 1;
265
266 while (timers && (int) (timers->expires - now) <= 0)
267 DoTimer(timers, now, &timers);
268
269 if (expired)
270 return 0;
271 }
272 }
273 else {
274 fd_set tmp_set;
275
276 if (*checkForInput[0] == *checkForInput[1]) {
277 if (timers) {
278 int expired = 0;
279
280 now = GetTimeInMillis();
281 if ((int) (timers->expires - now) <= 0)
282 expired = 1;
283
284 while (timers && (int) (timers->expires - now) <= 0)
285 DoTimer(timers, now, &timers);
286
287 if (expired)
288 return 0;
289 }
290 }
291 if (someReady)
292 XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask);
293 if (AnyClientsWriteBlocked && XFD_ANYSET(&clientsWritable)) {
294 NewOutputPending = TRUE;
295 XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
296 XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
297 if (!XFD_ANYSET(&ClientsWriteBlocked))
298 AnyClientsWriteBlocked = FALSE;
299 }
300
301 XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices);
302 XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
303 XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections);
304 if (XFD_ANYSET(&tmp_set))
305 QueueWorkProc(EstablishNewConnections, NULL,
306 (pointer) &LastSelectMask);
307
308 if (XFD_ANYSET(&devicesReadable) || XFD_ANYSET(&clientsReadable))
309 break;
310 /* check here for DDXes that queue events during Block/Wakeup */
311 if (*checkForInput[0] != *checkForInput[1])
312 return 0;
313 }
314 }
315
316 nready = 0;
317 if (XFD_ANYSET(&clientsReadable)) {
318 #ifndef WIN32
319 for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
320 int highest_priority = 0;
321
322 while (clientsReadable.fds_bits[i]) {
323 int client_priority, client_index;
324
325 curclient = mffs(clientsReadable.fds_bits[i]) - 1;
326 client_index = /* raphael: modified */
327 ConnectionTranslation[curclient +
328 (i * (sizeof(fd_mask) * 8))];
329 #else
330 int highest_priority = 0;
331 fd_set savedClientsReadable;
332
333 XFD_COPYSET(&clientsReadable, &savedClientsReadable);
334 for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++) {
335 int client_priority, client_index;
336
337 curclient = XFD_FD(&savedClientsReadable, i);
338 client_index = GetConnectionTranslation(curclient);
339 #endif
340 /* We implement "strict" priorities.
341 * Only the highest priority client is returned to
342 * dix. If multiple clients at the same priority are
343 * ready, they are all returned. This means that an
344 * aggressive client could take over the server.
345 * This was not considered a big problem because
346 * aggressive clients can hose the server in so many
347 * other ways :)
348 */
349 client_priority = clients[client_index]->priority;
350 if (nready == 0 || client_priority > highest_priority) {
351 /* Either we found the first client, or we found
352 * a client whose priority is greater than all others
353 * that have been found so far. Either way, we want
354 * to initialize the list of clients to contain just
355 * this client.
356 */
357 pClientsReady[0] = client_index;
358 highest_priority = client_priority;
359 nready = 1;
360 }
361 /* the following if makes sure that multiple same-priority
362 * clients get batched together
363 */
364 else if (client_priority == highest_priority) {
365 pClientsReady[nready++] = client_index;
366 }
367 #ifndef WIN32
368 clientsReadable.fds_bits[i] &= ~(((fd_mask) 1L) << curclient);
369 }
370 #else
371 FD_CLR(curclient, &clientsReadable);
372 #endif
373 }
374 }
375
376 if (nready)
377 SmartScheduleStartTimer();
378
379 return nready;
380 }
381
382 /* If time has rewound, re-run every affected timer.
383 * Timers might drop out of the list, so we have to restart every time. */
384 static void
385 CheckAllTimers(void)
386 {
387 OsTimerPtr timer;
388 CARD32 now;
389
390 OsBlockSignals();
391 start:
392 now = GetTimeInMillis();
393
394 for (timer = timers; timer; timer = timer->next) {
395 if (timer->expires - now > timer->delta + 250) {
396 TimerForce(timer);
397 goto start;
398 }
399 }
400 OsReleaseSignals();
401 }
402
403 static void
404 DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev)
405 {
406 CARD32 newTime;
407
408 OsBlockSignals();
409 *prev = timer->next;
410 timer->next = NULL;
411 newTime = (*timer->callback) (timer, now, timer->arg);
412 if (newTime)
413 TimerSet(timer, 0, newTime, timer->callback, timer->arg);
414 OsReleaseSignals();
415 }
416
417 OsTimerPtr
418 TimerSet(OsTimerPtr timer, int flags, CARD32 millis,
419 OsTimerCallback func, pointer arg)
420 {
421 register OsTimerPtr *prev;
422 CARD32 now = GetTimeInMillis();
423
424 if (!timer) {
425 timer = malloc(sizeof(struct _OsTimerRec));
426 if (!timer)
427 return NULL;
428 }
429 else {
430 OsBlockSignals();
431 for (prev = &timers; *prev; prev = &(*prev)->next) {
432 if (*prev == timer) {
433 *prev = timer->next;
434 if (flags & TimerForceOld)
435 (void) (*timer->callback) (timer, now, timer->arg);
436 break;
437 }
438 }
439 OsReleaseSignals();
440 }
441 if (!millis)
442 return timer;
443 if (flags & TimerAbsolute) {
444 timer->delta = millis - now;
445 }
446 else {
447 timer->delta = millis;
448 millis += now;
449 }
450 timer->expires = millis;
451 timer->callback = func;
452 timer->arg = arg;
453 if ((int) (millis - now) <= 0) {
454 timer->next = NULL;
455 millis = (*timer->callback) (timer, now, timer->arg);
456 if (!millis)
457 return timer;
458 }
459 OsBlockSignals();
460 for (prev = &timers;
461 *prev && (int) ((*prev)->expires - millis) <= 0;
462 prev = &(*prev)->next);
463 timer->next = *prev;
464 *prev = timer;
465 OsReleaseSignals();
466 return timer;
467 }
468
469 Bool
470 TimerForce(OsTimerPtr timer)
471 {
472 int rc = FALSE;
473 OsTimerPtr *prev;
474
475 OsBlockSignals();
476 for (prev = &timers; *prev; prev = &(*prev)->next) {
477 if (*prev == timer) {
478 DoTimer(timer, GetTimeInMillis(), prev);
479 rc = TRUE;
480 break;
481 }
482 }
483 OsReleaseSignals();
484 return rc;
485 }
486
487 void
488 TimerCancel(OsTimerPtr timer)
489 {
490 OsTimerPtr *prev;
491
492 if (!timer)
493 return;
494 OsBlockSignals();
495 for (prev = &timers; *prev; prev = &(*prev)->next) {
496 if (*prev == timer) {
497 *prev = timer->next;
498 break;
499 }
500 }
501 OsReleaseSignals();
502 }
503
504 void
505 TimerFree(OsTimerPtr timer)
506 {
507 if (!timer)
508 return;
509 TimerCancel(timer);
510 free(timer);
511 }
512
513 void
514 TimerCheck(void)
515 {
516 CARD32 now = GetTimeInMillis();
517
518 while (timers && (int) (timers->expires - now) <= 0)
519 DoTimer(timers, now, &timers);
520 }
521
522 void
523 TimerInit(void)
524 {
525 OsTimerPtr timer;
526
527 while ((timer = timers)) {
528 timers = timer->next;
529 free(timer);
530 }
531 }
532
533 #ifdef DPMSExtension
534
535 #define DPMS_CHECK_MODE(mode,time)\
536 if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\
537 DPMSSet(serverClient, mode);
538
539 #define DPMS_CHECK_TIMEOUT(time)\
540 if (time > 0 && (time - timeout) > 0)\
541 return time - timeout;
542
543 static CARD32
544 NextDPMSTimeout(INT32 timeout)
545 {
546 /*
547 * Return the amount of time remaining until we should set
548 * the next power level. Fallthroughs are intentional.
549 */
550 switch (DPMSPowerLevel) {
551 case DPMSModeOn:
552 DPMS_CHECK_TIMEOUT(DPMSStandbyTime)
553
554 case DPMSModeStandby:
555 DPMS_CHECK_TIMEOUT(DPMSSuspendTime)
556
557 case DPMSModeSuspend:
558 DPMS_CHECK_TIMEOUT(DPMSOffTime)
559
560 default: /* DPMSModeOff */
561 return 0;
562 }
563 }
564 #endif /* DPMSExtension */
565
566 static CARD32
567 ScreenSaverTimeoutExpire(OsTimerPtr timer, CARD32 now, pointer arg)
568 {
569 INT32 timeout = now - LastEventTime(XIAllDevices).milliseconds;
570 CARD32 nextTimeout = 0;
571
572 #ifdef DPMSExtension
573 /*
574 * Check each mode lowest to highest, since a lower mode can
575 * have the same timeout as a higher one.
576 */
577 if (DPMSEnabled) {
578 DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime)
579 DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime)
580 DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime)
581
582 nextTimeout = NextDPMSTimeout(timeout);
583 }
584
585 /*
586 * Only do the screensaver checks if we're not in a DPMS
587 * power saving mode
588 */
589 if (DPMSPowerLevel != DPMSModeOn)
590 return nextTimeout;
591 #endif /* DPMSExtension */
592
593 if (!ScreenSaverTime)
594 return nextTimeout;
595
596 if (timeout < ScreenSaverTime) {
597 return nextTimeout > 0 ?
598 min(ScreenSaverTime - timeout, nextTimeout) :
599 ScreenSaverTime - timeout;
600 }
601
602 ResetOsBuffers(); /* not ideal, but better than nothing */
603 dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive);
604
605 if (ScreenSaverInterval > 0) {
606 nextTimeout = nextTimeout > 0 ?
607 min(ScreenSaverInterval, nextTimeout) : ScreenSaverInterval;
608 }
609
610 return nextTimeout;
611 }
612
613 static OsTimerPtr ScreenSaverTimer = NULL;
614
615 void
616 FreeScreenSaverTimer(void)
617 {
618 if (ScreenSaverTimer) {
619 TimerFree(ScreenSaverTimer);
620 ScreenSaverTimer = NULL;
621 }
622 }
623
624 void
625 SetScreenSaverTimer(void)
626 {
627 CARD32 timeout = 0;
628
629 #ifdef DPMSExtension
630 if (DPMSEnabled) {
631 /*
632 * A higher DPMS level has a timeout that's either less
633 * than or equal to that of a lower DPMS level.
634 */
635 if (DPMSStandbyTime > 0)
636 timeout = DPMSStandbyTime;
637
638 else if (DPMSSuspendTime > 0)
639 timeout = DPMSSuspendTime;
640
641 else if (DPMSOffTime > 0)
642 timeout = DPMSOffTime;
643 }
644 #endif
645
646 if (ScreenSaverTime > 0) {
647 timeout = timeout > 0 ? min(ScreenSaverTime, timeout) : ScreenSaverTime;
648 }
649
650 #ifdef SCREENSAVER
651 if (timeout && !screenSaverSuspended) {
652 #else
653 if (timeout) {
654 #endif
655 ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout,
656 ScreenSaverTimeoutExpire, NULL);
657 }
658 else if (ScreenSaverTimer) {
659 FreeScreenSaverTimer();
660 }
661 }