WaitFor.c revision 6747b715
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
2505b261ecSmrg
2605b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2705b261ecSmrg
2805b261ecSmrg                        All Rights Reserved
2905b261ecSmrg
3005b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3105b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3205b261ecSmrgprovided that the above copyright notice appear in all copies and that
3305b261ecSmrgboth that copyright notice and this permission notice appear in
3405b261ecSmrgsupporting documentation, and that the name of Digital not be
3505b261ecSmrgused in advertising or publicity pertaining to distribution of the
3605b261ecSmrgsoftware without specific, written prior permission.
3705b261ecSmrg
3805b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3905b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
4005b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4105b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4205b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4305b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4405b261ecSmrgSOFTWARE.
4505b261ecSmrg
4605b261ecSmrg******************************************************************/
4705b261ecSmrg
4805b261ecSmrg
4905b261ecSmrg/*****************************************************************
5005b261ecSmrg * OS Dependent input routines:
5105b261ecSmrg *
5205b261ecSmrg *  WaitForSomething
5305b261ecSmrg *  TimerForce, TimerSet, TimerCheck, TimerFree
5405b261ecSmrg *
5505b261ecSmrg *****************************************************************/
5605b261ecSmrg
5705b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5805b261ecSmrg#include <dix-config.h>
5905b261ecSmrg#endif
6005b261ecSmrg
6105b261ecSmrg#ifdef WIN32
6205b261ecSmrg#include <X11/Xwinsock.h>
6305b261ecSmrg#endif
6405b261ecSmrg#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 <X11/Xpoll.h>
7205b261ecSmrg#include "dixstruct.h"
7305b261ecSmrg#include "opaque.h"
7405b261ecSmrg#ifdef DPMSExtension
7505b261ecSmrg#include "dpmsproc.h"
7605b261ecSmrg#endif
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
8605b261ecSmrg/* 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
10305b261ecSmrg    if (!mask) return 0;
10405b261ecSmrg    i = 1;
10505b261ecSmrg    while (!(mask & 1))
10605b261ecSmrg    {
10705b261ecSmrg	i++;
10805b261ecSmrg	mask >>= 1;
10905b261ecSmrg    }
11005b261ecSmrg    return i;
11105b261ecSmrg}
11205b261ecSmrg
11305b261ecSmrg#ifdef DPMSExtension
1146747b715Smrg#include <X11/extensions/dpmsconst.h>
11505b261ecSmrg#endif
11605b261ecSmrg
11705b261ecSmrgstruct _OsTimerRec {
11805b261ecSmrg    OsTimerPtr		next;
11905b261ecSmrg    CARD32		expires;
12005b261ecSmrg    CARD32              delta;
12105b261ecSmrg    OsTimerCallback	callback;
12205b261ecSmrg    pointer		arg;
12305b261ecSmrg};
12405b261ecSmrg
12505b261ecSmrgstatic void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev);
12605b261ecSmrgstatic void CheckAllTimers(void);
12705b261ecSmrgstatic 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;
15605b261ecSmrg    int nready;
15705b261ecSmrg    fd_set devicesReadable;
15805b261ecSmrg    CARD32 now = 0;
15905b261ecSmrg    Bool    someReady = FALSE;
16005b261ecSmrg
16105b261ecSmrg    FD_ZERO(&clientsReadable);
16205b261ecSmrg
16305b261ecSmrg    /* We need a while loop here to handle
16405b261ecSmrg       crashed connections and the screen saver timeout */
16505b261ecSmrg    while (1)
16605b261ecSmrg    {
16705b261ecSmrg	/* deal with any blocked jobs */
16805b261ecSmrg	if (workQueue)
16905b261ecSmrg	    ProcessWorkQueue();
17005b261ecSmrg	if (XFD_ANYSET (&ClientsWithInput))
17105b261ecSmrg	{
17205b261ecSmrg	    if (!SmartScheduleDisable)
17305b261ecSmrg	    {
17405b261ecSmrg		someReady = TRUE;
17505b261ecSmrg		waittime.tv_sec = 0;
17605b261ecSmrg		waittime.tv_usec = 0;
17705b261ecSmrg		wt = &waittime;
17805b261ecSmrg	    }
17905b261ecSmrg	    else
18005b261ecSmrg	    {
18105b261ecSmrg		XFD_COPYSET (&ClientsWithInput, &clientsReadable);
18205b261ecSmrg		break;
18305b261ecSmrg	    }
18405b261ecSmrg	}
18505b261ecSmrg	if (someReady)
18605b261ecSmrg	{
18705b261ecSmrg	    XFD_COPYSET(&AllSockets, &LastSelectMask);
18805b261ecSmrg	    XFD_UNSET(&LastSelectMask, &ClientsWithInput);
18905b261ecSmrg	}
19005b261ecSmrg	else
19105b261ecSmrg	{
19205b261ecSmrg        wt = NULL;
19305b261ecSmrg	if (timers)
19405b261ecSmrg        {
19505b261ecSmrg            now = GetTimeInMillis();
19605b261ecSmrg	    timeout = timers->expires - now;
19705b261ecSmrg            if (timeout > 0 && timeout > timers->delta + 250) {
19805b261ecSmrg                /* time has rewound.  reset the timers. */
19905b261ecSmrg                CheckAllTimers();
20005b261ecSmrg            }
20105b261ecSmrg
20205b261ecSmrg	    if (timers) {
20305b261ecSmrg		timeout = timers->expires - now;
20405b261ecSmrg		if (timeout < 0)
20505b261ecSmrg		    timeout = 0;
20605b261ecSmrg		waittime.tv_sec = timeout / MILLI_PER_SECOND;
20705b261ecSmrg		waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
20805b261ecSmrg				   (1000000 / MILLI_PER_SECOND);
20905b261ecSmrg		wt = &waittime;
21005b261ecSmrg	    }
21105b261ecSmrg	}
21205b261ecSmrg	XFD_COPYSET(&AllSockets, &LastSelectMask);
21305b261ecSmrg	}
2144642e01fSmrg	SmartScheduleStopTimer ();
2154642e01fSmrg
21605b261ecSmrg	BlockHandler((pointer)&wt, (pointer)&LastSelectMask);
21705b261ecSmrg	if (NewOutputPending)
21805b261ecSmrg	    FlushAllOutput();
21905b261ecSmrg	/* keep this check close to select() call to minimize race */
22005b261ecSmrg	if (dispatchException)
22105b261ecSmrg	    i = -1;
22205b261ecSmrg	else if (AnyClientsWriteBlocked)
22305b261ecSmrg	{
22405b261ecSmrg	    XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable);
22505b261ecSmrg	    i = Select (MaxClients, &LastSelectMask, &clientsWritable, NULL, wt);
22605b261ecSmrg	}
22705b261ecSmrg	else
22805b261ecSmrg	{
22905b261ecSmrg	    i = Select (MaxClients, &LastSelectMask, NULL, NULL, wt);
23005b261ecSmrg	}
23105b261ecSmrg	selecterr = GetErrno();
23205b261ecSmrg	WakeupHandler(i, (pointer)&LastSelectMask);
2334642e01fSmrg	SmartScheduleStartTimer ();
23405b261ecSmrg	if (i <= 0) /* An error or timeout occurred */
23505b261ecSmrg	{
23605b261ecSmrg	    if (dispatchException)
23705b261ecSmrg		return 0;
23805b261ecSmrg	    if (i < 0)
23905b261ecSmrg	    {
24005b261ecSmrg		if (selecterr == EBADF)    /* Some client disconnected */
24105b261ecSmrg		{
24205b261ecSmrg		    CheckConnections ();
24305b261ecSmrg		    if (! XFD_ANYSET (&AllClients))
24405b261ecSmrg			return 0;
24505b261ecSmrg		}
24605b261ecSmrg		else if (selecterr == EINVAL)
24705b261ecSmrg		{
2484642e01fSmrg		    FatalError("WaitForSomething(): select: %s\n",
2494642e01fSmrg			strerror(selecterr));
25005b261ecSmrg            }
25105b261ecSmrg		else if (selecterr != EINTR && selecterr != EAGAIN)
25205b261ecSmrg		{
2534642e01fSmrg		    ErrorF("WaitForSomething(): select: %s\n",
2544642e01fSmrg			strerror(selecterr));
25505b261ecSmrg		}
25605b261ecSmrg	    }
25705b261ecSmrg	    else if (someReady)
25805b261ecSmrg	    {
25905b261ecSmrg		/*
26005b261ecSmrg		 * If no-one else is home, bail quickly
26105b261ecSmrg		 */
26205b261ecSmrg		XFD_COPYSET(&ClientsWithInput, &LastSelectMask);
26305b261ecSmrg		XFD_COPYSET(&ClientsWithInput, &clientsReadable);
26405b261ecSmrg		break;
26505b261ecSmrg	    }
26605b261ecSmrg	    if (*checkForInput[0] != *checkForInput[1])
26705b261ecSmrg		return 0;
26805b261ecSmrg
26905b261ecSmrg	    if (timers)
27005b261ecSmrg	    {
27105b261ecSmrg                int expired = 0;
27205b261ecSmrg		now = GetTimeInMillis();
27305b261ecSmrg		if ((int) (timers->expires - now) <= 0)
27405b261ecSmrg		    expired = 1;
27505b261ecSmrg
27605b261ecSmrg		while (timers && (int) (timers->expires - now) <= 0)
27705b261ecSmrg		    DoTimer(timers, now, &timers);
27805b261ecSmrg
27905b261ecSmrg                if (expired)
28005b261ecSmrg                    return 0;
28105b261ecSmrg	    }
28205b261ecSmrg	}
28305b261ecSmrg	else
28405b261ecSmrg	{
28505b261ecSmrg	    fd_set tmp_set;
28605b261ecSmrg
28705b261ecSmrg	    if (*checkForInput[0] == *checkForInput[1]) {
28805b261ecSmrg	        if (timers)
28905b261ecSmrg	        {
29005b261ecSmrg                    int expired = 0;
29105b261ecSmrg		    now = GetTimeInMillis();
29205b261ecSmrg		    if ((int) (timers->expires - now) <= 0)
29305b261ecSmrg		        expired = 1;
29405b261ecSmrg
29505b261ecSmrg		    while (timers && (int) (timers->expires - now) <= 0)
29605b261ecSmrg		        DoTimer(timers, now, &timers);
29705b261ecSmrg
29805b261ecSmrg                    if (expired)
29905b261ecSmrg                        return 0;
30005b261ecSmrg	        }
30105b261ecSmrg	    }
30205b261ecSmrg	    if (someReady)
30305b261ecSmrg		XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask);
30405b261ecSmrg	    if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable))
30505b261ecSmrg	    {
30605b261ecSmrg		NewOutputPending = TRUE;
30705b261ecSmrg		XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
30805b261ecSmrg		XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
30905b261ecSmrg		if (! XFD_ANYSET(&ClientsWriteBlocked))
31005b261ecSmrg		    AnyClientsWriteBlocked = FALSE;
31105b261ecSmrg	    }
31205b261ecSmrg
31305b261ecSmrg	    XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices);
31405b261ecSmrg	    XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
31505b261ecSmrg	    XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections);
31605b261ecSmrg	    if (XFD_ANYSET(&tmp_set))
31705b261ecSmrg		QueueWorkProc(EstablishNewConnections, NULL,
31805b261ecSmrg			      (pointer)&LastSelectMask);
31905b261ecSmrg
32005b261ecSmrg	    if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable))
32105b261ecSmrg		break;
3224642e01fSmrg	    /* check here for DDXes that queue events during Block/Wakeup */
32305b261ecSmrg	    if (*checkForInput[0] != *checkForInput[1])
32405b261ecSmrg		return 0;
32505b261ecSmrg	}
32605b261ecSmrg    }
32705b261ecSmrg
32805b261ecSmrg    nready = 0;
32905b261ecSmrg    if (XFD_ANYSET (&clientsReadable))
33005b261ecSmrg    {
33105b261ecSmrg#ifndef WIN32
33205b261ecSmrg	for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++)
33305b261ecSmrg	{
33405b261ecSmrg	    int highest_priority = 0;
33505b261ecSmrg
33605b261ecSmrg	    while (clientsReadable.fds_bits[i])
33705b261ecSmrg	    {
33805b261ecSmrg	        int client_priority, client_index;
33905b261ecSmrg
3406747b715Smrg		curclient = mffs (clientsReadable.fds_bits[i]) - 1;
34105b261ecSmrg		client_index = /* raphael: modified */
34205b261ecSmrg			ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))];
34305b261ecSmrg#else
34405b261ecSmrg	int highest_priority = 0;
34505b261ecSmrg	fd_set savedClientsReadable;
34605b261ecSmrg	XFD_COPYSET(&clientsReadable, &savedClientsReadable);
34705b261ecSmrg	for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++)
34805b261ecSmrg	{
34905b261ecSmrg	    int client_priority, client_index;
35005b261ecSmrg
35105b261ecSmrg	    curclient = XFD_FD(&savedClientsReadable, i);
35205b261ecSmrg	    client_index = GetConnectionTranslation(curclient);
35305b261ecSmrg#endif
35405b261ecSmrg		/*  We implement "strict" priorities.
35505b261ecSmrg		 *  Only the highest priority client is returned to
35605b261ecSmrg		 *  dix.  If multiple clients at the same priority are
35705b261ecSmrg		 *  ready, they are all returned.  This means that an
35805b261ecSmrg		 *  aggressive client could take over the server.
35905b261ecSmrg		 *  This was not considered a big problem because
36005b261ecSmrg		 *  aggressive clients can hose the server in so many
36105b261ecSmrg		 *  other ways :)
36205b261ecSmrg		 */
36305b261ecSmrg		client_priority = clients[client_index]->priority;
36405b261ecSmrg		if (nready == 0 || client_priority > highest_priority)
36505b261ecSmrg		{
36605b261ecSmrg		    /*  Either we found the first client, or we found
36705b261ecSmrg		     *  a client whose priority is greater than all others
36805b261ecSmrg		     *  that have been found so far.  Either way, we want
36905b261ecSmrg		     *  to initialize the list of clients to contain just
37005b261ecSmrg		     *  this client.
37105b261ecSmrg		     */
37205b261ecSmrg		    pClientsReady[0] = client_index;
37305b261ecSmrg		    highest_priority = client_priority;
37405b261ecSmrg		    nready = 1;
37505b261ecSmrg		}
37605b261ecSmrg		/*  the following if makes sure that multiple same-priority
37705b261ecSmrg		 *  clients get batched together
37805b261ecSmrg		 */
37905b261ecSmrg		else if (client_priority == highest_priority)
38005b261ecSmrg		{
38105b261ecSmrg		    pClientsReady[nready++] = client_index;
38205b261ecSmrg		}
38305b261ecSmrg#ifndef WIN32
38405b261ecSmrg		clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient);
38505b261ecSmrg	    }
38605b261ecSmrg#else
38705b261ecSmrg	    FD_CLR(curclient, &clientsReadable);
38805b261ecSmrg#endif
38905b261ecSmrg	}
39005b261ecSmrg    }
39105b261ecSmrg    return nready;
39205b261ecSmrg}
39305b261ecSmrg
39405b261ecSmrg/* If time has rewound, re-run every affected timer.
39505b261ecSmrg * Timers might drop out of the list, so we have to restart every time. */
39605b261ecSmrgstatic void
39705b261ecSmrgCheckAllTimers(void)
39805b261ecSmrg{
39905b261ecSmrg    OsTimerPtr timer;
40005b261ecSmrg    CARD32 now;
40105b261ecSmrg
40205b261ecSmrgstart:
40305b261ecSmrg    now = GetTimeInMillis();
40405b261ecSmrg
40505b261ecSmrg    for (timer = timers; timer; timer = timer->next) {
40605b261ecSmrg        if (timer->expires - now > timer->delta + 250) {
40705b261ecSmrg            TimerForce(timer);
40805b261ecSmrg            goto start;
40905b261ecSmrg        }
41005b261ecSmrg    }
41105b261ecSmrg}
41205b261ecSmrg
41305b261ecSmrgstatic void
41405b261ecSmrgDoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev)
41505b261ecSmrg{
41605b261ecSmrg    CARD32 newTime;
41705b261ecSmrg
41805b261ecSmrg    *prev = timer->next;
41905b261ecSmrg    timer->next = NULL;
42005b261ecSmrg    newTime = (*timer->callback)(timer, now, timer->arg);
42105b261ecSmrg    if (newTime)
42205b261ecSmrg	TimerSet(timer, 0, newTime, timer->callback, timer->arg);
42305b261ecSmrg}
42405b261ecSmrg
4256747b715SmrgOsTimerPtr
42605b261ecSmrgTimerSet(OsTimerPtr timer, int flags, CARD32 millis,
42705b261ecSmrg    OsTimerCallback func, pointer arg)
42805b261ecSmrg{
42905b261ecSmrg    register OsTimerPtr *prev;
43005b261ecSmrg    CARD32 now = GetTimeInMillis();
43105b261ecSmrg
43205b261ecSmrg    if (!timer)
43305b261ecSmrg    {
4346747b715Smrg	timer = malloc(sizeof(struct _OsTimerRec));
43505b261ecSmrg	if (!timer)
43605b261ecSmrg	    return NULL;
43705b261ecSmrg    }
43805b261ecSmrg    else
43905b261ecSmrg    {
44005b261ecSmrg	for (prev = &timers; *prev; prev = &(*prev)->next)
44105b261ecSmrg	{
44205b261ecSmrg	    if (*prev == timer)
44305b261ecSmrg	    {
44405b261ecSmrg		*prev = timer->next;
44505b261ecSmrg		if (flags & TimerForceOld)
44605b261ecSmrg		    (void)(*timer->callback)(timer, now, timer->arg);
44705b261ecSmrg		break;
44805b261ecSmrg	    }
44905b261ecSmrg	}
45005b261ecSmrg    }
45105b261ecSmrg    if (!millis)
45205b261ecSmrg	return timer;
45305b261ecSmrg    if (flags & TimerAbsolute) {
45405b261ecSmrg        timer->delta = millis - now;
45505b261ecSmrg    }
45605b261ecSmrg    else {
45705b261ecSmrg        timer->delta = millis;
45805b261ecSmrg	millis += now;
45905b261ecSmrg    }
46005b261ecSmrg    timer->expires = millis;
46105b261ecSmrg    timer->callback = func;
46205b261ecSmrg    timer->arg = arg;
46305b261ecSmrg    if ((int) (millis - now) <= 0)
46405b261ecSmrg    {
46505b261ecSmrg	timer->next = NULL;
46605b261ecSmrg	millis = (*timer->callback)(timer, now, timer->arg);
46705b261ecSmrg	if (!millis)
46805b261ecSmrg	    return timer;
46905b261ecSmrg    }
47005b261ecSmrg    for (prev = &timers;
47105b261ecSmrg	 *prev && (int) ((*prev)->expires - millis) <= 0;
47205b261ecSmrg	 prev = &(*prev)->next)
47305b261ecSmrg        ;
47405b261ecSmrg    timer->next = *prev;
47505b261ecSmrg    *prev = timer;
47605b261ecSmrg    return timer;
47705b261ecSmrg}
47805b261ecSmrg
47905b261ecSmrgBool
48005b261ecSmrgTimerForce(OsTimerPtr timer)
48105b261ecSmrg{
48205b261ecSmrg    OsTimerPtr *prev;
48305b261ecSmrg
48405b261ecSmrg    for (prev = &timers; *prev; prev = &(*prev)->next)
48505b261ecSmrg    {
48605b261ecSmrg	if (*prev == timer)
48705b261ecSmrg	{
48805b261ecSmrg	    DoTimer(timer, GetTimeInMillis(), prev);
48905b261ecSmrg	    return TRUE;
49005b261ecSmrg	}
49105b261ecSmrg    }
49205b261ecSmrg    return FALSE;
49305b261ecSmrg}
49405b261ecSmrg
49505b261ecSmrg
4966747b715Smrgvoid
49705b261ecSmrgTimerCancel(OsTimerPtr timer)
49805b261ecSmrg{
49905b261ecSmrg    OsTimerPtr *prev;
50005b261ecSmrg
50105b261ecSmrg    if (!timer)
50205b261ecSmrg	return;
50305b261ecSmrg    for (prev = &timers; *prev; prev = &(*prev)->next)
50405b261ecSmrg    {
50505b261ecSmrg	if (*prev == timer)
50605b261ecSmrg	{
50705b261ecSmrg	    *prev = timer->next;
50805b261ecSmrg	    break;
50905b261ecSmrg	}
51005b261ecSmrg    }
51105b261ecSmrg}
51205b261ecSmrg
5136747b715Smrgvoid
51405b261ecSmrgTimerFree(OsTimerPtr timer)
51505b261ecSmrg{
51605b261ecSmrg    if (!timer)
51705b261ecSmrg	return;
51805b261ecSmrg    TimerCancel(timer);
5196747b715Smrg    free(timer);
52005b261ecSmrg}
52105b261ecSmrg
52205b261ecSmrgvoid
52305b261ecSmrgTimerCheck(void)
52405b261ecSmrg{
52505b261ecSmrg    CARD32 now = GetTimeInMillis();
52605b261ecSmrg
52705b261ecSmrg    while (timers && (int) (timers->expires - now) <= 0)
52805b261ecSmrg	DoTimer(timers, now, &timers);
52905b261ecSmrg}
53005b261ecSmrg
53105b261ecSmrgvoid
53205b261ecSmrgTimerInit(void)
53305b261ecSmrg{
53405b261ecSmrg    OsTimerPtr timer;
53505b261ecSmrg
53605b261ecSmrg    while ((timer = timers))
53705b261ecSmrg    {
53805b261ecSmrg	timers = timer->next;
5396747b715Smrg	free(timer);
54005b261ecSmrg    }
54105b261ecSmrg}
54205b261ecSmrg
54305b261ecSmrg#ifdef DPMSExtension
54405b261ecSmrg
54505b261ecSmrg#define DPMS_CHECK_MODE(mode,time)\
54605b261ecSmrg    if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\
5474642e01fSmrg	DPMSSet(serverClient, mode);
54805b261ecSmrg
54905b261ecSmrg#define DPMS_CHECK_TIMEOUT(time)\
55005b261ecSmrg    if (time > 0 && (time - timeout) > 0)\
55105b261ecSmrg	return time - timeout;
55205b261ecSmrg
55305b261ecSmrgstatic CARD32
55405b261ecSmrgNextDPMSTimeout(INT32 timeout)
55505b261ecSmrg{
55605b261ecSmrg    /*
55705b261ecSmrg     * Return the amount of time remaining until we should set
55805b261ecSmrg     * the next power level. Fallthroughs are intentional.
55905b261ecSmrg     */
56005b261ecSmrg    switch (DPMSPowerLevel)
56105b261ecSmrg    {
56205b261ecSmrg	case DPMSModeOn:
56305b261ecSmrg	    DPMS_CHECK_TIMEOUT(DPMSStandbyTime)
56405b261ecSmrg
56505b261ecSmrg	case DPMSModeStandby:
56605b261ecSmrg	    DPMS_CHECK_TIMEOUT(DPMSSuspendTime)
56705b261ecSmrg
56805b261ecSmrg	case DPMSModeSuspend:
56905b261ecSmrg	    DPMS_CHECK_TIMEOUT(DPMSOffTime)
57005b261ecSmrg
57105b261ecSmrg	default: /* DPMSModeOff */
57205b261ecSmrg	    return 0;
57305b261ecSmrg    }
57405b261ecSmrg}
57505b261ecSmrg#endif /* DPMSExtension */
57605b261ecSmrg
57705b261ecSmrgstatic CARD32
57805b261ecSmrgScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer arg)
57905b261ecSmrg{
58005b261ecSmrg    INT32 timeout      = now - lastDeviceEventTime.milliseconds;
58105b261ecSmrg    CARD32 nextTimeout = 0;
58205b261ecSmrg
58305b261ecSmrg#ifdef DPMSExtension
58405b261ecSmrg    /*
58505b261ecSmrg     * Check each mode lowest to highest, since a lower mode can
58605b261ecSmrg     * have the same timeout as a higher one.
58705b261ecSmrg     */
58805b261ecSmrg    if (DPMSEnabled)
58905b261ecSmrg    {
59005b261ecSmrg	DPMS_CHECK_MODE(DPMSModeOff,     DPMSOffTime)
59105b261ecSmrg	DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime)
59205b261ecSmrg	DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime)
59305b261ecSmrg
59405b261ecSmrg	nextTimeout = NextDPMSTimeout(timeout);
59505b261ecSmrg    }
59605b261ecSmrg
59705b261ecSmrg    /*
59805b261ecSmrg     * Only do the screensaver checks if we're not in a DPMS
59905b261ecSmrg     * power saving mode
60005b261ecSmrg     */
60105b261ecSmrg    if (DPMSPowerLevel != DPMSModeOn)
60205b261ecSmrg	return nextTimeout;
60305b261ecSmrg#endif /* DPMSExtension */
60405b261ecSmrg
60505b261ecSmrg    if (!ScreenSaverTime)
60605b261ecSmrg	return nextTimeout;
60705b261ecSmrg
60805b261ecSmrg    if (timeout < ScreenSaverTime)
60905b261ecSmrg    {
61005b261ecSmrg	return nextTimeout > 0 ?
61105b261ecSmrg		min(ScreenSaverTime - timeout, nextTimeout) :
61205b261ecSmrg		ScreenSaverTime - timeout;
61305b261ecSmrg    }
61405b261ecSmrg
61505b261ecSmrg    ResetOsBuffers(); /* not ideal, but better than nothing */
6164642e01fSmrg    dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive);
61705b261ecSmrg
61805b261ecSmrg    if (ScreenSaverInterval > 0)
61905b261ecSmrg    {
62005b261ecSmrg	nextTimeout = nextTimeout > 0 ?
62105b261ecSmrg		min(ScreenSaverInterval, nextTimeout) :
62205b261ecSmrg		ScreenSaverInterval;
62305b261ecSmrg    }
62405b261ecSmrg
62505b261ecSmrg    return nextTimeout;
62605b261ecSmrg}
62705b261ecSmrg
62805b261ecSmrgstatic OsTimerPtr ScreenSaverTimer = NULL;
62905b261ecSmrg
63005b261ecSmrgvoid
63105b261ecSmrgFreeScreenSaverTimer(void)
63205b261ecSmrg{
63305b261ecSmrg    if (ScreenSaverTimer) {
63405b261ecSmrg	TimerFree(ScreenSaverTimer);
63505b261ecSmrg	ScreenSaverTimer = NULL;
63605b261ecSmrg    }
63705b261ecSmrg}
63805b261ecSmrg
63905b261ecSmrgvoid
64005b261ecSmrgSetScreenSaverTimer(void)
64105b261ecSmrg{
64205b261ecSmrg    CARD32 timeout = 0;
64305b261ecSmrg
64405b261ecSmrg#ifdef DPMSExtension
64505b261ecSmrg    if (DPMSEnabled)
64605b261ecSmrg    {
64705b261ecSmrg	/*
64805b261ecSmrg	 * A higher DPMS level has a timeout that's either less
64905b261ecSmrg	 * than or equal to that of a lower DPMS level.
65005b261ecSmrg	 */
65105b261ecSmrg	if (DPMSStandbyTime > 0)
65205b261ecSmrg	    timeout = DPMSStandbyTime;
65305b261ecSmrg
65405b261ecSmrg	else if (DPMSSuspendTime > 0)
65505b261ecSmrg	    timeout = DPMSSuspendTime;
65605b261ecSmrg
65705b261ecSmrg	else if (DPMSOffTime > 0)
65805b261ecSmrg	    timeout = DPMSOffTime;
65905b261ecSmrg    }
66005b261ecSmrg#endif
66105b261ecSmrg
66205b261ecSmrg    if (ScreenSaverTime > 0)
66305b261ecSmrg    {
66405b261ecSmrg	timeout = timeout > 0 ?
66505b261ecSmrg		min(ScreenSaverTime, timeout) :
66605b261ecSmrg		ScreenSaverTime;
66705b261ecSmrg    }
66805b261ecSmrg
66905b261ecSmrg#ifdef SCREENSAVER
67005b261ecSmrg    if (timeout && !screenSaverSuspended) {
67105b261ecSmrg#else
67205b261ecSmrg    if (timeout) {
67305b261ecSmrg#endif
67405b261ecSmrg	ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout,
67505b261ecSmrg	                            ScreenSaverTimeoutExpire, NULL);
67605b261ecSmrg    }
67705b261ecSmrg    else if (ScreenSaverTimer) {
67805b261ecSmrg	FreeScreenSaverTimer();
67905b261ecSmrg    }
68005b261ecSmrg}
68105b261ecSmrg
682