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 "dixstruct.h"
70 #include "opaque.h"
71 #ifdef DPMSExtension
72 #include "dpmsproc.h"
73 #endif
74 #include "busfault.h"
75 
76 #ifdef WIN32
77 /* Error codes from windows sockets differ from fileio error codes  */
78 #undef EINTR
79 #define EINTR WSAEINTR
80 #undef EINVAL
81 #define EINVAL WSAEINVAL
82 #undef EBADF
83 #define EBADF WSAENOTSOCK
84 /* Windows select does not set errno. Use GetErrno as wrapper for
85    WSAGetLastError */
86 #define GetErrno WSAGetLastError
87 #else
88 /* This is just a fallback to errno to hide the differences between unix and
89    Windows in the code */
90 #define GetErrno() errno
91 #endif
92 
93 #ifdef DPMSExtension
94 #include <X11/extensions/dpmsconst.h>
95 #endif
96 
97 struct _OsTimerRec {
98     struct xorg_list list;
99     CARD32 expires;
100     CARD32 delta;
101     OsTimerCallback callback;
102     void *arg;
103 };
104 
105 static void DoTimer(OsTimerPtr timer, CARD32 now);
106 static void DoTimers(CARD32 now);
107 static void CheckAllTimers(void);
108 static volatile struct xorg_list timers;
109 
110 static inline OsTimerPtr
first_timer(void)111 first_timer(void)
112 {
113     /* inline xorg_list_is_empty which can't handle volatile */
114     if (timers.next == &timers)
115         return NULL;
116     return xorg_list_first_entry(&timers, struct _OsTimerRec, list);
117 }
118 
119 /*
120  * Compute timeout until next timer, running
121  * any expired timers
122  */
123 static int
check_timers(void)124 check_timers(void)
125 {
126     OsTimerPtr timer;
127 
128     if ((timer = first_timer()) != NULL) {
129         CARD32 now = GetTimeInMillis();
130         int timeout = timer->expires - now;
131 
132         if (timeout <= 0) {
133             DoTimers(now);
134         } else {
135             /* Make sure the timeout is sane */
136             if (timeout < timer->delta + 250)
137                 return timeout;
138 
139             /* time has rewound.  reset the timers. */
140             CheckAllTimers();
141         }
142 
143         return 0;
144     }
145     return -1;
146 }
147 
148 /*****************
149  * WaitForSomething:
150  *     Make the server suspend until there is
151  *	1. data from clients or
152  *	2. input events available or
153  *	3. ddx notices something of interest (graphics
154  *	   queue ready, etc.) or
155  *	4. clients that have buffered replies/events are ready
156  *
157  *     If the time between INPUT events is
158  *     greater than ScreenSaverTime, the display is turned off (or
159  *     saved, depending on the hardware).  So, WaitForSomething()
160  *     has to handle this also (that's why the select() has a timeout.
161  *     For more info on ClientsWithInput, see ReadRequestFromClient().
162  *     pClientsReady is an array to store ready client->index values into.
163  *****************/
164 
165 Bool
WaitForSomething(Bool are_ready)166 WaitForSomething(Bool are_ready)
167 {
168     int i;
169     int timeout;
170     int pollerr;
171     static Bool were_ready;
172     Bool timer_is_running;
173 
174     timer_is_running = were_ready;
175 
176     if (were_ready && !are_ready) {
177         timer_is_running = FALSE;
178         SmartScheduleStopTimer();
179     }
180 
181     were_ready = FALSE;
182 
183 #ifdef BUSFAULT
184     busfault_check();
185 #endif
186 
187     /* We need a while loop here to handle
188        crashed connections and the screen saver timeout */
189     while (1) {
190         /* deal with any blocked jobs */
191         if (workQueue) {
192             ProcessWorkQueue();
193         }
194 
195         timeout = check_timers();
196         are_ready = clients_are_ready();
197 
198         if (are_ready)
199             timeout = 0;
200 
201         BlockHandler(&timeout);
202         if (NewOutputPending)
203             FlushAllOutput();
204         /* keep this check close to select() call to minimize race */
205         if (dispatchException)
206             i = -1;
207         else
208             i = ospoll_wait(server_poll, timeout);
209         pollerr = GetErrno();
210         WakeupHandler(i);
211         if (i <= 0) {           /* An error or timeout occurred */
212             if (dispatchException)
213                 return FALSE;
214             if (i < 0) {
215                 if (pollerr != EINTR && !ETEST(pollerr)) {
216                     ErrorF("WaitForSomething(): poll: %s\n",
217                            strerror(pollerr));
218                 }
219             }
220         } else
221             are_ready = clients_are_ready();
222 
223         if (InputCheckPending())
224             return FALSE;
225 
226         if (are_ready) {
227             were_ready = TRUE;
228             if (!timer_is_running)
229                 SmartScheduleStartTimer();
230             return TRUE;
231         }
232     }
233 }
234 
235 void
AdjustWaitForDelay(void * waitTime,int newdelay)236 AdjustWaitForDelay(void *waitTime, int newdelay)
237 {
238     int *timeoutp = waitTime;
239     int timeout = *timeoutp;
240 
241     if (timeout < 0 || newdelay < timeout)
242         *timeoutp = newdelay;
243 }
244 
timer_pending(OsTimerPtr timer)245 static inline Bool timer_pending(OsTimerPtr timer) {
246     return !xorg_list_is_empty(&timer->list);
247 }
248 
249 /* If time has rewound, re-run every affected timer.
250  * Timers might drop out of the list, so we have to restart every time. */
251 static void
CheckAllTimers(void)252 CheckAllTimers(void)
253 {
254     OsTimerPtr timer;
255     CARD32 now;
256 
257     input_lock();
258  start:
259     now = GetTimeInMillis();
260 
261     xorg_list_for_each_entry(timer, &timers, list) {
262         if (timer->expires - now > timer->delta + 250) {
263             DoTimer(timer, now);
264             goto start;
265         }
266     }
267     input_unlock();
268 }
269 
270 static void
DoTimer(OsTimerPtr timer,CARD32 now)271 DoTimer(OsTimerPtr timer, CARD32 now)
272 {
273     CARD32 newTime;
274 
275     xorg_list_del(&timer->list);
276     newTime = (*timer->callback) (timer, now, timer->arg);
277     if (newTime)
278         TimerSet(timer, 0, newTime, timer->callback, timer->arg);
279 }
280 
281 static void
DoTimers(CARD32 now)282 DoTimers(CARD32 now)
283 {
284     OsTimerPtr  timer;
285 
286     input_lock();
287     while ((timer = first_timer())) {
288         if ((int) (timer->expires - now) > 0)
289             break;
290         DoTimer(timer, now);
291     }
292     input_unlock();
293 }
294 
295 OsTimerPtr
TimerSet(OsTimerPtr timer,int flags,CARD32 millis,OsTimerCallback func,void * arg)296 TimerSet(OsTimerPtr timer, int flags, CARD32 millis,
297          OsTimerCallback func, void *arg)
298 {
299     OsTimerPtr existing;
300     CARD32 now = GetTimeInMillis();
301 
302     if (!timer) {
303         timer = calloc(1, sizeof(struct _OsTimerRec));
304         if (!timer)
305             return NULL;
306         xorg_list_init(&timer->list);
307     }
308     else {
309         input_lock();
310         if (timer_pending(timer)) {
311             xorg_list_del(&timer->list);
312             if (flags & TimerForceOld)
313                 (void) (*timer->callback) (timer, now, timer->arg);
314         }
315         input_unlock();
316     }
317     if (!millis)
318         return timer;
319     if (flags & TimerAbsolute) {
320         timer->delta = millis - now;
321     }
322     else {
323         timer->delta = millis;
324         millis += now;
325     }
326     timer->expires = millis;
327     timer->callback = func;
328     timer->arg = arg;
329     input_lock();
330 
331     /* Sort into list */
332     xorg_list_for_each_entry(existing, &timers, list)
333         if ((int) (existing->expires - millis) > 0)
334             break;
335     /* This even works at the end of the list -- existing->list will be timers */
336     xorg_list_append(&timer->list, &existing->list);
337 
338     /* Check to see if the timer is ready to run now */
339     if ((int) (millis - now) <= 0)
340         DoTimer(timer, now);
341 
342     input_unlock();
343     return timer;
344 }
345 
346 Bool
TimerForce(OsTimerPtr timer)347 TimerForce(OsTimerPtr timer)
348 {
349     int pending;
350 
351     input_lock();
352     pending = timer_pending(timer);
353     if (pending)
354         DoTimer(timer, GetTimeInMillis());
355     input_unlock();
356     return pending;
357 }
358 
359 void
TimerCancel(OsTimerPtr timer)360 TimerCancel(OsTimerPtr timer)
361 {
362     if (!timer)
363         return;
364     input_lock();
365     xorg_list_del(&timer->list);
366     input_unlock();
367 }
368 
369 void
TimerFree(OsTimerPtr timer)370 TimerFree(OsTimerPtr timer)
371 {
372     if (!timer)
373         return;
374     TimerCancel(timer);
375     free(timer);
376 }
377 
378 void
TimerCheck(void)379 TimerCheck(void)
380 {
381     DoTimers(GetTimeInMillis());
382 }
383 
384 void
TimerInit(void)385 TimerInit(void)
386 {
387     static Bool been_here;
388     OsTimerPtr timer, tmp;
389 
390     if (!been_here) {
391         been_here = TRUE;
392         xorg_list_init((struct xorg_list*) &timers);
393     }
394 
395     xorg_list_for_each_entry_safe(timer, tmp, &timers, list) {
396         xorg_list_del(&timer->list);
397         free(timer);
398     }
399 }
400 
401 #ifdef DPMSExtension
402 
403 #define DPMS_CHECK_MODE(mode,time)\
404     if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\
405 	DPMSSet(serverClient, mode);
406 
407 #define DPMS_CHECK_TIMEOUT(time)\
408     if (time > 0 && (time - timeout) > 0)\
409 	return time - timeout;
410 
411 static CARD32
NextDPMSTimeout(INT32 timeout)412 NextDPMSTimeout(INT32 timeout)
413 {
414     /*
415      * Return the amount of time remaining until we should set
416      * the next power level. Fallthroughs are intentional.
417      */
418     switch (DPMSPowerLevel) {
419     case DPMSModeOn:
420         DPMS_CHECK_TIMEOUT(DPMSStandbyTime)
421 
422     case DPMSModeStandby:
423         DPMS_CHECK_TIMEOUT(DPMSSuspendTime)
424 
425     case DPMSModeSuspend:
426         DPMS_CHECK_TIMEOUT(DPMSOffTime)
427 
428     default:                   /* DPMSModeOff */
429         return 0;
430     }
431 }
432 #endif                          /* DPMSExtension */
433 
434 static CARD32
ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,void * arg)435 ScreenSaverTimeoutExpire(OsTimerPtr timer, CARD32 now, void *arg)
436 {
437     INT32 timeout = now - LastEventTime(XIAllDevices).milliseconds;
438     CARD32 nextTimeout = 0;
439 
440 #ifdef DPMSExtension
441     /*
442      * Check each mode lowest to highest, since a lower mode can
443      * have the same timeout as a higher one.
444      */
445     if (DPMSEnabled) {
446         DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime)
447             DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime)
448             DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime)
449 
450             nextTimeout = NextDPMSTimeout(timeout);
451     }
452 
453     /*
454      * Only do the screensaver checks if we're not in a DPMS
455      * power saving mode
456      */
457     if (DPMSPowerLevel != DPMSModeOn)
458         return nextTimeout;
459 #endif                          /* DPMSExtension */
460 
461     if (!ScreenSaverTime)
462         return nextTimeout;
463 
464     if (timeout < ScreenSaverTime) {
465         return nextTimeout > 0 ?
466             min(ScreenSaverTime - timeout, nextTimeout) :
467             ScreenSaverTime - timeout;
468     }
469 
470     ResetOsBuffers();           /* not ideal, but better than nothing */
471     dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive);
472 
473     if (ScreenSaverInterval > 0) {
474         nextTimeout = nextTimeout > 0 ?
475             min(ScreenSaverInterval, nextTimeout) : ScreenSaverInterval;
476     }
477 
478     return nextTimeout;
479 }
480 
481 static OsTimerPtr ScreenSaverTimer = NULL;
482 
483 void
FreeScreenSaverTimer(void)484 FreeScreenSaverTimer(void)
485 {
486     if (ScreenSaverTimer) {
487         TimerFree(ScreenSaverTimer);
488         ScreenSaverTimer = NULL;
489     }
490 }
491 
492 void
SetScreenSaverTimer(void)493 SetScreenSaverTimer(void)
494 {
495     CARD32 timeout = 0;
496 
497 #ifdef DPMSExtension
498     if (DPMSEnabled) {
499         /*
500          * A higher DPMS level has a timeout that's either less
501          * than or equal to that of a lower DPMS level.
502          */
503         if (DPMSStandbyTime > 0)
504             timeout = DPMSStandbyTime;
505 
506         else if (DPMSSuspendTime > 0)
507             timeout = DPMSSuspendTime;
508 
509         else if (DPMSOffTime > 0)
510             timeout = DPMSOffTime;
511     }
512 #endif
513 
514     if (ScreenSaverTime > 0) {
515         timeout = timeout > 0 ? min(ScreenSaverTime, timeout) : ScreenSaverTime;
516     }
517 
518 #ifdef SCREENSAVER
519     if (timeout && !screenSaverSuspended) {
520 #else
521     if (timeout) {
522 #endif
523         ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout,
524                                     ScreenSaverTimeoutExpire, NULL);
525     }
526     else if (ScreenSaverTimer) {
527         FreeScreenSaverTimer();
528     }
529 }
530