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