WaitFor.c revision f7df2e56
105b261ecSmrg/***********************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1987, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg
2505b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2605b261ecSmrg
2705b261ecSmrg                        All Rights Reserved
2805b261ecSmrg
29f7df2e56SmrgPermission to use, copy, modify, and distribute this software and its
30f7df2e56Smrgdocumentation for any purpose and without fee is hereby granted,
3105b261ecSmrgprovided that the above copyright notice appear in all copies and that
32f7df2e56Smrgboth that copyright notice and this permission notice appear in
3305b261ecSmrgsupporting documentation, and that the name of Digital not be
3405b261ecSmrgused in advertising or publicity pertaining to distribution of the
35f7df2e56Smrgsoftware without specific, written prior permission.
3605b261ecSmrg
3705b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3805b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
3905b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4005b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4105b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4205b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4305b261ecSmrgSOFTWARE.
4405b261ecSmrg
4505b261ecSmrg******************************************************************/
4605b261ecSmrg
4705b261ecSmrg/*****************************************************************
4805b261ecSmrg * OS Dependent input routines:
4905b261ecSmrg *
5005b261ecSmrg *  WaitForSomething
5105b261ecSmrg *  TimerForce, TimerSet, TimerCheck, TimerFree
5205b261ecSmrg *
5305b261ecSmrg *****************************************************************/
5405b261ecSmrg
555bd42952Smrg#include <X11/Xpoll.h>
565bd42952Smrg
5705b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5805b261ecSmrg#include <dix-config.h>
5905b261ecSmrg#endif
6005b261ecSmrg
6105b261ecSmrg#ifdef WIN32
6205b261ecSmrg#include <X11/Xwinsock.h>
6305b261ecSmrg#endif
64f7df2e56Smrg#include <X11/Xos.h>            /* for strings, fcntl, time */
6505b261ecSmrg#include <errno.h>
6605b261ecSmrg#include <stdio.h>
6705b261ecSmrg#include <X11/X.h>
6805b261ecSmrg#include "misc.h"
6905b261ecSmrg
7005b261ecSmrg#include "osdep.h"
7105b261ecSmrg#include "dixstruct.h"
7205b261ecSmrg#include "opaque.h"
7305b261ecSmrg#ifdef DPMSExtension
7405b261ecSmrg#include "dpmsproc.h"
7505b261ecSmrg#endif
76f7df2e56Smrg#include "busfault.h"
7705b261ecSmrg
7805b261ecSmrg#ifdef WIN32
7905b261ecSmrg/* Error codes from windows sockets differ from fileio error codes  */
8005b261ecSmrg#undef EINTR
8105b261ecSmrg#define EINTR WSAEINTR
8205b261ecSmrg#undef EINVAL
8305b261ecSmrg#define EINVAL WSAEINVAL
8405b261ecSmrg#undef EBADF
8505b261ecSmrg#define EBADF WSAENOTSOCK
86f7df2e56Smrg/* Windows select does not set errno. Use GetErrno as wrapper for
8705b261ecSmrg   WSAGetLastError */
8805b261ecSmrg#define GetErrno WSAGetLastError
8905b261ecSmrg#else
9005b261ecSmrg/* This is just a fallback to errno to hide the differences between unix and
9105b261ecSmrg   Windows in the code */
9205b261ecSmrg#define GetErrno() errno
9305b261ecSmrg#endif
9405b261ecSmrg
956747b715Smrg/* like ffs, but uses fd_mask instead of int as argument, so it works
966747b715Smrg   when fd_mask is longer than an int, such as common 64-bit platforms */
9705b261ecSmrg/* modifications by raphael */
9805b261ecSmrgint
9905b261ecSmrgmffs(fd_mask mask)
10005b261ecSmrg{
10105b261ecSmrg    int i;
10205b261ecSmrg
103f7df2e56Smrg    if (!mask)
104f7df2e56Smrg        return 0;
10505b261ecSmrg    i = 1;
106f7df2e56Smrg    while (!(mask & 1)) {
107f7df2e56Smrg        i++;
108f7df2e56Smrg        mask >>= 1;
10905b261ecSmrg    }
11005b261ecSmrg    return i;
11105b261ecSmrg}
11205b261ecSmrg
11305b261ecSmrg#ifdef DPMSExtension
1146747b715Smrg#include <X11/extensions/dpmsconst.h>
11505b261ecSmrg#endif
11605b261ecSmrg
11705b261ecSmrgstruct _OsTimerRec {
118f7df2e56Smrg    OsTimerPtr next;
119f7df2e56Smrg    CARD32 expires;
120f7df2e56Smrg    CARD32 delta;
121f7df2e56Smrg    OsTimerCallback callback;
122f7df2e56Smrg    void *arg;
12305b261ecSmrg};
12405b261ecSmrg
125f7df2e56Smrgstatic void DoTimer(OsTimerPtr timer, CARD32 now, volatile OsTimerPtr *prev);
12605b261ecSmrgstatic void CheckAllTimers(void);
127f7df2e56Smrgstatic volatile OsTimerPtr timers = NULL;
12805b261ecSmrg
12905b261ecSmrg/*****************
13005b261ecSmrg * WaitForSomething:
13105b261ecSmrg *     Make the server suspend until there is
13205b261ecSmrg *	1. data from clients or
13305b261ecSmrg *	2. input events available or
13405b261ecSmrg *	3. ddx notices something of interest (graphics
13505b261ecSmrg *	   queue ready, etc.) or
13605b261ecSmrg *	4. clients that have buffered replies/events are ready
13705b261ecSmrg *
13805b261ecSmrg *     If the time between INPUT events is
13905b261ecSmrg *     greater than ScreenSaverTime, the display is turned off (or
14005b261ecSmrg *     saved, depending on the hardware).  So, WaitForSomething()
14105b261ecSmrg *     has to handle this also (that's why the select() has a timeout.
14205b261ecSmrg *     For more info on ClientsWithInput, see ReadRequestFromClient().
14305b261ecSmrg *     pClientsReady is an array to store ready client->index values into.
14405b261ecSmrg *****************/
14505b261ecSmrg
14605b261ecSmrgint
14705b261ecSmrgWaitForSomething(int *pClientsReady)
14805b261ecSmrg{
14905b261ecSmrg    int i;
15005b261ecSmrg    struct timeval waittime, *wt;
15105b261ecSmrg    INT32 timeout = 0;
15205b261ecSmrg    fd_set clientsReadable;
15305b261ecSmrg    fd_set clientsWritable;
15405b261ecSmrg    int curclient;
15505b261ecSmrg    int selecterr;
1569ace9065Smrg    static int nready;
15705b261ecSmrg    fd_set devicesReadable;
15805b261ecSmrg    CARD32 now = 0;
159f7df2e56Smrg    Bool someReady = FALSE;
16005b261ecSmrg
16105b261ecSmrg    FD_ZERO(&clientsReadable);
162f7df2e56Smrg    FD_ZERO(&clientsWritable);
16305b261ecSmrg
1649ace9065Smrg    if (nready)
1659ace9065Smrg        SmartScheduleStopTimer();
1669ace9065Smrg    nready = 0;
1679ace9065Smrg
168f7df2e56Smrg#ifdef BUSFAULT
169f7df2e56Smrg    busfault_check();
170f7df2e56Smrg#endif
171f7df2e56Smrg
172f7df2e56Smrg    /* We need a while loop here to handle
17305b261ecSmrg       crashed connections and the screen saver timeout */
174f7df2e56Smrg    while (1) {
175f7df2e56Smrg        /* deal with any blocked jobs */
176f7df2e56Smrg        if (workQueue)
177f7df2e56Smrg            ProcessWorkQueue();
178f7df2e56Smrg        if (XFD_ANYSET(&ClientsWithInput)) {
179f7df2e56Smrg            if (!SmartScheduleDisable) {
180f7df2e56Smrg                someReady = TRUE;
181f7df2e56Smrg                waittime.tv_sec = 0;
182f7df2e56Smrg                waittime.tv_usec = 0;
183f7df2e56Smrg                wt = &waittime;
184f7df2e56Smrg            }
185f7df2e56Smrg            else {
186f7df2e56Smrg                XFD_COPYSET(&ClientsWithInput, &clientsReadable);
187f7df2e56Smrg                break;
18805b261ecSmrg            }
189f7df2e56Smrg        }
190f7df2e56Smrg        if (someReady) {
191f7df2e56Smrg            XFD_COPYSET(&AllSockets, &LastSelectMask);
192f7df2e56Smrg            XFD_UNSET(&LastSelectMask, &ClientsWithInput);
193f7df2e56Smrg        }
194f7df2e56Smrg        else {
195f7df2e56Smrg            wt = NULL;
196f7df2e56Smrg            if (timers) {
197f7df2e56Smrg                now = GetTimeInMillis();
198f7df2e56Smrg                timeout = timers->expires - now;
199f7df2e56Smrg                if (timeout > 0 && timeout > timers->delta + 250) {
200f7df2e56Smrg                    /* time has rewound.  reset the timers. */
201f7df2e56Smrg                    CheckAllTimers();
202f7df2e56Smrg                }
203f7df2e56Smrg
204f7df2e56Smrg                if (timers) {
205f7df2e56Smrg                    timeout = timers->expires - now;
206f7df2e56Smrg                    if (timeout < 0)
207f7df2e56Smrg                        timeout = 0;
208f7df2e56Smrg                    waittime.tv_sec = timeout / MILLI_PER_SECOND;
209f7df2e56Smrg                    waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
210f7df2e56Smrg                        (1000000 / MILLI_PER_SECOND);
211f7df2e56Smrg                    wt = &waittime;
212f7df2e56Smrg                }
213f7df2e56Smrg            }
214f7df2e56Smrg            XFD_COPYSET(&AllSockets, &LastSelectMask);
215f7df2e56Smrg        }
21605b261ecSmrg
217f7df2e56Smrg        BlockHandler((void *) &wt, (void *) &LastSelectMask);
218f7df2e56Smrg        if (NewOutputPending)
219f7df2e56Smrg            FlushAllOutput();
220f7df2e56Smrg        /* keep this check close to select() call to minimize race */
221f7df2e56Smrg        if (dispatchException)
222f7df2e56Smrg            i = -1;
223f7df2e56Smrg        else if (AnyClientsWriteBlocked) {
224f7df2e56Smrg            XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable);
225f7df2e56Smrg            i = Select(MaxClients, &LastSelectMask, &clientsWritable, NULL, wt);
226f7df2e56Smrg        }
227f7df2e56Smrg        else {
228f7df2e56Smrg            i = Select(MaxClients, &LastSelectMask, NULL, NULL, wt);
229f7df2e56Smrg        }
230f7df2e56Smrg        selecterr = GetErrno();
231f7df2e56Smrg        WakeupHandler(i, (void *) &LastSelectMask);
232f7df2e56Smrg        if (i <= 0) {           /* An error or timeout occurred */
233f7df2e56Smrg            if (dispatchException)
234f7df2e56Smrg                return 0;
235f7df2e56Smrg            if (i < 0) {
236f7df2e56Smrg                if (selecterr == EBADF) {       /* Some client disconnected */
237f7df2e56Smrg                    CheckConnections();
238f7df2e56Smrg                    if (!XFD_ANYSET(&AllClients))
239f7df2e56Smrg                        return 0;
240f7df2e56Smrg                }
241f7df2e56Smrg                else if (selecterr == EINVAL) {
242f7df2e56Smrg                    FatalError("WaitForSomething(): select: %s\n",
243f7df2e56Smrg                               strerror(selecterr));
244f7df2e56Smrg                }
245f7df2e56Smrg                else if (selecterr != EINTR && selecterr != EAGAIN) {
246f7df2e56Smrg                    ErrorF("WaitForSomething(): select: %s\n",
247f7df2e56Smrg                           strerror(selecterr));
248f7df2e56Smrg                }
249f7df2e56Smrg            }
250f7df2e56Smrg            else if (someReady) {
251f7df2e56Smrg                /*
252f7df2e56Smrg                 * If no-one else is home, bail quickly
253f7df2e56Smrg                 */
254f7df2e56Smrg                XFD_COPYSET(&ClientsWithInput, &LastSelectMask);
255f7df2e56Smrg                XFD_COPYSET(&ClientsWithInput, &clientsReadable);
256f7df2e56Smrg                break;
25705b261ecSmrg            }
258f7df2e56Smrg            if (*checkForInput[0] != *checkForInput[1])
259f7df2e56Smrg                return 0;
260f7df2e56Smrg
261f7df2e56Smrg            if (timers) {
26205b261ecSmrg                int expired = 0;
26305b261ecSmrg
264f7df2e56Smrg                now = GetTimeInMillis();
265f7df2e56Smrg                if ((int) (timers->expires - now) <= 0)
266f7df2e56Smrg                    expired = 1;
267f7df2e56Smrg
268f7df2e56Smrg                if (expired) {
269f7df2e56Smrg                    OsBlockSignals();
270f7df2e56Smrg                    while (timers && (int) (timers->expires - now) <= 0)
271f7df2e56Smrg                        DoTimer(timers, now, &timers);
272f7df2e56Smrg                    OsReleaseSignals();
27305b261ecSmrg
27405b261ecSmrg                    return 0;
275f7df2e56Smrg                }
276f7df2e56Smrg            }
277f7df2e56Smrg        }
278f7df2e56Smrg        else {
279f7df2e56Smrg            fd_set tmp_set;
280f7df2e56Smrg
281f7df2e56Smrg            if (*checkForInput[0] == *checkForInput[1]) {
282f7df2e56Smrg                if (timers) {
28305b261ecSmrg                    int expired = 0;
28405b261ecSmrg
285f7df2e56Smrg                    now = GetTimeInMillis();
286f7df2e56Smrg                    if ((int) (timers->expires - now) <= 0)
287f7df2e56Smrg                        expired = 1;
288f7df2e56Smrg
289f7df2e56Smrg                    if (expired) {
290f7df2e56Smrg                        OsBlockSignals();
291f7df2e56Smrg                        while (timers && (int) (timers->expires - now) <= 0)
292f7df2e56Smrg                            DoTimer(timers, now, &timers);
293f7df2e56Smrg                        OsReleaseSignals();
29405b261ecSmrg
29505b261ecSmrg                        return 0;
296f7df2e56Smrg                    }
297f7df2e56Smrg                }
298f7df2e56Smrg            }
299f7df2e56Smrg            if (someReady)
300f7df2e56Smrg                XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask);
301f7df2e56Smrg            if (AnyClientsWriteBlocked && XFD_ANYSET(&clientsWritable)) {
302f7df2e56Smrg                NewOutputPending = TRUE;
303f7df2e56Smrg                XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
304f7df2e56Smrg                XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
305f7df2e56Smrg                if (!XFD_ANYSET(&ClientsWriteBlocked))
306f7df2e56Smrg                    AnyClientsWriteBlocked = FALSE;
307f7df2e56Smrg            }
308f7df2e56Smrg
309f7df2e56Smrg            XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices);
310f7df2e56Smrg            XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
311f7df2e56Smrg            XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections);
312f7df2e56Smrg            if (XFD_ANYSET(&tmp_set))
313f7df2e56Smrg                QueueWorkProc(EstablishNewConnections, NULL,
314f7df2e56Smrg                              (void *) &LastSelectMask);
315f7df2e56Smrg
316f7df2e56Smrg            if (XFD_ANYSET(&devicesReadable) || XFD_ANYSET(&clientsReadable))
317f7df2e56Smrg                break;
318f7df2e56Smrg            /* check here for DDXes that queue events during Block/Wakeup */
319f7df2e56Smrg            if (*checkForInput[0] != *checkForInput[1])
320f7df2e56Smrg                return 0;
321f7df2e56Smrg        }
32205b261ecSmrg    }
32305b261ecSmrg
32405b261ecSmrg    nready = 0;
325f7df2e56Smrg    if (XFD_ANYSET(&clientsReadable)) {
32605b261ecSmrg#ifndef WIN32
327f7df2e56Smrg        for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
328f7df2e56Smrg            int highest_priority = 0;
32905b261ecSmrg
330f7df2e56Smrg            while (clientsReadable.fds_bits[i]) {
331f7df2e56Smrg                int client_priority, client_index;
33205b261ecSmrg
333f7df2e56Smrg                curclient = mffs(clientsReadable.fds_bits[i]) - 1;
334f7df2e56Smrg                client_index =  /* raphael: modified */
335f7df2e56Smrg                    ConnectionTranslation[curclient +
336f7df2e56Smrg                                          (i * (sizeof(fd_mask) * 8))];
33705b261ecSmrg#else
338f7df2e56Smrg        int highest_priority = 0;
339f7df2e56Smrg        fd_set savedClientsReadable;
340f7df2e56Smrg
341f7df2e56Smrg        XFD_COPYSET(&clientsReadable, &savedClientsReadable);
342f7df2e56Smrg        for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++) {
343f7df2e56Smrg            int client_priority, client_index;
344f7df2e56Smrg
345f7df2e56Smrg            curclient = XFD_FD(&savedClientsReadable, i);
346f7df2e56Smrg            client_index = GetConnectionTranslation(curclient);
34705b261ecSmrg#endif
348f7df2e56Smrg            /*  We implement "strict" priorities.
349f7df2e56Smrg             *  Only the highest priority client is returned to
350f7df2e56Smrg             *  dix.  If multiple clients at the same priority are
351f7df2e56Smrg             *  ready, they are all returned.  This means that an
352f7df2e56Smrg             *  aggressive client could take over the server.
353f7df2e56Smrg             *  This was not considered a big problem because
354f7df2e56Smrg             *  aggressive clients can hose the server in so many
355f7df2e56Smrg             *  other ways :)
356f7df2e56Smrg             */
357f7df2e56Smrg            client_priority = clients[client_index]->priority;
358f7df2e56Smrg            if (nready == 0 || client_priority > highest_priority) {
359f7df2e56Smrg                /*  Either we found the first client, or we found
360f7df2e56Smrg                 *  a client whose priority is greater than all others
361f7df2e56Smrg                 *  that have been found so far.  Either way, we want
362f7df2e56Smrg                 *  to initialize the list of clients to contain just
363f7df2e56Smrg                 *  this client.
364f7df2e56Smrg                 */
365f7df2e56Smrg                pClientsReady[0] = client_index;
366f7df2e56Smrg                highest_priority = client_priority;
367f7df2e56Smrg                nready = 1;
368f7df2e56Smrg            }
369f7df2e56Smrg            /*  the following if makes sure that multiple same-priority
370f7df2e56Smrg             *  clients get batched together
371f7df2e56Smrg             */
372f7df2e56Smrg            else if (client_priority == highest_priority) {
373f7df2e56Smrg                pClientsReady[nready++] = client_index;
374f7df2e56Smrg            }
37505b261ecSmrg#ifndef WIN32
376f7df2e56Smrg            clientsReadable.fds_bits[i] &= ~(((fd_mask) 1L) << curclient);
377f7df2e56Smrg        }
37805b261ecSmrg#else
379f7df2e56Smrg            FD_CLR(curclient, &clientsReadable);
38005b261ecSmrg#endif
381f7df2e56Smrg        }
38205b261ecSmrg    }
3839ace9065Smrg
3849ace9065Smrg    if (nready)
3859ace9065Smrg        SmartScheduleStartTimer();
3869ace9065Smrg
38705b261ecSmrg    return nready;
38805b261ecSmrg}
38905b261ecSmrg
39005b261ecSmrg/* If time has rewound, re-run every affected timer.
39105b261ecSmrg * Timers might drop out of the list, so we have to restart every time. */
39205b261ecSmrgstatic void
39305b261ecSmrgCheckAllTimers(void)
39405b261ecSmrg{
39505b261ecSmrg    OsTimerPtr timer;
39605b261ecSmrg    CARD32 now;
39705b261ecSmrg
398f7df2e56Smrg    OsBlockSignals();
399f7df2e56Smrg start:
40005b261ecSmrg    now = GetTimeInMillis();
40105b261ecSmrg
40205b261ecSmrg    for (timer = timers; timer; timer = timer->next) {
40305b261ecSmrg        if (timer->expires - now > timer->delta + 250) {
40405b261ecSmrg            TimerForce(timer);
40505b261ecSmrg            goto start;
40605b261ecSmrg        }
40705b261ecSmrg    }
408f7df2e56Smrg    OsReleaseSignals();
40905b261ecSmrg}
41005b261ecSmrg
41105b261ecSmrgstatic void
412f7df2e56SmrgDoTimer(OsTimerPtr timer, CARD32 now, volatile OsTimerPtr *prev)
41305b261ecSmrg{
41405b261ecSmrg    CARD32 newTime;
41505b261ecSmrg
416f7df2e56Smrg    OsBlockSignals();
41705b261ecSmrg    *prev = timer->next;
41805b261ecSmrg    timer->next = NULL;
419f7df2e56Smrg    OsReleaseSignals();
420f7df2e56Smrg
421f7df2e56Smrg    newTime = (*timer->callback) (timer, now, timer->arg);
42205b261ecSmrg    if (newTime)
423f7df2e56Smrg        TimerSet(timer, 0, newTime, timer->callback, timer->arg);
42405b261ecSmrg}
42505b261ecSmrg
4266747b715SmrgOsTimerPtr
427f7df2e56SmrgTimerSet(OsTimerPtr timer, int flags, CARD32 millis,
428f7df2e56Smrg         OsTimerCallback func, void *arg)
42905b261ecSmrg{
430f7df2e56Smrg    volatile OsTimerPtr *prev;
43105b261ecSmrg    CARD32 now = GetTimeInMillis();
43205b261ecSmrg
433f7df2e56Smrg    if (!timer) {
434f7df2e56Smrg        timer = malloc(sizeof(struct _OsTimerRec));
435f7df2e56Smrg        if (!timer)
436f7df2e56Smrg            return NULL;
43705b261ecSmrg    }
438f7df2e56Smrg    else {
439f7df2e56Smrg        OsBlockSignals();
440f7df2e56Smrg        for (prev = &timers; *prev; prev = &(*prev)->next) {
441f7df2e56Smrg            if (*prev == timer) {
442f7df2e56Smrg                *prev = timer->next;
443f7df2e56Smrg                if (flags & TimerForceOld)
444f7df2e56Smrg                    (void) (*timer->callback) (timer, now, timer->arg);
445f7df2e56Smrg                break;
446f7df2e56Smrg            }
447f7df2e56Smrg        }
448f7df2e56Smrg        OsReleaseSignals();
44905b261ecSmrg    }
45005b261ecSmrg    if (!millis)
451f7df2e56Smrg        return timer;
45205b261ecSmrg    if (flags & TimerAbsolute) {
45305b261ecSmrg        timer->delta = millis - now;
45405b261ecSmrg    }
45505b261ecSmrg    else {
45605b261ecSmrg        timer->delta = millis;
457f7df2e56Smrg        millis += now;
45805b261ecSmrg    }
45905b261ecSmrg    timer->expires = millis;
46005b261ecSmrg    timer->callback = func;
46105b261ecSmrg    timer->arg = arg;
462f7df2e56Smrg    if ((int) (millis - now) <= 0) {
463f7df2e56Smrg        timer->next = NULL;
464f7df2e56Smrg        millis = (*timer->callback) (timer, now, timer->arg);
465f7df2e56Smrg        if (!millis)
466f7df2e56Smrg            return timer;
46705b261ecSmrg    }
468f7df2e56Smrg    OsBlockSignals();
46905b261ecSmrg    for (prev = &timers;
470f7df2e56Smrg         *prev && (int) ((*prev)->expires - millis) <= 0;
471f7df2e56Smrg         prev = &(*prev)->next);
47205b261ecSmrg    timer->next = *prev;
47305b261ecSmrg    *prev = timer;
474f7df2e56Smrg    OsReleaseSignals();
47505b261ecSmrg    return timer;
47605b261ecSmrg}
47705b261ecSmrg
47805b261ecSmrgBool
47905b261ecSmrgTimerForce(OsTimerPtr timer)
48005b261ecSmrg{
481f7df2e56Smrg    int rc = FALSE;
482f7df2e56Smrg    volatile OsTimerPtr *prev;
483f7df2e56Smrg
484f7df2e56Smrg    OsBlockSignals();
485f7df2e56Smrg    for (prev = &timers; *prev; prev = &(*prev)->next) {
486f7df2e56Smrg        if (*prev == timer) {
487f7df2e56Smrg            DoTimer(timer, GetTimeInMillis(), prev);
488f7df2e56Smrg            rc = TRUE;
489f7df2e56Smrg            break;
490f7df2e56Smrg        }
49105b261ecSmrg    }
492f7df2e56Smrg    OsReleaseSignals();
493f7df2e56Smrg    return rc;
49405b261ecSmrg}
49505b261ecSmrg
4966747b715Smrgvoid
49705b261ecSmrgTimerCancel(OsTimerPtr timer)
49805b261ecSmrg{
499f7df2e56Smrg    volatile OsTimerPtr *prev;
50005b261ecSmrg
50105b261ecSmrg    if (!timer)
502f7df2e56Smrg        return;
503f7df2e56Smrg    OsBlockSignals();
504f7df2e56Smrg    for (prev = &timers; *prev; prev = &(*prev)->next) {
505f7df2e56Smrg        if (*prev == timer) {
506f7df2e56Smrg            *prev = timer->next;
507f7df2e56Smrg            break;
508f7df2e56Smrg        }
50905b261ecSmrg    }
510f7df2e56Smrg    OsReleaseSignals();
51105b261ecSmrg}
51205b261ecSmrg
5136747b715Smrgvoid
51405b261ecSmrgTimerFree(OsTimerPtr timer)
51505b261ecSmrg{
51605b261ecSmrg    if (!timer)
517f7df2e56Smrg        return;
51805b261ecSmrg    TimerCancel(timer);
5196747b715Smrg    free(timer);
52005b261ecSmrg}
52105b261ecSmrg
52205b261ecSmrgvoid
52305b261ecSmrgTimerCheck(void)
52405b261ecSmrg{
52505b261ecSmrg    CARD32 now = GetTimeInMillis();
52605b261ecSmrg
527f7df2e56Smrg    if (timers && (int) (timers->expires - now) <= 0) {
528f7df2e56Smrg        OsBlockSignals();
529f7df2e56Smrg        while (timers && (int) (timers->expires - now) <= 0)
530f7df2e56Smrg            DoTimer(timers, now, &timers);
531f7df2e56Smrg        OsReleaseSignals();
532f7df2e56Smrg    }
53305b261ecSmrg}
53405b261ecSmrg
53505b261ecSmrgvoid
53605b261ecSmrgTimerInit(void)
53705b261ecSmrg{
53805b261ecSmrg    OsTimerPtr timer;
53905b261ecSmrg
540f7df2e56Smrg    while ((timer = timers)) {
541f7df2e56Smrg        timers = timer->next;
542f7df2e56Smrg        free(timer);
54305b261ecSmrg    }
54405b261ecSmrg}
54505b261ecSmrg
54605b261ecSmrg#ifdef DPMSExtension
54705b261ecSmrg
54805b261ecSmrg#define DPMS_CHECK_MODE(mode,time)\
54905b261ecSmrg    if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\
5504642e01fSmrg	DPMSSet(serverClient, mode);
55105b261ecSmrg
55205b261ecSmrg#define DPMS_CHECK_TIMEOUT(time)\
55305b261ecSmrg    if (time > 0 && (time - timeout) > 0)\
55405b261ecSmrg	return time - timeout;
55505b261ecSmrg
55605b261ecSmrgstatic CARD32
55705b261ecSmrgNextDPMSTimeout(INT32 timeout)
55805b261ecSmrg{
55905b261ecSmrg    /*
56005b261ecSmrg     * Return the amount of time remaining until we should set
56105b261ecSmrg     * the next power level. Fallthroughs are intentional.
56205b261ecSmrg     */
563f7df2e56Smrg    switch (DPMSPowerLevel) {
564f7df2e56Smrg    case DPMSModeOn:
565f7df2e56Smrg        DPMS_CHECK_TIMEOUT(DPMSStandbyTime)
56605b261ecSmrg
567f7df2e56Smrg    case DPMSModeStandby:
568f7df2e56Smrg        DPMS_CHECK_TIMEOUT(DPMSSuspendTime)
56905b261ecSmrg
570f7df2e56Smrg    case DPMSModeSuspend:
571f7df2e56Smrg        DPMS_CHECK_TIMEOUT(DPMSOffTime)
57205b261ecSmrg
573f7df2e56Smrg    default:                   /* DPMSModeOff */
574f7df2e56Smrg        return 0;
57505b261ecSmrg    }
57605b261ecSmrg}
577f7df2e56Smrg#endif                          /* DPMSExtension */
57805b261ecSmrg
57905b261ecSmrgstatic CARD32
580f7df2e56SmrgScreenSaverTimeoutExpire(OsTimerPtr timer, CARD32 now, void *arg)
58105b261ecSmrg{
582f7df2e56Smrg    INT32 timeout = now - LastEventTime(XIAllDevices).milliseconds;
58305b261ecSmrg    CARD32 nextTimeout = 0;
58405b261ecSmrg
58505b261ecSmrg#ifdef DPMSExtension
58605b261ecSmrg    /*
58705b261ecSmrg     * Check each mode lowest to highest, since a lower mode can
58805b261ecSmrg     * have the same timeout as a higher one.
58905b261ecSmrg     */
590f7df2e56Smrg    if (DPMSEnabled) {
591f7df2e56Smrg        DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime)
592f7df2e56Smrg            DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime)
593f7df2e56Smrg            DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime)
59405b261ecSmrg
595f7df2e56Smrg            nextTimeout = NextDPMSTimeout(timeout);
59605b261ecSmrg    }
59705b261ecSmrg
59805b261ecSmrg    /*
59905b261ecSmrg     * Only do the screensaver checks if we're not in a DPMS
60005b261ecSmrg     * power saving mode
60105b261ecSmrg     */
60205b261ecSmrg    if (DPMSPowerLevel != DPMSModeOn)
603f7df2e56Smrg        return nextTimeout;
604f7df2e56Smrg#endif                          /* DPMSExtension */
60505b261ecSmrg
60605b261ecSmrg    if (!ScreenSaverTime)
607f7df2e56Smrg        return nextTimeout;
60805b261ecSmrg
609f7df2e56Smrg    if (timeout < ScreenSaverTime) {
610f7df2e56Smrg        return nextTimeout > 0 ?
611f7df2e56Smrg            min(ScreenSaverTime - timeout, nextTimeout) :
612f7df2e56Smrg            ScreenSaverTime - timeout;
61305b261ecSmrg    }
61405b261ecSmrg
615f7df2e56Smrg    ResetOsBuffers();           /* not ideal, but better than nothing */
6164642e01fSmrg    dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive);
61705b261ecSmrg
618f7df2e56Smrg    if (ScreenSaverInterval > 0) {
619f7df2e56Smrg        nextTimeout = nextTimeout > 0 ?
620f7df2e56Smrg            min(ScreenSaverInterval, nextTimeout) : ScreenSaverInterval;
62105b261ecSmrg    }
62205b261ecSmrg
62305b261ecSmrg    return nextTimeout;
62405b261ecSmrg}
62505b261ecSmrg
62605b261ecSmrgstatic OsTimerPtr ScreenSaverTimer = NULL;
62705b261ecSmrg
62805b261ecSmrgvoid
62905b261ecSmrgFreeScreenSaverTimer(void)
63005b261ecSmrg{
63105b261ecSmrg    if (ScreenSaverTimer) {
632f7df2e56Smrg        TimerFree(ScreenSaverTimer);
633f7df2e56Smrg        ScreenSaverTimer = NULL;
63405b261ecSmrg    }
63505b261ecSmrg}
63605b261ecSmrg
63705b261ecSmrgvoid
63805b261ecSmrgSetScreenSaverTimer(void)
63905b261ecSmrg{
64005b261ecSmrg    CARD32 timeout = 0;
64105b261ecSmrg
64205b261ecSmrg#ifdef DPMSExtension
643f7df2e56Smrg    if (DPMSEnabled) {
644f7df2e56Smrg        /*
645f7df2e56Smrg         * A higher DPMS level has a timeout that's either less
646f7df2e56Smrg         * than or equal to that of a lower DPMS level.
647f7df2e56Smrg         */
648f7df2e56Smrg        if (DPMSStandbyTime > 0)
649f7df2e56Smrg            timeout = DPMSStandbyTime;
650f7df2e56Smrg
651f7df2e56Smrg        else if (DPMSSuspendTime > 0)
652f7df2e56Smrg            timeout = DPMSSuspendTime;
653f7df2e56Smrg
654f7df2e56Smrg        else if (DPMSOffTime > 0)
655f7df2e56Smrg            timeout = DPMSOffTime;
65605b261ecSmrg    }
65705b261ecSmrg#endif
65805b261ecSmrg
659f7df2e56Smrg    if (ScreenSaverTime > 0) {
660f7df2e56Smrg        timeout = timeout > 0 ? min(ScreenSaverTime, timeout) : ScreenSaverTime;
66105b261ecSmrg    }
66205b261ecSmrg
66305b261ecSmrg#ifdef SCREENSAVER
66405b261ecSmrg    if (timeout && !screenSaverSuspended) {
66505b261ecSmrg#else
66605b261ecSmrg    if (timeout) {
66705b261ecSmrg#endif
668f7df2e56Smrg        ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout,
669f7df2e56Smrg                                    ScreenSaverTimeoutExpire, NULL);
67005b261ecSmrg    }
67105b261ecSmrg    else if (ScreenSaverTimer) {
672f7df2e56Smrg        FreeScreenSaverTimer();
67305b261ecSmrg    }
67405b261ecSmrg}
675