1 /***********************************************************
3 Copyright (c) 1987 X Consortium
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of the X Consortium shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from the X Consortium.
27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
31 Permission to use, copy, modify, and distribute this software and its
32 documentation for any purpose and without fee is hereby granted,
33 provided that the above copyright notice appear in all copies and that
34 both that copyright notice and this permission notice appear in
35 supporting documentation, and that the name of Digital not be
36 used in advertising or publicity pertaining to distribution of the
37 software without specific, written prior permission.
39 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47 ******************************************************************/
49 /* $XConsortium: WaitFor.c /main/55 1996/12/02 10:22:24 lehors $ */
50 /* $XFree86: xc/programs/Xserver/os/WaitFor.c,v 3.11.2.3 1998/01/31 14:23:33 hohndel Exp $ */
52 /*****************************************************************
53 * OS Dependent input routines:
56 * TimerForce, TimerSet, TimerCheck, TimerFree
58 *****************************************************************/
61 #include <X11/Xwinsock.h>
63 #include "Xos.h" /* for strings, fcntl, time */
76 #define select(n,r,w,x,t) nbio_select(n,r,w,x,t)
79 #define select(n,r,w,x,t) os2PseudoSelect(n,r,w,x,t)
81 #include <X11/Xpoll.h>
83 #include "dixstruct.h"
88 extern void DPMSSet();
91 extern fd_set AllSockets;
92 extern fd_set AllClients;
93 extern fd_set LastSelectMask;
94 extern fd_set WellKnownConnections;
95 extern fd_set EnabledDevices;
96 extern fd_set ClientsWithInput;
97 extern fd_set ClientsWriteBlocked;
98 extern fd_set OutputPending;
100 extern int ConnectionTranslation[];
102 extern Bool NewOutputPending;
103 extern Bool AnyClientsWriteBlocked;
105 extern WorkQueuePtr workQueue;
110 * defined in xtestext1dd.c
112 extern int playback_on;
113 #endif /* XTESTEXT1 */
118 OsTimerCallback callback;
122 static void DoTimer();
123 static OsTimerPtr timers;
127 * Make the server suspend until there is
128 * 1. data from clients or
129 * 2. input events available or
130 * 3. ddx notices something of interest (graphics
131 * queue ready, etc.) or
132 * 4. clients that have buffered replies/events are ready
134 * If the time between INPUT events is
135 * greater than ScreenSaverTime, the display is turned off (or
136 * saved, depending on the hardware). So, WaitForSomething()
137 * has to handle this also (that's why the select() has a timeout.
138 * For more info on ClientsWithInput, see ReadRequestFromClient().
139 * pClientsReady is an array to store ready client->index values into.
142 static INT32 timeTilFrob = 0; /* while screen saving */
147 WaitForSomething(pClientsReady)
151 struct timeval waittime, *wt;
154 INT32 standbyTimeout, suspendTimeout, offTimeout;
156 fd_set clientsReadable;
157 fd_set clientsWritable;
161 fd_set devicesReadable;
164 FD_ZERO(&clientsReadable);
166 /* We need a while loop here to handle
167 crashed connections and the screen saver timeout */
170 /* deal with any blocked jobs */
174 if (XFD_ANYSET (&ClientsWithInput))
176 XFD_COPYSET (&ClientsWithInput, &clientsReadable);
180 if (ScreenSaverTime > 0 || DPMSEnabled || timers)
182 if (ScreenSaverTime > 0 || timers)
184 now = GetTimeInMillis();
188 while (timers && timers->expires <= now)
189 DoTimer(timers, now, &timers);
192 timeout = timers->expires - now;
193 waittime.tv_sec = timeout / MILLI_PER_SECOND;
194 waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
195 (1000000 / MILLI_PER_SECOND);
200 if (ScreenSaverTime > 0 ||
202 (DPMSStandbyTime > 0 || DPMSSuspendTime > 0 || DPMSOffTime > 0)))
204 if (ScreenSaverTime > 0)
209 if (ScreenSaverTime > 0)
210 timeout = (ScreenSaverTime -
211 (now - lastDeviceEventTime.milliseconds));
212 if (DPMSStandbyTime > 0)
213 standbyTimeout = (DPMSStandbyTime -
214 (now - lastDeviceEventTime.milliseconds));
215 if (DPMSSuspendTime > 0)
216 suspendTimeout = (DPMSSuspendTime -
217 (now - lastDeviceEventTime.milliseconds));
219 offTimeout = (DPMSOffTime -
220 (now - lastDeviceEventTime.milliseconds));
222 timeout = (ScreenSaverTime -
223 (now - lastDeviceEventTime.milliseconds));
224 #endif /* DPMSExtension */
226 if (timeout <= 0 && ScreenSaverTime > 0)
228 if (timeout <= 0) /* may be forced by AutoResetServer() */
229 #endif /* DPMSExtension */
233 timeSinceSave = -timeout;
234 if (timeSinceSave >= timeTilFrob && timeTilFrob >= 0)
236 ResetOsBuffers(); /* not ideal, but better than nothing */
237 SaveScreens(SCREEN_SAVER_ON, ScreenSaverActive);
239 if (ScreenSaverInterval > 0 &&
240 DPMSPowerLevel == DPMSModeOn)
242 if (ScreenSaverInterval)
243 #endif /* DPMSExtension */
244 /* round up to the next ScreenSaverInterval */
245 timeTilFrob = ScreenSaverInterval *
246 ((timeSinceSave + ScreenSaverInterval) /
247 ScreenSaverInterval);
251 timeout = timeTilFrob - timeSinceSave;
255 if (ScreenSaverTime > 0 && timeout > ScreenSaverTime)
256 timeout = ScreenSaverTime;
262 if (standbyTimeout > 0
263 && (timeout <= 0 || timeout > standbyTimeout))
264 timeout = standbyTimeout;
265 if (suspendTimeout > 0
266 && (timeout <= 0 || timeout > suspendTimeout))
267 timeout = suspendTimeout;
269 && (timeout <= 0 || timeout > offTimeout))
270 timeout = offTimeout;
273 if (timeout > 0 && (!wt || timeout < (timers->expires - now)))
275 waittime.tv_sec = timeout / MILLI_PER_SECOND;
276 waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
277 (1000000 / MILLI_PER_SECOND);
281 /* don't bother unless it's switched on */
285 * If this mode's enabled, and if the time's come
286 * and if we're still at a lesser mode, do it now.
288 if (DPMSStandbyTime > 0) {
289 if (standbyTimeout <= 0) {
290 if (DPMSPowerLevel < DPMSModeStandby) {
291 DPMSSet(DPMSModeStandby);
296 * and ditto. Note that since these modes can have the
297 * same timeouts, they can happen at the same time.
299 if (DPMSSuspendTime > 0) {
300 if (suspendTimeout <= 0) {
301 if (DPMSPowerLevel < DPMSModeSuspend) {
302 DPMSSet(DPMSModeSuspend);
306 if (DPMSOffTime > 0) {
307 if (offTimeout <= 0) {
308 if (DPMSPowerLevel < DPMSModeOff) {
309 DPMSSet(DPMSModeOff);
316 XFD_COPYSET(&AllSockets, &LastSelectMask);
317 BlockHandler((pointer)&wt, (pointer)&LastSelectMask);
318 if (NewOutputPending)
321 /* XXX how does this interact with new write block handling? */
324 XTestComputeWaitTime (&waittime);
326 #endif /* XTESTEXT1 */
327 /* keep this check close to select() call to minimize race */
328 if (dispatchException)
330 else if (AnyClientsWriteBlocked)
332 XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable);
333 i = Select (MAXSOCKS, &LastSelectMask, &clientsWritable, NULL, wt);
336 i = Select (MAXSOCKS, &LastSelectMask, NULL, NULL, wt);
338 WakeupHandler(i, (pointer)&LastSelectMask);
341 i = XTestProcessInputAction (i, &waittime);
343 #endif /* XTESTEXT1 */
344 if (i <= 0) /* An error or timeout occurred */
347 if (dispatchException)
349 FD_ZERO(&clientsWritable);
351 if (selecterr == EBADF) /* Some client disconnected */
354 if (! XFD_ANYSET (&AllClients))
357 else if (selecterr == EINVAL)
359 FatalError("WaitForSomething(): select: errno=%d\n",
362 else if (selecterr != EINTR)
364 ErrorF("WaitForSomething(): select: errno=%d\n",
369 now = GetTimeInMillis();
370 while (timers && timers->expires <= now)
371 DoTimer(timers, now, &timers);
373 if (*checkForInput[0] != *checkForInput[1])
381 if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable))
383 NewOutputPending = TRUE;
384 XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
385 XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
386 if (! XFD_ANYSET(&ClientsWriteBlocked))
387 AnyClientsWriteBlocked = FALSE;
390 XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices);
391 XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
393 if (LastSelectMask.fds_bits[0] & WellKnownConnections.fds_bits[0])
395 XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections);
396 if (XFD_ANYSET(&tmp_set))
398 QueueWorkProc(EstablishNewConnections, NULL,
399 (pointer)&LastSelectMask);
401 if (XFD_ANYSET (&devicesReadable) && (DPMSPowerLevel != DPMSModeOn))
404 if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable))
410 if (XFD_ANYSET (&clientsReadable))
413 for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++)
415 int highest_priority;
417 while (clientsReadable.fds_bits[i])
419 int client_priority, client_index;
421 curclient = ffs (clientsReadable.fds_bits[i]) - 1;
422 client_index = ConnectionTranslation[curclient + (i << 5)];
424 int highest_priority;
425 fd_set savedClientsReadable;
426 XFD_COPYSET(&clientsReadable, &savedClientsReadable);
427 for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++)
429 int client_priority, client_index;
431 curclient = XFD_FD(&savedClientsReadable, i);
432 client_index = ConnectionTranslation[curclient];
435 /* We implement "strict" priorities.
436 * Only the highest priority client is returned to
437 * dix. If multiple clients at the same priority are
438 * ready, they are all returned. This means that an
439 * aggressive client could take over the server.
440 * This was not considered a big problem because
441 * aggressive clients can hose the server in so many
444 client_priority = clients[client_index]->priority;
445 if (nready == 0 || client_priority > highest_priority)
447 /* Either we found the first client, or we found
448 * a client whose priority is greater than all others
449 * that have been found so far. Either way, we want
450 * to initialize the list of clients to contain just
453 pClientsReady[0] = client_index;
454 highest_priority = client_priority;
457 /* the following if makes sure that multiple same-priority
458 * clients get batched together
460 else if (client_priority == highest_priority)
463 pClientsReady[nready++] = client_index;
466 clientsReadable.fds_bits[i] &= ~(((fd_mask)1) << curclient);
469 FD_CLR(curclient, &clientsReadable);
478 * This is not always a macro.
485 for (i=0; i<mskcnt; i++)
494 #define dbprintf(list) /* printf list */
497 WaitForSomething(pClientsReady)
500 register int i, wt, nt;
502 long alwaysCheckForInput[2];
509 /* Be sure to check for input on every sweep in the dispatcher.
510 * This routine should be in InitInput, but since this is more
511 * or less a device dependent routine, and the semantics of it
512 * are device independent I decided to put it here.
514 alwaysCheckForInput[0] = 0;
515 alwaysCheckForInput[1] = 1;
516 SetInputCheck(&alwaysCheckForInput[0], &alwaysCheckForInput[1]);
519 /* deal with any blocked jobs */
523 if (ANYSET(ClientsWithInput)) {
524 FdSet clientsReadable;
525 int highest_priority;
527 COPYBITS(ClientsWithInput, clientsReadable);
528 dbprintf(("WaitFor: "));
530 for (i=0; i < mskcnt; i++) {
531 while (clientsReadable[i]) {
532 int client_priority, curclient, client_index;
534 curclient = ffs (clientsReadable[i]) - 1;
535 client_index = ConnectionTranslation[curclient + (i << 5)];
536 dbprintf(("%d has input\n", curclient));
538 client_priority = clients[client_index]->priority;
539 if (nready == 0 || client_priority > highest_priority)
541 pClientsReady[0] = client_index;
542 highest_priority = client_priority;
545 else if (client_priority == highest_priority)
548 pClientsReady[nready++] = client_index;
550 clientsReadable[i] &= ~(((FdMask)1) << curclient);
557 now = GetTimeInMillis();
560 while (timers && timers->expires <= now)
561 DoTimer(timers, now, &timers);
564 timeout = timers->expires - now;
568 if (ScreenSaverTime) {
569 timeout = ScreenSaverTime - TimeSinceLastInputEvent();
570 if (timeout <= 0) { /* may be forced by AutoResetServer() */
573 timeSinceSave = -timeout;
574 if ((timeSinceSave >= timeTilFrob) && (timeTilFrob >= 0)) {
575 SaveScreens(SCREEN_SAVER_ON, ScreenSaverActive);
576 if (ScreenSaverInterval)
577 /* round up to the next ScreenSaverInterval */
578 timeTilFrob = ScreenSaverInterval *
579 ((timeSinceSave + ScreenSaverInterval) /
580 ScreenSaverInterval);
584 timeout = timeTilFrob - timeSinceSave;
586 if (timeout > ScreenSaverTime)
587 timeout = ScreenSaverTime;
591 if (wt < 0 || (timeTilFrob >= 0 && wt > timeout)) {
596 /* Check for new clients. We do this here and not in the listener
597 * threads because we cannot be sure that dix is re-entrant, and
598 * we need to call some dix routines during startup.
601 QueueWorkProc(EstablishNewConnections, NULL,
605 /* Call device dependent block handlers, which may want to
606 * specify a different timeout (e.g. used for key auto-repeat).
608 wtp = (struct timeval *) NULL;
609 BlockHandler((pointer)&wtp, (pointer)NULL);
610 if (wtp) wt = (wtp->tv_sec * 1000) + (wtp->tv_usec / 1000);
612 if (NewOutputPending)
615 /* TODO: XTESTEXT1 */
617 nready = AmFindReadyClients(pClientsReady, AllSockets);
619 /* If we found some work, or the iop server has us informed about
620 * new device events, we return.
622 if (nready || AmoebaEventsAvailable())
625 if (dispatchException)
628 /* Nothing interesting is available. Go to sleep with a timeout.
629 * The other threads will wake us when needed.
631 i = SleepMainThread(wt);
633 /* Wake up any of the sleeping handlers */
634 WakeupHandler((unsigned long)0, (pointer)NULL);
636 /* TODO: XTESTEXT1 */
638 if (dispatchException)
642 /* An error or timeout occurred */
647 dbprintf(("WaitForSomething: %d clients ready\n", nready));
655 DoTimer(timer, now, prev)
656 register OsTimerPtr timer;
664 newTime = (*timer->callback)(timer, now, timer->arg);
666 TimerSet(timer, 0, newTime, timer->callback, timer->arg);
670 TimerSet(timer, flags, millis, func, arg)
671 register OsTimerPtr timer;
674 OsTimerCallback func;
677 register OsTimerPtr *prev;
678 CARD32 now = GetTimeInMillis();
682 timer = (OsTimerPtr)xalloc(sizeof(struct _OsTimerRec));
688 for (prev = &timers; *prev; prev = &(*prev)->next)
693 if (flags & TimerForceOld)
694 (void)(*timer->callback)(timer, now, timer->arg);
701 if (!(flags & TimerAbsolute))
703 timer->expires = millis;
704 timer->callback = func;
709 millis = (*timer->callback)(timer, now, timer->arg);
714 *prev && millis > (*prev)->expires;
715 prev = &(*prev)->next)
724 register OsTimerPtr timer;
726 register OsTimerPtr *prev;
727 register CARD32 newTime;
729 for (prev = &timers; *prev; prev = &(*prev)->next)
733 DoTimer(timer, GetTimeInMillis(), prev);
743 register OsTimerPtr timer;
745 register OsTimerPtr *prev;
749 for (prev = &timers; *prev; prev = &(*prev)->next)
761 register OsTimerPtr timer;
772 register CARD32 now = GetTimeInMillis();
774 while (timers && timers->expires <= now)
775 DoTimer(timers, now, &timers);
783 while (timer = timers)
785 timers = timer->next;