First import
[xorg_rtime.git] / xorg-server-1.4 / os / WaitFor.c
blobec1592c014fcf4e53d96603d52379230f30c5d69
1 /***********************************************************
3 Copyright 1987, 1998 The Open Group
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.
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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.
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.
26 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
28 All Rights Reserved
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44 SOFTWARE.
46 ******************************************************************/
49 /*****************************************************************
50 * OS Dependent input routines:
52 * WaitForSomething
53 * TimerForce, TimerSet, TimerCheck, TimerFree
55 *****************************************************************/
57 #ifdef HAVE_DIX_CONFIG_H
58 #include <dix-config.h>
59 #endif
61 #ifdef WIN32
62 #include <X11/Xwinsock.h>
63 #endif
64 #include <X11/Xos.h> /* for strings, fcntl, time */
65 #include <errno.h>
66 #include <stdio.h>
67 #include <X11/X.h>
68 #include "misc.h"
70 #include "osdep.h"
71 #include <X11/Xpoll.h>
72 #include "dixstruct.h"
73 #include "opaque.h"
74 #ifdef DPMSExtension
75 #include "dpmsproc.h"
76 #endif
78 #ifdef WIN32
79 /* Error codes from windows sockets differ from fileio error codes */
80 #undef EINTR
81 #define EINTR WSAEINTR
82 #undef EINVAL
83 #define EINVAL WSAEINVAL
84 #undef EBADF
85 #define EBADF WSAENOTSOCK
86 /* Windows select does not set errno. Use GetErrno as wrapper for
87 WSAGetLastError */
88 #define GetErrno WSAGetLastError
89 #else
90 /* This is just a fallback to errno to hide the differences between unix and
91 Windows in the code */
92 #define GetErrno() errno
93 #endif
95 /* modifications by raphael */
96 int
97 mffs(fd_mask mask)
99 int i;
101 if (!mask) return 0;
102 i = 1;
103 while (!(mask & 1))
105 i++;
106 mask >>= 1;
108 return i;
111 #ifdef DPMSExtension
112 #define DPMS_SERVER
113 #include <X11/extensions/dpms.h>
114 #endif
116 struct _OsTimerRec {
117 OsTimerPtr next;
118 CARD32 expires;
119 CARD32 delta;
120 OsTimerCallback callback;
121 pointer arg;
124 static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev);
125 static void CheckAllTimers(void);
126 static OsTimerPtr timers = NULL;
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
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 *****************/
146 WaitForSomething(int *pClientsReady)
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 int nready;
156 fd_set devicesReadable;
157 CARD32 now = 0;
158 #ifdef SMART_SCHEDULE
159 Bool someReady = FALSE;
160 #endif
162 FD_ZERO(&clientsReadable);
164 /* We need a while loop here to handle
165 crashed connections and the screen saver timeout */
166 while (1)
168 /* deal with any blocked jobs */
169 if (workQueue)
170 ProcessWorkQueue();
171 if (XFD_ANYSET (&ClientsWithInput))
173 #ifdef SMART_SCHEDULE
174 if (!SmartScheduleDisable)
176 someReady = TRUE;
177 waittime.tv_sec = 0;
178 waittime.tv_usec = 0;
179 wt = &waittime;
181 else
182 #endif
184 XFD_COPYSET (&ClientsWithInput, &clientsReadable);
185 break;
188 #ifdef SMART_SCHEDULE
189 if (someReady)
191 XFD_COPYSET(&AllSockets, &LastSelectMask);
192 XFD_UNSET(&LastSelectMask, &ClientsWithInput);
194 else
196 #endif
197 wt = NULL;
198 if (timers)
200 now = GetTimeInMillis();
201 timeout = timers->expires - now;
202 if (timeout > 0 && timeout > timers->delta + 250) {
203 /* time has rewound. reset the timers. */
204 CheckAllTimers();
207 if (timers) {
208 timeout = timers->expires - now;
209 if (timeout < 0)
210 timeout = 0;
211 waittime.tv_sec = timeout / MILLI_PER_SECOND;
212 waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
213 (1000000 / MILLI_PER_SECOND);
214 wt = &waittime;
217 XFD_COPYSET(&AllSockets, &LastSelectMask);
218 #ifdef SMART_SCHEDULE
220 SmartScheduleIdle = TRUE;
221 #endif
222 BlockHandler((pointer)&wt, (pointer)&LastSelectMask);
223 if (NewOutputPending)
224 FlushAllOutput();
225 /* keep this check close to select() call to minimize race */
226 if (dispatchException)
227 i = -1;
228 else if (AnyClientsWriteBlocked)
230 XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable);
231 i = Select (MaxClients, &LastSelectMask, &clientsWritable, NULL, wt);
233 else
235 i = Select (MaxClients, &LastSelectMask, NULL, NULL, wt);
237 selecterr = GetErrno();
238 WakeupHandler(i, (pointer)&LastSelectMask);
239 #ifdef SMART_SCHEDULE
240 if (i >= 0)
242 SmartScheduleIdle = FALSE;
243 SmartScheduleIdleCount = 0;
244 if (SmartScheduleTimerStopped)
245 (void) SmartScheduleStartTimer ();
247 #endif
248 if (i <= 0) /* An error or timeout occurred */
250 if (dispatchException)
251 return 0;
252 if (i < 0)
254 if (selecterr == EBADF) /* Some client disconnected */
256 CheckConnections ();
257 if (! XFD_ANYSET (&AllClients))
258 return 0;
260 else if (selecterr == EINVAL)
262 FatalError("WaitForSomething(): select: errno=%d\n",
263 selecterr);
265 else if (selecterr != EINTR)
267 ErrorF("WaitForSomething(): select: errno=%d\n",
268 selecterr);
271 #ifdef SMART_SCHEDULE
272 else if (someReady)
275 * If no-one else is home, bail quickly
277 XFD_COPYSET(&ClientsWithInput, &LastSelectMask);
278 XFD_COPYSET(&ClientsWithInput, &clientsReadable);
279 break;
281 #endif
282 if (*checkForInput[0] != *checkForInput[1])
283 return 0;
285 if (timers)
287 int expired = 0;
288 now = GetTimeInMillis();
289 if ((int) (timers->expires - now) <= 0)
290 expired = 1;
292 while (timers && (int) (timers->expires - now) <= 0)
293 DoTimer(timers, now, &timers);
295 if (expired)
296 return 0;
299 else
301 fd_set tmp_set;
303 if (*checkForInput[0] == *checkForInput[1]) {
304 if (timers)
306 int expired = 0;
307 now = GetTimeInMillis();
308 if ((int) (timers->expires - now) <= 0)
309 expired = 1;
311 while (timers && (int) (timers->expires - now) <= 0)
312 DoTimer(timers, now, &timers);
314 if (expired)
315 return 0;
318 #ifdef SMART_SCHEDULE
319 if (someReady)
320 XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask);
321 #endif
322 if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable))
324 NewOutputPending = TRUE;
325 XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
326 XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
327 if (! XFD_ANYSET(&ClientsWriteBlocked))
328 AnyClientsWriteBlocked = FALSE;
331 XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices);
332 XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
333 XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections);
334 if (XFD_ANYSET(&tmp_set))
335 QueueWorkProc(EstablishNewConnections, NULL,
336 (pointer)&LastSelectMask);
338 if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable))
339 break;
340 #ifdef WIN32
341 /* Windows keyboard and mouse events are added to the input queue
342 in Block- and WakupHandlers. There is no device to check if
343 data is ready. So check here if new input is available */
344 if (*checkForInput[0] != *checkForInput[1])
345 return 0;
346 #endif
350 nready = 0;
351 if (XFD_ANYSET (&clientsReadable))
353 #ifndef WIN32
354 for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++)
356 int highest_priority = 0;
358 while (clientsReadable.fds_bits[i])
360 int client_priority, client_index;
362 curclient = ffs (clientsReadable.fds_bits[i]) - 1;
363 client_index = /* raphael: modified */
364 ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))];
365 #else
366 int highest_priority = 0;
367 fd_set savedClientsReadable;
368 XFD_COPYSET(&clientsReadable, &savedClientsReadable);
369 for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++)
371 int client_priority, client_index;
373 curclient = XFD_FD(&savedClientsReadable, i);
374 client_index = GetConnectionTranslation(curclient);
375 #endif
376 #ifdef XSYNC
377 /* We implement "strict" priorities.
378 * Only the highest priority client is returned to
379 * dix. If multiple clients at the same priority are
380 * ready, they are all returned. This means that an
381 * aggressive client could take over the server.
382 * This was not considered a big problem because
383 * aggressive clients can hose the server in so many
384 * other ways :)
386 client_priority = clients[client_index]->priority;
387 if (nready == 0 || client_priority > highest_priority)
389 /* Either we found the first client, or we found
390 * a client whose priority is greater than all others
391 * that have been found so far. Either way, we want
392 * to initialize the list of clients to contain just
393 * this client.
395 pClientsReady[0] = client_index;
396 highest_priority = client_priority;
397 nready = 1;
399 /* the following if makes sure that multiple same-priority
400 * clients get batched together
402 else if (client_priority == highest_priority)
403 #endif
405 pClientsReady[nready++] = client_index;
407 #ifndef WIN32
408 clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient);
410 #else
411 FD_CLR(curclient, &clientsReadable);
412 #endif
415 return nready;
418 #if 0
420 * This is not always a macro.
422 ANYSET(FdMask *src)
424 int i;
426 for (i=0; i<mskcnt; i++)
427 if (src[ i ])
428 return (TRUE);
429 return (FALSE);
431 #endif
433 /* If time has rewound, re-run every affected timer.
434 * Timers might drop out of the list, so we have to restart every time. */
435 static void
436 CheckAllTimers(void)
438 OsTimerPtr timer;
439 CARD32 now;
441 start:
442 now = GetTimeInMillis();
444 for (timer = timers; timer; timer = timer->next) {
445 if (timer->expires - now > timer->delta + 250) {
446 TimerForce(timer);
447 goto start;
452 static void
453 DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev)
455 CARD32 newTime;
457 *prev = timer->next;
458 timer->next = NULL;
459 newTime = (*timer->callback)(timer, now, timer->arg);
460 if (newTime)
461 TimerSet(timer, 0, newTime, timer->callback, timer->arg);
464 _X_EXPORT OsTimerPtr
465 TimerSet(OsTimerPtr timer, int flags, CARD32 millis,
466 OsTimerCallback func, pointer arg)
468 register OsTimerPtr *prev;
469 CARD32 now = GetTimeInMillis();
471 if (!timer)
473 timer = (OsTimerPtr)xalloc(sizeof(struct _OsTimerRec));
474 if (!timer)
475 return NULL;
477 else
479 for (prev = &timers; *prev; prev = &(*prev)->next)
481 if (*prev == timer)
483 *prev = timer->next;
484 if (flags & TimerForceOld)
485 (void)(*timer->callback)(timer, now, timer->arg);
486 break;
490 if (!millis)
491 return timer;
492 if (flags & TimerAbsolute) {
493 timer->delta = millis - now;
495 else {
496 timer->delta = millis;
497 millis += now;
499 timer->expires = millis;
500 timer->callback = func;
501 timer->arg = arg;
502 if ((int) (millis - now) <= 0)
504 timer->next = NULL;
505 millis = (*timer->callback)(timer, now, timer->arg);
506 if (!millis)
507 return timer;
509 for (prev = &timers;
510 *prev && (int) ((*prev)->expires - millis) <= 0;
511 prev = &(*prev)->next)
513 timer->next = *prev;
514 *prev = timer;
515 return timer;
518 Bool
519 TimerForce(OsTimerPtr timer)
521 OsTimerPtr *prev;
523 for (prev = &timers; *prev; prev = &(*prev)->next)
525 if (*prev == timer)
527 DoTimer(timer, GetTimeInMillis(), prev);
528 return TRUE;
531 return FALSE;
535 _X_EXPORT void
536 TimerCancel(OsTimerPtr timer)
538 OsTimerPtr *prev;
540 if (!timer)
541 return;
542 for (prev = &timers; *prev; prev = &(*prev)->next)
544 if (*prev == timer)
546 *prev = timer->next;
547 break;
552 _X_EXPORT void
553 TimerFree(OsTimerPtr timer)
555 if (!timer)
556 return;
557 TimerCancel(timer);
558 xfree(timer);
561 void
562 TimerCheck(void)
564 CARD32 now = GetTimeInMillis();
566 while (timers && (int) (timers->expires - now) <= 0)
567 DoTimer(timers, now, &timers);
570 void
571 TimerInit(void)
573 OsTimerPtr timer;
575 while ((timer = timers))
577 timers = timer->next;
578 xfree(timer);
582 #ifdef DPMSExtension
584 #define DPMS_CHECK_MODE(mode,time)\
585 if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\
586 DPMSSet(mode);
588 #define DPMS_CHECK_TIMEOUT(time)\
589 if (time > 0 && (time - timeout) > 0)\
590 return time - timeout;
592 static CARD32
593 NextDPMSTimeout(INT32 timeout)
596 * Return the amount of time remaining until we should set
597 * the next power level. Fallthroughs are intentional.
599 switch (DPMSPowerLevel)
601 case DPMSModeOn:
602 DPMS_CHECK_TIMEOUT(DPMSStandbyTime)
604 case DPMSModeStandby:
605 DPMS_CHECK_TIMEOUT(DPMSSuspendTime)
607 case DPMSModeSuspend:
608 DPMS_CHECK_TIMEOUT(DPMSOffTime)
610 default: /* DPMSModeOff */
611 return 0;
614 #endif /* DPMSExtension */
616 static CARD32
617 ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer arg)
619 INT32 timeout = now - lastDeviceEventTime.milliseconds;
620 CARD32 nextTimeout = 0;
622 #ifdef DPMSExtension
624 * Check each mode lowest to highest, since a lower mode can
625 * have the same timeout as a higher one.
627 if (DPMSEnabled)
629 DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime)
630 DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime)
631 DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime)
633 nextTimeout = NextDPMSTimeout(timeout);
637 * Only do the screensaver checks if we're not in a DPMS
638 * power saving mode
640 if (DPMSPowerLevel != DPMSModeOn)
641 return nextTimeout;
642 #endif /* DPMSExtension */
644 if (!ScreenSaverTime)
645 return nextTimeout;
647 if (timeout < ScreenSaverTime)
649 return nextTimeout > 0 ?
650 min(ScreenSaverTime - timeout, nextTimeout) :
651 ScreenSaverTime - timeout;
654 ResetOsBuffers(); /* not ideal, but better than nothing */
655 SaveScreens(SCREEN_SAVER_ON, ScreenSaverActive);
657 if (ScreenSaverInterval > 0)
659 nextTimeout = nextTimeout > 0 ?
660 min(ScreenSaverInterval, nextTimeout) :
661 ScreenSaverInterval;
664 return nextTimeout;
667 static OsTimerPtr ScreenSaverTimer = NULL;
669 void
670 FreeScreenSaverTimer(void)
672 if (ScreenSaverTimer) {
673 TimerFree(ScreenSaverTimer);
674 ScreenSaverTimer = NULL;
678 void
679 SetScreenSaverTimer(void)
681 CARD32 timeout = 0;
683 #ifdef DPMSExtension
684 if (DPMSEnabled)
687 * A higher DPMS level has a timeout that's either less
688 * than or equal to that of a lower DPMS level.
690 if (DPMSStandbyTime > 0)
691 timeout = DPMSStandbyTime;
693 else if (DPMSSuspendTime > 0)
694 timeout = DPMSSuspendTime;
696 else if (DPMSOffTime > 0)
697 timeout = DPMSOffTime;
699 #endif
701 if (ScreenSaverTime > 0)
703 timeout = timeout > 0 ?
704 min(ScreenSaverTime, timeout) :
705 ScreenSaverTime;
708 #ifdef SCREENSAVER
709 if (timeout && !screenSaverSuspended) {
710 #else
711 if (timeout) {
712 #endif
713 ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout,
714 ScreenSaverTimeoutExpire, NULL);
716 else if (ScreenSaverTimer) {
717 FreeScreenSaverTimer();