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