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
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.
25 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
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.
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
45 ******************************************************************/
47 /*****************************************************************
48 * OS Dependent input routines:
51 * TimerForce, TimerSet, TimerCheck, TimerFree
53 *****************************************************************/
55 #ifdef HAVE_DIX_CONFIG_H
56 #include <dix-config.h>
60 #include <X11/Xwinsock.h>
62 #include <X11/Xos.h> /* for strings, fcntl, time */
69 #include <X11/Xpoll.h>
70 #include "dixstruct.h"
77 /* Error codes from windows sockets differ from fileio error codes */
79 #define EINTR WSAEINTR
81 #define EINVAL WSAEINVAL
83 #define EBADF WSAENOTSOCK
84 /* Windows select does not set errno. Use GetErrno as wrapper for
86 #define GetErrno WSAGetLastError
88 /* This is just a fallback to errno to hide the differences between unix and
89 Windows in the code */
90 #define GetErrno() errno
93 /* like ffs, but uses fd_mask instead of int as argument, so it works
94 when fd_mask is longer than an int, such as common 64-bit platforms */
95 /* modifications by raphael */
104 while (!(mask & 1)) {
112 #include <X11/extensions/dpmsconst.h>
119 OsTimerCallback callback;
123 static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev);
124 static void CheckAllTimers(void);
125 static OsTimerPtr timers = NULL;
129 * Make the server suspend until there is
130 * 1. data from clients or
131 * 2. input events available or
132 * 3. ddx notices something of interest (graphics
133 * queue ready, etc.) or
134 * 4. clients that have buffered replies/events are ready
136 * If the time between INPUT events is
137 * greater than ScreenSaverTime, the display is turned off (or
138 * saved, depending on the hardware). So, WaitForSomething()
139 * has to handle this also (that's why the select() has a timeout.
140 * For more info on ClientsWithInput, see ReadRequestFromClient().
141 * pClientsReady is an array to store ready client->index values into.
145 WaitForSomething(int *pClientsReady)
148 struct timeval waittime, *wt;
150 fd_set clientsReadable;
151 fd_set clientsWritable;
155 fd_set devicesReadable;
157 Bool someReady = FALSE;
159 FD_ZERO(&clientsReadable);
162 SmartScheduleStopTimer();
165 /* We need a while loop here to handle
166 crashed connections and the screen saver timeout */
168 /* deal with any blocked jobs */
171 if (XFD_ANYSET(&ClientsWithInput)) {
172 if (!SmartScheduleDisable) {
175 waittime.tv_usec = 0;
179 XFD_COPYSET(&ClientsWithInput, &clientsReadable);
184 XFD_COPYSET(&AllSockets, &LastSelectMask);
185 XFD_UNSET(&LastSelectMask, &ClientsWithInput);
190 now = GetTimeInMillis();
191 timeout = timers->expires - now;
192 if (timeout > 0 && timeout > timers->delta + 250) {
193 /* time has rewound. reset the timers. */
198 timeout = timers->expires - now;
201 waittime.tv_sec = timeout / MILLI_PER_SECOND;
202 waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
203 (1000000 / MILLI_PER_SECOND);
207 XFD_COPYSET(&AllSockets, &LastSelectMask);
210 BlockHandler((pointer) &wt, (pointer) &LastSelectMask);
211 if (NewOutputPending)
213 /* keep this check close to select() call to minimize race */
214 if (dispatchException)
216 else if (AnyClientsWriteBlocked) {
217 XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable);
218 #ifndef _F_EXCLUDE_NON_MASK_SELECTED_FD_FROM_MAXCLIENTS_
219 i = Select(MaxClients, &LastSelectMask, &clientsWritable, NULL, wt);
221 i = Select(FD_SETSIZE, &LastSelectMask, &clientsWritable, NULL, wt);
225 #ifndef _F_EXCLUDE_NON_MASK_SELECTED_FD_FROM_MAXCLIENTS_
226 i = Select(MaxClients, &LastSelectMask, NULL, NULL, wt);
228 i = Select(FD_SETSIZE, &LastSelectMask, NULL, NULL, wt);
231 selecterr = GetErrno();
232 WakeupHandler(i, (pointer) &LastSelectMask);
233 if (i <= 0) { /* An error or timeout occurred */
234 if (dispatchException)
237 if (selecterr == EBADF) { /* Some client disconnected */
239 if (!XFD_ANYSET(&AllClients))
242 else if (selecterr == EINVAL) {
243 FatalError("WaitForSomething(): select: %s\n",
244 strerror(selecterr));
246 else if (selecterr != EINTR && selecterr != EAGAIN) {
247 ErrorF("WaitForSomething(): select: %s\n",
248 strerror(selecterr));
251 else if (someReady) {
253 * If no-one else is home, bail quickly
255 XFD_COPYSET(&ClientsWithInput, &LastSelectMask);
256 XFD_COPYSET(&ClientsWithInput, &clientsReadable);
259 if (*checkForInput[0] != *checkForInput[1])
265 now = GetTimeInMillis();
266 if ((int) (timers->expires - now) <= 0)
269 while (timers && (int) (timers->expires - now) <= 0)
270 DoTimer(timers, now, &timers);
279 if (*checkForInput[0] == *checkForInput[1]) {
283 now = GetTimeInMillis();
284 if ((int) (timers->expires - now) <= 0)
287 while (timers && (int) (timers->expires - now) <= 0)
288 DoTimer(timers, now, &timers);
295 XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask);
296 if (AnyClientsWriteBlocked && XFD_ANYSET(&clientsWritable)) {
297 NewOutputPending = TRUE;
298 XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
299 XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
300 if (!XFD_ANYSET(&ClientsWriteBlocked))
301 AnyClientsWriteBlocked = FALSE;
304 XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices);
305 XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
306 XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections);
307 if (XFD_ANYSET(&tmp_set))
308 QueueWorkProc(EstablishNewConnections, NULL,
309 (pointer) &LastSelectMask);
311 if (XFD_ANYSET(&devicesReadable) || XFD_ANYSET(&clientsReadable))
313 /* check here for DDXes that queue events during Block/Wakeup */
314 if (*checkForInput[0] != *checkForInput[1])
320 if (XFD_ANYSET(&clientsReadable)) {
322 for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
323 int highest_priority = 0;
325 while (clientsReadable.fds_bits[i]) {
326 int client_priority, client_index;
328 curclient = mffs(clientsReadable.fds_bits[i]) - 1;
329 client_index = /* raphael: modified */
330 ConnectionTranslation[curclient +
331 (i * (sizeof(fd_mask) * 8))];
333 int highest_priority = 0;
334 fd_set savedClientsReadable;
336 XFD_COPYSET(&clientsReadable, &savedClientsReadable);
337 for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++) {
338 int client_priority, client_index;
340 curclient = XFD_FD(&savedClientsReadable, i);
341 client_index = GetConnectionTranslation(curclient);
343 /* We implement "strict" priorities.
344 * Only the highest priority client is returned to
345 * dix. If multiple clients at the same priority are
346 * ready, they are all returned. This means that an
347 * aggressive client could take over the server.
348 * This was not considered a big problem because
349 * aggressive clients can hose the server in so many
352 client_priority = clients[client_index]->priority;
353 if (nready == 0 || client_priority > highest_priority) {
354 /* Either we found the first client, or we found
355 * a client whose priority is greater than all others
356 * that have been found so far. Either way, we want
357 * to initialize the list of clients to contain just
360 pClientsReady[0] = client_index;
361 highest_priority = client_priority;
364 /* the following if makes sure that multiple same-priority
365 * clients get batched together
367 else if (client_priority == highest_priority) {
368 pClientsReady[nready++] = client_index;
371 clientsReadable.fds_bits[i] &= ~(((fd_mask) 1L) << curclient);
374 FD_CLR(curclient, &clientsReadable);
380 SmartScheduleStartTimer();
385 /* If time has rewound, re-run every affected timer.
386 * Timers might drop out of the list, so we have to restart every time. */
395 now = GetTimeInMillis();
397 for (timer = timers; timer; timer = timer->next) {
398 if (timer->expires - now > timer->delta + 250) {
407 DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev)
414 newTime = (*timer->callback) (timer, now, timer->arg);
416 TimerSet(timer, 0, newTime, timer->callback, timer->arg);
421 TimerSet(OsTimerPtr timer, int flags, CARD32 millis,
422 OsTimerCallback func, pointer arg)
424 register OsTimerPtr *prev;
425 CARD32 now = GetTimeInMillis();
428 timer = malloc(sizeof(struct _OsTimerRec));
434 for (prev = &timers; *prev; prev = &(*prev)->next) {
435 if (*prev == timer) {
437 if (flags & TimerForceOld)
438 (void) (*timer->callback) (timer, now, timer->arg);
446 if (flags & TimerAbsolute) {
447 timer->delta = millis - now;
450 timer->delta = millis;
453 timer->expires = millis;
454 timer->callback = func;
456 if ((int) (millis - now) <= 0) {
458 millis = (*timer->callback) (timer, now, timer->arg);
464 *prev && (int) ((*prev)->expires - millis) <= 0;
465 prev = &(*prev)->next);
473 TimerForce(OsTimerPtr timer)
479 for (prev = &timers; *prev; prev = &(*prev)->next) {
480 if (*prev == timer) {
481 DoTimer(timer, GetTimeInMillis(), prev);
491 TimerCancel(OsTimerPtr timer)
498 for (prev = &timers; *prev; prev = &(*prev)->next) {
499 if (*prev == timer) {
508 TimerFree(OsTimerPtr timer)
519 CARD32 now = GetTimeInMillis();
521 while (timers && (int) (timers->expires - now) <= 0)
522 DoTimer(timers, now, &timers);
530 while ((timer = timers)) {
531 timers = timer->next;
538 #define DPMS_CHECK_MODE(mode,time)\
539 if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\
540 DPMSSet(serverClient, mode);
542 #define DPMS_CHECK_TIMEOUT(time)\
543 if (time > 0 && (time - timeout) > 0)\
544 return time - timeout;
547 NextDPMSTimeout(INT32 timeout)
550 * Return the amount of time remaining until we should set
551 * the next power level. Fallthroughs are intentional.
553 switch (DPMSPowerLevel) {
555 DPMS_CHECK_TIMEOUT(DPMSStandbyTime)
557 case DPMSModeStandby:
558 DPMS_CHECK_TIMEOUT(DPMSSuspendTime)
560 case DPMSModeSuspend:
561 DPMS_CHECK_TIMEOUT(DPMSOffTime)
563 default: /* DPMSModeOff */
567 #endif /* DPMSExtension */
570 ScreenSaverTimeoutExpire(OsTimerPtr timer, CARD32 now, pointer arg)
572 INT32 timeout = now - lastDeviceEventTime[XIAllDevices].milliseconds;
573 CARD32 nextTimeout = 0;
577 * Check each mode lowest to highest, since a lower mode can
578 * have the same timeout as a higher one.
581 DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime)
582 DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime)
583 DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime)
585 nextTimeout = NextDPMSTimeout(timeout);
589 * Only do the screensaver checks if we're not in a DPMS
592 if (DPMSPowerLevel != DPMSModeOn)
594 #endif /* DPMSExtension */
596 if (!ScreenSaverTime)
599 if (timeout < ScreenSaverTime) {
600 return nextTimeout > 0 ?
601 min(ScreenSaverTime - timeout, nextTimeout) :
602 ScreenSaverTime - timeout;
605 ResetOsBuffers(); /* not ideal, but better than nothing */
606 dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive);
608 if (ScreenSaverInterval > 0) {
609 nextTimeout = nextTimeout > 0 ?
610 min(ScreenSaverInterval, nextTimeout) : ScreenSaverInterval;
616 static OsTimerPtr ScreenSaverTimer = NULL;
619 FreeScreenSaverTimer(void)
621 if (ScreenSaverTimer) {
622 TimerFree(ScreenSaverTimer);
623 ScreenSaverTimer = NULL;
628 SetScreenSaverTimer(void)
635 * A higher DPMS level has a timeout that's either less
636 * than or equal to that of a lower DPMS level.
638 if (DPMSStandbyTime > 0)
639 timeout = DPMSStandbyTime;
641 else if (DPMSSuspendTime > 0)
642 timeout = DPMSSuspendTime;
644 else if (DPMSOffTime > 0)
645 timeout = DPMSOffTime;
649 if (ScreenSaverTime > 0) {
650 timeout = timeout > 0 ? min(ScreenSaverTime, timeout) : ScreenSaverTime;
654 if (timeout && !screenSaverSuspended) {
658 ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout,
659 ScreenSaverTimeoutExpire, NULL);
661 else if (ScreenSaverTimer) {
662 FreeScreenSaverTimer();