xref: /OK3568_Linux_fs/external/xserver/os/WaitFor.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /***********************************************************
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun Copyright 1987, 1998  The Open Group
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun Permission to use, copy, modify, distribute, and sell this software and its
6*4882a593Smuzhiyun documentation for any purpose is hereby granted without fee, provided that
7*4882a593Smuzhiyun the above copyright notice appear in all copies and that both that
8*4882a593Smuzhiyun copyright notice and this permission notice appear in supporting
9*4882a593Smuzhiyun documentation.
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun The above copyright notice and this permission notice shall be included in
12*4882a593Smuzhiyun all copies or substantial portions of the Software.
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*4882a593Smuzhiyun IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*4882a593Smuzhiyun FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17*4882a593Smuzhiyun OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18*4882a593Smuzhiyun AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19*4882a593Smuzhiyun CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun Except as contained in this notice, the name of The Open Group shall not be
22*4882a593Smuzhiyun used in advertising or otherwise to promote the sale, use or other dealings
23*4882a593Smuzhiyun in this Software without prior written authorization from The Open Group.
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun                         All Rights Reserved
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun Permission to use, copy, modify, and distribute this software and its
30*4882a593Smuzhiyun documentation for any purpose and without fee is hereby granted,
31*4882a593Smuzhiyun provided that the above copyright notice appear in all copies and that
32*4882a593Smuzhiyun both that copyright notice and this permission notice appear in
33*4882a593Smuzhiyun supporting documentation, and that the name of Digital not be
34*4882a593Smuzhiyun used in advertising or publicity pertaining to distribution of the
35*4882a593Smuzhiyun software without specific, written prior permission.
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38*4882a593Smuzhiyun ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39*4882a593Smuzhiyun DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40*4882a593Smuzhiyun ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41*4882a593Smuzhiyun WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42*4882a593Smuzhiyun ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43*4882a593Smuzhiyun SOFTWARE.
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun ******************************************************************/
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /*****************************************************************
48*4882a593Smuzhiyun  * OS Dependent input routines:
49*4882a593Smuzhiyun  *
50*4882a593Smuzhiyun  *  WaitForSomething
51*4882a593Smuzhiyun  *  TimerForce, TimerSet, TimerCheck, TimerFree
52*4882a593Smuzhiyun  *
53*4882a593Smuzhiyun  *****************************************************************/
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
56*4882a593Smuzhiyun #include <dix-config.h>
57*4882a593Smuzhiyun #endif
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #ifdef WIN32
60*4882a593Smuzhiyun #include <X11/Xwinsock.h>
61*4882a593Smuzhiyun #endif
62*4882a593Smuzhiyun #include <X11/Xos.h>            /* for strings, fcntl, time */
63*4882a593Smuzhiyun #include <errno.h>
64*4882a593Smuzhiyun #include <stdio.h>
65*4882a593Smuzhiyun #include <X11/X.h>
66*4882a593Smuzhiyun #include "misc.h"
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #include "osdep.h"
69*4882a593Smuzhiyun #include "dixstruct.h"
70*4882a593Smuzhiyun #include "opaque.h"
71*4882a593Smuzhiyun #ifdef DPMSExtension
72*4882a593Smuzhiyun #include "dpmsproc.h"
73*4882a593Smuzhiyun #endif
74*4882a593Smuzhiyun #include "busfault.h"
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #ifdef WIN32
77*4882a593Smuzhiyun /* Error codes from windows sockets differ from fileio error codes  */
78*4882a593Smuzhiyun #undef EINTR
79*4882a593Smuzhiyun #define EINTR WSAEINTR
80*4882a593Smuzhiyun #undef EINVAL
81*4882a593Smuzhiyun #define EINVAL WSAEINVAL
82*4882a593Smuzhiyun #undef EBADF
83*4882a593Smuzhiyun #define EBADF WSAENOTSOCK
84*4882a593Smuzhiyun /* Windows select does not set errno. Use GetErrno as wrapper for
85*4882a593Smuzhiyun    WSAGetLastError */
86*4882a593Smuzhiyun #define GetErrno WSAGetLastError
87*4882a593Smuzhiyun #else
88*4882a593Smuzhiyun /* This is just a fallback to errno to hide the differences between unix and
89*4882a593Smuzhiyun    Windows in the code */
90*4882a593Smuzhiyun #define GetErrno() errno
91*4882a593Smuzhiyun #endif
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun #ifdef DPMSExtension
94*4882a593Smuzhiyun #include <X11/extensions/dpmsconst.h>
95*4882a593Smuzhiyun #endif
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun struct _OsTimerRec {
98*4882a593Smuzhiyun     struct xorg_list list;
99*4882a593Smuzhiyun     CARD32 expires;
100*4882a593Smuzhiyun     CARD32 delta;
101*4882a593Smuzhiyun     OsTimerCallback callback;
102*4882a593Smuzhiyun     void *arg;
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun static void DoTimer(OsTimerPtr timer, CARD32 now);
106*4882a593Smuzhiyun static void DoTimers(CARD32 now);
107*4882a593Smuzhiyun static void CheckAllTimers(void);
108*4882a593Smuzhiyun static volatile struct xorg_list timers;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun static inline OsTimerPtr
first_timer(void)111*4882a593Smuzhiyun first_timer(void)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun     /* inline xorg_list_is_empty which can't handle volatile */
114*4882a593Smuzhiyun     if (timers.next == &timers)
115*4882a593Smuzhiyun         return NULL;
116*4882a593Smuzhiyun     return xorg_list_first_entry(&timers, struct _OsTimerRec, list);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun /*
120*4882a593Smuzhiyun  * Compute timeout until next timer, running
121*4882a593Smuzhiyun  * any expired timers
122*4882a593Smuzhiyun  */
123*4882a593Smuzhiyun static int
check_timers(void)124*4882a593Smuzhiyun check_timers(void)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun     OsTimerPtr timer;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun     if ((timer = first_timer()) != NULL) {
129*4882a593Smuzhiyun         CARD32 now = GetTimeInMillis();
130*4882a593Smuzhiyun         int timeout = timer->expires - now;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun         if (timeout <= 0) {
133*4882a593Smuzhiyun             DoTimers(now);
134*4882a593Smuzhiyun         } else {
135*4882a593Smuzhiyun             /* Make sure the timeout is sane */
136*4882a593Smuzhiyun             if (timeout < timer->delta + 250)
137*4882a593Smuzhiyun                 return timeout;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun             /* time has rewound.  reset the timers. */
140*4882a593Smuzhiyun             CheckAllTimers();
141*4882a593Smuzhiyun         }
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun         return 0;
144*4882a593Smuzhiyun     }
145*4882a593Smuzhiyun     return -1;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun /*****************
149*4882a593Smuzhiyun  * WaitForSomething:
150*4882a593Smuzhiyun  *     Make the server suspend until there is
151*4882a593Smuzhiyun  *	1. data from clients or
152*4882a593Smuzhiyun  *	2. input events available or
153*4882a593Smuzhiyun  *	3. ddx notices something of interest (graphics
154*4882a593Smuzhiyun  *	   queue ready, etc.) or
155*4882a593Smuzhiyun  *	4. clients that have buffered replies/events are ready
156*4882a593Smuzhiyun  *
157*4882a593Smuzhiyun  *     If the time between INPUT events is
158*4882a593Smuzhiyun  *     greater than ScreenSaverTime, the display is turned off (or
159*4882a593Smuzhiyun  *     saved, depending on the hardware).  So, WaitForSomething()
160*4882a593Smuzhiyun  *     has to handle this also (that's why the select() has a timeout.
161*4882a593Smuzhiyun  *     For more info on ClientsWithInput, see ReadRequestFromClient().
162*4882a593Smuzhiyun  *     pClientsReady is an array to store ready client->index values into.
163*4882a593Smuzhiyun  *****************/
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun Bool
WaitForSomething(Bool are_ready)166*4882a593Smuzhiyun WaitForSomething(Bool are_ready)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun     int i;
169*4882a593Smuzhiyun     int timeout;
170*4882a593Smuzhiyun     int pollerr;
171*4882a593Smuzhiyun     static Bool were_ready;
172*4882a593Smuzhiyun     Bool timer_is_running;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun     timer_is_running = were_ready;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun     if (were_ready && !are_ready) {
177*4882a593Smuzhiyun         timer_is_running = FALSE;
178*4882a593Smuzhiyun         SmartScheduleStopTimer();
179*4882a593Smuzhiyun     }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun     were_ready = FALSE;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun #ifdef BUSFAULT
184*4882a593Smuzhiyun     busfault_check();
185*4882a593Smuzhiyun #endif
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun     /* We need a while loop here to handle
188*4882a593Smuzhiyun        crashed connections and the screen saver timeout */
189*4882a593Smuzhiyun     while (1) {
190*4882a593Smuzhiyun         /* deal with any blocked jobs */
191*4882a593Smuzhiyun         if (workQueue) {
192*4882a593Smuzhiyun             ProcessWorkQueue();
193*4882a593Smuzhiyun         }
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun         timeout = check_timers();
196*4882a593Smuzhiyun         are_ready = clients_are_ready();
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun         if (are_ready)
199*4882a593Smuzhiyun             timeout = 0;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun         BlockHandler(&timeout);
202*4882a593Smuzhiyun         if (NewOutputPending)
203*4882a593Smuzhiyun             FlushAllOutput();
204*4882a593Smuzhiyun         /* keep this check close to select() call to minimize race */
205*4882a593Smuzhiyun         if (dispatchException)
206*4882a593Smuzhiyun             i = -1;
207*4882a593Smuzhiyun         else
208*4882a593Smuzhiyun             i = ospoll_wait(server_poll, timeout);
209*4882a593Smuzhiyun         pollerr = GetErrno();
210*4882a593Smuzhiyun         WakeupHandler(i);
211*4882a593Smuzhiyun         if (i <= 0) {           /* An error or timeout occurred */
212*4882a593Smuzhiyun             if (dispatchException)
213*4882a593Smuzhiyun                 return FALSE;
214*4882a593Smuzhiyun             if (i < 0) {
215*4882a593Smuzhiyun                 if (pollerr != EINTR && !ETEST(pollerr)) {
216*4882a593Smuzhiyun                     ErrorF("WaitForSomething(): poll: %s\n",
217*4882a593Smuzhiyun                            strerror(pollerr));
218*4882a593Smuzhiyun                 }
219*4882a593Smuzhiyun             }
220*4882a593Smuzhiyun         } else
221*4882a593Smuzhiyun             are_ready = clients_are_ready();
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun         if (InputCheckPending())
224*4882a593Smuzhiyun             return FALSE;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun         if (are_ready) {
227*4882a593Smuzhiyun             were_ready = TRUE;
228*4882a593Smuzhiyun             if (!timer_is_running)
229*4882a593Smuzhiyun                 SmartScheduleStartTimer();
230*4882a593Smuzhiyun             return TRUE;
231*4882a593Smuzhiyun         }
232*4882a593Smuzhiyun     }
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun void
AdjustWaitForDelay(void * waitTime,int newdelay)236*4882a593Smuzhiyun AdjustWaitForDelay(void *waitTime, int newdelay)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun     int *timeoutp = waitTime;
239*4882a593Smuzhiyun     int timeout = *timeoutp;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun     if (timeout < 0 || newdelay < timeout)
242*4882a593Smuzhiyun         *timeoutp = newdelay;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun 
timer_pending(OsTimerPtr timer)245*4882a593Smuzhiyun static inline Bool timer_pending(OsTimerPtr timer) {
246*4882a593Smuzhiyun     return !xorg_list_is_empty(&timer->list);
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun /* If time has rewound, re-run every affected timer.
250*4882a593Smuzhiyun  * Timers might drop out of the list, so we have to restart every time. */
251*4882a593Smuzhiyun static void
CheckAllTimers(void)252*4882a593Smuzhiyun CheckAllTimers(void)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun     OsTimerPtr timer;
255*4882a593Smuzhiyun     CARD32 now;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun     input_lock();
258*4882a593Smuzhiyun  start:
259*4882a593Smuzhiyun     now = GetTimeInMillis();
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun     xorg_list_for_each_entry(timer, &timers, list) {
262*4882a593Smuzhiyun         if (timer->expires - now > timer->delta + 250) {
263*4882a593Smuzhiyun             DoTimer(timer, now);
264*4882a593Smuzhiyun             goto start;
265*4882a593Smuzhiyun         }
266*4882a593Smuzhiyun     }
267*4882a593Smuzhiyun     input_unlock();
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun static void
DoTimer(OsTimerPtr timer,CARD32 now)271*4882a593Smuzhiyun DoTimer(OsTimerPtr timer, CARD32 now)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun     CARD32 newTime;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun     xorg_list_del(&timer->list);
276*4882a593Smuzhiyun     newTime = (*timer->callback) (timer, now, timer->arg);
277*4882a593Smuzhiyun     if (newTime)
278*4882a593Smuzhiyun         TimerSet(timer, 0, newTime, timer->callback, timer->arg);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun static void
DoTimers(CARD32 now)282*4882a593Smuzhiyun DoTimers(CARD32 now)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun     OsTimerPtr  timer;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun     input_lock();
287*4882a593Smuzhiyun     while ((timer = first_timer())) {
288*4882a593Smuzhiyun         if ((int) (timer->expires - now) > 0)
289*4882a593Smuzhiyun             break;
290*4882a593Smuzhiyun         DoTimer(timer, now);
291*4882a593Smuzhiyun     }
292*4882a593Smuzhiyun     input_unlock();
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun OsTimerPtr
TimerSet(OsTimerPtr timer,int flags,CARD32 millis,OsTimerCallback func,void * arg)296*4882a593Smuzhiyun TimerSet(OsTimerPtr timer, int flags, CARD32 millis,
297*4882a593Smuzhiyun          OsTimerCallback func, void *arg)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun     OsTimerPtr existing, tmp;
300*4882a593Smuzhiyun     CARD32 now = GetTimeInMillis();
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun     if (!timer) {
303*4882a593Smuzhiyun         timer = calloc(1, sizeof(struct _OsTimerRec));
304*4882a593Smuzhiyun         if (!timer)
305*4882a593Smuzhiyun             return NULL;
306*4882a593Smuzhiyun         xorg_list_init(&timer->list);
307*4882a593Smuzhiyun     }
308*4882a593Smuzhiyun     else {
309*4882a593Smuzhiyun         input_lock();
310*4882a593Smuzhiyun         if (timer_pending(timer)) {
311*4882a593Smuzhiyun             xorg_list_del(&timer->list);
312*4882a593Smuzhiyun             if (flags & TimerForceOld)
313*4882a593Smuzhiyun                 (void) (*timer->callback) (timer, now, timer->arg);
314*4882a593Smuzhiyun         }
315*4882a593Smuzhiyun         input_unlock();
316*4882a593Smuzhiyun     }
317*4882a593Smuzhiyun     if (!millis)
318*4882a593Smuzhiyun         return timer;
319*4882a593Smuzhiyun     if (flags & TimerAbsolute) {
320*4882a593Smuzhiyun         timer->delta = millis - now;
321*4882a593Smuzhiyun     }
322*4882a593Smuzhiyun     else {
323*4882a593Smuzhiyun         timer->delta = millis;
324*4882a593Smuzhiyun         millis += now;
325*4882a593Smuzhiyun     }
326*4882a593Smuzhiyun     timer->expires = millis;
327*4882a593Smuzhiyun     timer->callback = func;
328*4882a593Smuzhiyun     timer->arg = arg;
329*4882a593Smuzhiyun     input_lock();
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun     /* Sort into list */
332*4882a593Smuzhiyun     xorg_list_for_each_entry_safe(existing, tmp, &timers, list)
333*4882a593Smuzhiyun         if ((int) (existing->expires - millis) > 0)
334*4882a593Smuzhiyun             break;
335*4882a593Smuzhiyun     /* This even works at the end of the list -- existing->list will be timers */
336*4882a593Smuzhiyun     xorg_list_add(&timer->list, existing->list.prev);
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun     /* Check to see if the timer is ready to run now */
339*4882a593Smuzhiyun     if ((int) (millis - now) <= 0)
340*4882a593Smuzhiyun         DoTimer(timer, now);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun     input_unlock();
343*4882a593Smuzhiyun     return timer;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun Bool
TimerForce(OsTimerPtr timer)347*4882a593Smuzhiyun TimerForce(OsTimerPtr timer)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun     int pending;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun     input_lock();
352*4882a593Smuzhiyun     pending = timer_pending(timer);
353*4882a593Smuzhiyun     if (pending)
354*4882a593Smuzhiyun         DoTimer(timer, GetTimeInMillis());
355*4882a593Smuzhiyun     input_unlock();
356*4882a593Smuzhiyun     return pending;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun void
TimerCancel(OsTimerPtr timer)360*4882a593Smuzhiyun TimerCancel(OsTimerPtr timer)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun     if (!timer)
363*4882a593Smuzhiyun         return;
364*4882a593Smuzhiyun     input_lock();
365*4882a593Smuzhiyun     xorg_list_del(&timer->list);
366*4882a593Smuzhiyun     input_unlock();
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun void
TimerFree(OsTimerPtr timer)370*4882a593Smuzhiyun TimerFree(OsTimerPtr timer)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun     if (!timer)
373*4882a593Smuzhiyun         return;
374*4882a593Smuzhiyun     TimerCancel(timer);
375*4882a593Smuzhiyun     free(timer);
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun void
TimerCheck(void)379*4882a593Smuzhiyun TimerCheck(void)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun     DoTimers(GetTimeInMillis());
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun void
TimerInit(void)385*4882a593Smuzhiyun TimerInit(void)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun     static Bool been_here;
388*4882a593Smuzhiyun     OsTimerPtr timer, tmp;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun     if (!been_here) {
391*4882a593Smuzhiyun         been_here = TRUE;
392*4882a593Smuzhiyun         xorg_list_init((struct xorg_list*) &timers);
393*4882a593Smuzhiyun     }
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun     xorg_list_for_each_entry_safe(timer, tmp, &timers, list) {
396*4882a593Smuzhiyun         xorg_list_del(&timer->list);
397*4882a593Smuzhiyun         free(timer);
398*4882a593Smuzhiyun     }
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun #ifdef DPMSExtension
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun #define DPMS_CHECK_MODE(mode,time)\
404*4882a593Smuzhiyun     if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\
405*4882a593Smuzhiyun 	DPMSSet(serverClient, mode);
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun #define DPMS_CHECK_TIMEOUT(time)\
408*4882a593Smuzhiyun     if (time > 0 && (time - timeout) > 0)\
409*4882a593Smuzhiyun 	return time - timeout;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun static CARD32
NextDPMSTimeout(INT32 timeout)412*4882a593Smuzhiyun NextDPMSTimeout(INT32 timeout)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun     /*
415*4882a593Smuzhiyun      * Return the amount of time remaining until we should set
416*4882a593Smuzhiyun      * the next power level. Fallthroughs are intentional.
417*4882a593Smuzhiyun      */
418*4882a593Smuzhiyun     switch (DPMSPowerLevel) {
419*4882a593Smuzhiyun     case DPMSModeOn:
420*4882a593Smuzhiyun         DPMS_CHECK_TIMEOUT(DPMSStandbyTime)
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun     case DPMSModeStandby:
423*4882a593Smuzhiyun         DPMS_CHECK_TIMEOUT(DPMSSuspendTime)
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun     case DPMSModeSuspend:
426*4882a593Smuzhiyun         DPMS_CHECK_TIMEOUT(DPMSOffTime)
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun     default:                   /* DPMSModeOff */
429*4882a593Smuzhiyun         return 0;
430*4882a593Smuzhiyun     }
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun #endif                          /* DPMSExtension */
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun static CARD32
ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,void * arg)435*4882a593Smuzhiyun ScreenSaverTimeoutExpire(OsTimerPtr timer, CARD32 now, void *arg)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun     INT32 timeout = now - LastEventTime(XIAllDevices).milliseconds;
438*4882a593Smuzhiyun     CARD32 nextTimeout = 0;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun #ifdef DPMSExtension
441*4882a593Smuzhiyun     /*
442*4882a593Smuzhiyun      * Check each mode lowest to highest, since a lower mode can
443*4882a593Smuzhiyun      * have the same timeout as a higher one.
444*4882a593Smuzhiyun      */
445*4882a593Smuzhiyun     if (DPMSEnabled) {
446*4882a593Smuzhiyun         DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime)
447*4882a593Smuzhiyun             DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime)
448*4882a593Smuzhiyun             DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime)
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun             nextTimeout = NextDPMSTimeout(timeout);
451*4882a593Smuzhiyun     }
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun     /*
454*4882a593Smuzhiyun      * Only do the screensaver checks if we're not in a DPMS
455*4882a593Smuzhiyun      * power saving mode
456*4882a593Smuzhiyun      */
457*4882a593Smuzhiyun     if (DPMSPowerLevel != DPMSModeOn)
458*4882a593Smuzhiyun         return nextTimeout;
459*4882a593Smuzhiyun #endif                          /* DPMSExtension */
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun     if (!ScreenSaverTime)
462*4882a593Smuzhiyun         return nextTimeout;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun     if (timeout < ScreenSaverTime) {
465*4882a593Smuzhiyun         return nextTimeout > 0 ?
466*4882a593Smuzhiyun             min(ScreenSaverTime - timeout, nextTimeout) :
467*4882a593Smuzhiyun             ScreenSaverTime - timeout;
468*4882a593Smuzhiyun     }
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun     ResetOsBuffers();           /* not ideal, but better than nothing */
471*4882a593Smuzhiyun     dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun     if (ScreenSaverInterval > 0) {
474*4882a593Smuzhiyun         nextTimeout = nextTimeout > 0 ?
475*4882a593Smuzhiyun             min(ScreenSaverInterval, nextTimeout) : ScreenSaverInterval;
476*4882a593Smuzhiyun     }
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun     return nextTimeout;
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun static OsTimerPtr ScreenSaverTimer = NULL;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun void
FreeScreenSaverTimer(void)484*4882a593Smuzhiyun FreeScreenSaverTimer(void)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun     if (ScreenSaverTimer) {
487*4882a593Smuzhiyun         TimerFree(ScreenSaverTimer);
488*4882a593Smuzhiyun         ScreenSaverTimer = NULL;
489*4882a593Smuzhiyun     }
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun void
SetScreenSaverTimer(void)493*4882a593Smuzhiyun SetScreenSaverTimer(void)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun     CARD32 timeout = 0;
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun #ifdef DPMSExtension
498*4882a593Smuzhiyun     if (DPMSEnabled) {
499*4882a593Smuzhiyun         /*
500*4882a593Smuzhiyun          * A higher DPMS level has a timeout that's either less
501*4882a593Smuzhiyun          * than or equal to that of a lower DPMS level.
502*4882a593Smuzhiyun          */
503*4882a593Smuzhiyun         if (DPMSStandbyTime > 0)
504*4882a593Smuzhiyun             timeout = DPMSStandbyTime;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun         else if (DPMSSuspendTime > 0)
507*4882a593Smuzhiyun             timeout = DPMSSuspendTime;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun         else if (DPMSOffTime > 0)
510*4882a593Smuzhiyun             timeout = DPMSOffTime;
511*4882a593Smuzhiyun     }
512*4882a593Smuzhiyun #endif
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun     if (ScreenSaverTime > 0) {
515*4882a593Smuzhiyun         timeout = timeout > 0 ? min(ScreenSaverTime, timeout) : ScreenSaverTime;
516*4882a593Smuzhiyun     }
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun #ifdef SCREENSAVER
519*4882a593Smuzhiyun     if (timeout && !screenSaverSuspended) {
520*4882a593Smuzhiyun #else
521*4882a593Smuzhiyun     if (timeout) {
522*4882a593Smuzhiyun #endif
523*4882a593Smuzhiyun         ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout,
524*4882a593Smuzhiyun                                     ScreenSaverTimeoutExpire, NULL);
525*4882a593Smuzhiyun     }
526*4882a593Smuzhiyun     else if (ScreenSaverTimer) {
527*4882a593Smuzhiyun         FreeScreenSaverTimer();
528*4882a593Smuzhiyun     }
529*4882a593Smuzhiyun }
530