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"
78 /* Error codes from windows sockets differ from fileio error codes */
80 #define EINTR WSAEINTR
82 #define EINVAL WSAEINVAL
84 #define EBADF WSAENOTSOCK
85 /* Windows select does not set errno. Use GetErrno as wrapper for
87 #define GetErrno WSAGetLastError
89 /* This is just a fallback to errno to hide the differences between unix and
90 Windows in the code */
91 #define GetErrno() errno
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 */
105 while (!(mask
& 1)) {
113 #include <X11/extensions/dpmsconst.h>
120 OsTimerCallback callback
;
124 static void DoTimer(OsTimerPtr timer
, CARD32 now
, OsTimerPtr
*prev
);
125 static void CheckAllTimers(void);
126 static OsTimerPtr timers
= NULL
;
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.
146 WaitForSomething(int *pClientsReady
)
149 struct timeval waittime
, *wt
;
151 fd_set clientsReadable
;
152 fd_set clientsWritable
;
156 fd_set devicesReadable
;
158 Bool someReady
= FALSE
;
160 FD_ZERO(&clientsReadable
);
163 SmartScheduleStopTimer();
170 /* We need a while loop here to handle
171 crashed connections and the screen saver timeout */
173 /* deal with any blocked jobs */
176 if (XFD_ANYSET(&ClientsWithInput
)) {
177 if (!SmartScheduleDisable
) {
180 waittime
.tv_usec
= 0;
184 XFD_COPYSET(&ClientsWithInput
, &clientsReadable
);
189 XFD_COPYSET(&AllSockets
, &LastSelectMask
);
190 XFD_UNSET(&LastSelectMask
, &ClientsWithInput
);
195 now
= GetTimeInMillis();
196 timeout
= timers
->expires
- now
;
197 if (timeout
> 0 && timeout
> timers
->delta
+ 250) {
198 /* time has rewound. reset the timers. */
203 timeout
= timers
->expires
- now
;
206 waittime
.tv_sec
= timeout
/ MILLI_PER_SECOND
;
207 waittime
.tv_usec
= (timeout
% MILLI_PER_SECOND
) *
208 (1000000 / MILLI_PER_SECOND
);
212 XFD_COPYSET(&AllSockets
, &LastSelectMask
);
215 BlockHandler((pointer
) &wt
, (pointer
) &LastSelectMask
);
216 if (NewOutputPending
)
218 /* keep this check close to select() call to minimize race */
219 if (dispatchException
)
221 else if (AnyClientsWriteBlocked
) {
222 XFD_COPYSET(&ClientsWriteBlocked
, &clientsWritable
);
223 i
= Select(MaxClients
, &LastSelectMask
, &clientsWritable
, NULL
, wt
);
226 i
= Select(MaxClients
, &LastSelectMask
, NULL
, NULL
, wt
);
228 selecterr
= GetErrno();
229 WakeupHandler(i
, (pointer
) &LastSelectMask
);
230 if (i
<= 0) { /* An error or timeout occurred */
231 if (dispatchException
)
234 if (selecterr
== EBADF
) { /* Some client disconnected */
236 if (!XFD_ANYSET(&AllClients
))
239 else if (selecterr
== EINVAL
) {
240 FatalError("WaitForSomething(): select: %s\n",
241 strerror(selecterr
));
243 else if (selecterr
!= EINTR
&& selecterr
!= EAGAIN
) {
244 ErrorF("WaitForSomething(): select: %s\n",
245 strerror(selecterr
));
248 else if (someReady
) {
250 * If no-one else is home, bail quickly
252 XFD_COPYSET(&ClientsWithInput
, &LastSelectMask
);
253 XFD_COPYSET(&ClientsWithInput
, &clientsReadable
);
256 if (*checkForInput
[0] != *checkForInput
[1])
262 now
= GetTimeInMillis();
263 if ((int) (timers
->expires
- now
) <= 0)
266 while (timers
&& (int) (timers
->expires
- now
) <= 0)
267 DoTimer(timers
, now
, &timers
);
276 if (*checkForInput
[0] == *checkForInput
[1]) {
280 now
= GetTimeInMillis();
281 if ((int) (timers
->expires
- now
) <= 0)
284 while (timers
&& (int) (timers
->expires
- now
) <= 0)
285 DoTimer(timers
, now
, &timers
);
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
;
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
);
308 if (XFD_ANYSET(&devicesReadable
) || XFD_ANYSET(&clientsReadable
))
310 /* check here for DDXes that queue events during Block/Wakeup */
311 if (*checkForInput
[0] != *checkForInput
[1])
317 if (XFD_ANYSET(&clientsReadable
)) {
319 for (i
= 0; i
< howmany(XFD_SETSIZE
, NFDBITS
); i
++) {
320 int highest_priority
= 0;
322 while (clientsReadable
.fds_bits
[i
]) {
323 int client_priority
, client_index
;
325 curclient
= mffs(clientsReadable
.fds_bits
[i
]) - 1;
326 client_index
= /* raphael: modified */
327 ConnectionTranslation
[curclient
+
328 (i
* (sizeof(fd_mask
) * 8))];
330 int highest_priority
= 0;
331 fd_set savedClientsReadable
;
333 XFD_COPYSET(&clientsReadable
, &savedClientsReadable
);
334 for (i
= 0; i
< XFD_SETCOUNT(&savedClientsReadable
); i
++) {
335 int client_priority
, client_index
;
337 curclient
= XFD_FD(&savedClientsReadable
, i
);
338 client_index
= GetConnectionTranslation(curclient
);
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
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
357 pClientsReady
[0] = client_index
;
358 highest_priority
= client_priority
;
361 /* the following if makes sure that multiple same-priority
362 * clients get batched together
364 else if (client_priority
== highest_priority
) {
365 pClientsReady
[nready
++] = client_index
;
368 clientsReadable
.fds_bits
[i
] &= ~(((fd_mask
) 1L) << curclient
);
371 FD_CLR(curclient
, &clientsReadable
);
377 SmartScheduleStartTimer();
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. */
392 now
= GetTimeInMillis();
394 for (timer
= timers
; timer
; timer
= timer
->next
) {
395 if (timer
->expires
- now
> timer
->delta
+ 250) {
404 DoTimer(OsTimerPtr timer
, CARD32 now
, OsTimerPtr
*prev
)
411 newTime
= (*timer
->callback
) (timer
, now
, timer
->arg
);
413 TimerSet(timer
, 0, newTime
, timer
->callback
, timer
->arg
);
418 TimerSet(OsTimerPtr timer
, int flags
, CARD32 millis
,
419 OsTimerCallback func
, pointer arg
)
421 register OsTimerPtr
*prev
;
422 CARD32 now
= GetTimeInMillis();
425 timer
= malloc(sizeof(struct _OsTimerRec
));
431 for (prev
= &timers
; *prev
; prev
= &(*prev
)->next
) {
432 if (*prev
== timer
) {
434 if (flags
& TimerForceOld
)
435 (void) (*timer
->callback
) (timer
, now
, timer
->arg
);
443 if (flags
& TimerAbsolute
) {
444 timer
->delta
= millis
- now
;
447 timer
->delta
= millis
;
450 timer
->expires
= millis
;
451 timer
->callback
= func
;
453 if ((int) (millis
- now
) <= 0) {
455 millis
= (*timer
->callback
) (timer
, now
, timer
->arg
);
461 *prev
&& (int) ((*prev
)->expires
- millis
) <= 0;
462 prev
= &(*prev
)->next
);
470 TimerForce(OsTimerPtr timer
)
476 for (prev
= &timers
; *prev
; prev
= &(*prev
)->next
) {
477 if (*prev
== timer
) {
478 DoTimer(timer
, GetTimeInMillis(), prev
);
488 TimerCancel(OsTimerPtr timer
)
495 for (prev
= &timers
; *prev
; prev
= &(*prev
)->next
) {
496 if (*prev
== timer
) {
505 TimerFree(OsTimerPtr timer
)
516 CARD32 now
= GetTimeInMillis();
518 while (timers
&& (int) (timers
->expires
- now
) <= 0)
519 DoTimer(timers
, now
, &timers
);
527 while ((timer
= timers
)) {
528 timers
= timer
->next
;
535 #define DPMS_CHECK_MODE(mode,time)\
536 if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\
537 DPMSSet(serverClient, mode);
539 #define DPMS_CHECK_TIMEOUT(time)\
540 if (time > 0 && (time - timeout) > 0)\
541 return time - timeout;
544 NextDPMSTimeout(INT32 timeout
)
547 * Return the amount of time remaining until we should set
548 * the next power level. Fallthroughs are intentional.
550 switch (DPMSPowerLevel
) {
552 DPMS_CHECK_TIMEOUT(DPMSStandbyTime
)
554 case DPMSModeStandby
:
555 DPMS_CHECK_TIMEOUT(DPMSSuspendTime
)
557 case DPMSModeSuspend
:
558 DPMS_CHECK_TIMEOUT(DPMSOffTime
)
560 default: /* DPMSModeOff */
564 #endif /* DPMSExtension */
567 ScreenSaverTimeoutExpire(OsTimerPtr timer
, CARD32 now
, pointer arg
)
569 INT32 timeout
= now
- LastEventTime(XIAllDevices
).milliseconds
;
570 CARD32 nextTimeout
= 0;
574 * Check each mode lowest to highest, since a lower mode can
575 * have the same timeout as a higher one.
578 DPMS_CHECK_MODE(DPMSModeOff
, DPMSOffTime
)
579 DPMS_CHECK_MODE(DPMSModeSuspend
, DPMSSuspendTime
)
580 DPMS_CHECK_MODE(DPMSModeStandby
, DPMSStandbyTime
)
582 nextTimeout
= NextDPMSTimeout(timeout
);
586 * Only do the screensaver checks if we're not in a DPMS
589 if (DPMSPowerLevel
!= DPMSModeOn
)
591 #endif /* DPMSExtension */
593 if (!ScreenSaverTime
)
596 if (timeout
< ScreenSaverTime
) {
597 return nextTimeout
> 0 ?
598 min(ScreenSaverTime
- timeout
, nextTimeout
) :
599 ScreenSaverTime
- timeout
;
602 ResetOsBuffers(); /* not ideal, but better than nothing */
603 dixSaveScreens(serverClient
, SCREEN_SAVER_ON
, ScreenSaverActive
);
605 if (ScreenSaverInterval
> 0) {
606 nextTimeout
= nextTimeout
> 0 ?
607 min(ScreenSaverInterval
, nextTimeout
) : ScreenSaverInterval
;
613 static OsTimerPtr ScreenSaverTimer
= NULL
;
616 FreeScreenSaverTimer(void)
618 if (ScreenSaverTimer
) {
619 TimerFree(ScreenSaverTimer
);
620 ScreenSaverTimer
= NULL
;
625 SetScreenSaverTimer(void)
632 * A higher DPMS level has a timeout that's either less
633 * than or equal to that of a lower DPMS level.
635 if (DPMSStandbyTime
> 0)
636 timeout
= DPMSStandbyTime
;
638 else if (DPMSSuspendTime
> 0)
639 timeout
= DPMSSuspendTime
;
641 else if (DPMSOffTime
> 0)
642 timeout
= DPMSOffTime
;
646 if (ScreenSaverTime
> 0) {
647 timeout
= timeout
> 0 ? min(ScreenSaverTime
, timeout
) : ScreenSaverTime
;
651 if (timeout
&& !screenSaverSuspended
) {
655 ScreenSaverTimer
= TimerSet(ScreenSaverTimer
, 0, timeout
,
656 ScreenSaverTimeoutExpire
, NULL
);
658 else if (ScreenSaverTimer
) {
659 FreeScreenSaverTimer();