WaitFor.c revision 6747b715
1/*********************************************************** 2 3Copyright 1987, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25 26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 27 28 All Rights Reserved 29 30Permission to use, copy, modify, and distribute this software and its 31documentation for any purpose and without fee is hereby granted, 32provided that the above copyright notice appear in all copies and that 33both that copyright notice and this permission notice appear in 34supporting documentation, and that the name of Digital not be 35used in advertising or publicity pertaining to distribution of the 36software without specific, written prior permission. 37 38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44SOFTWARE. 45 46******************************************************************/ 47 48 49/***************************************************************** 50 * OS Dependent input routines: 51 * 52 * WaitForSomething 53 * TimerForce, TimerSet, TimerCheck, TimerFree 54 * 55 *****************************************************************/ 56 57#ifdef HAVE_DIX_CONFIG_H 58#include <dix-config.h> 59#endif 60 61#ifdef WIN32 62#include <X11/Xwinsock.h> 63#endif 64#include <X11/Xos.h> /* for strings, fcntl, time */ 65#include <errno.h> 66#include <stdio.h> 67#include <X11/X.h> 68#include "misc.h" 69 70#include "osdep.h" 71#include <X11/Xpoll.h> 72#include "dixstruct.h" 73#include "opaque.h" 74#ifdef DPMSExtension 75#include "dpmsproc.h" 76#endif 77 78#ifdef WIN32 79/* Error codes from windows sockets differ from fileio error codes */ 80#undef EINTR 81#define EINTR WSAEINTR 82#undef EINVAL 83#define EINVAL WSAEINVAL 84#undef EBADF 85#define EBADF WSAENOTSOCK 86/* Windows select does not set errno. Use GetErrno as wrapper for 87 WSAGetLastError */ 88#define GetErrno WSAGetLastError 89#else 90/* This is just a fallback to errno to hide the differences between unix and 91 Windows in the code */ 92#define GetErrno() errno 93#endif 94 95/* like ffs, but uses fd_mask instead of int as argument, so it works 96 when fd_mask is longer than an int, such as common 64-bit platforms */ 97/* modifications by raphael */ 98int 99mffs(fd_mask mask) 100{ 101 int i; 102 103 if (!mask) return 0; 104 i = 1; 105 while (!(mask & 1)) 106 { 107 i++; 108 mask >>= 1; 109 } 110 return i; 111} 112 113#ifdef DPMSExtension 114#include <X11/extensions/dpmsconst.h> 115#endif 116 117struct _OsTimerRec { 118 OsTimerPtr next; 119 CARD32 expires; 120 CARD32 delta; 121 OsTimerCallback callback; 122 pointer arg; 123}; 124 125static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev); 126static void CheckAllTimers(void); 127static OsTimerPtr timers = NULL; 128 129/***************** 130 * WaitForSomething: 131 * Make the server suspend until there is 132 * 1. data from clients or 133 * 2. input events available or 134 * 3. ddx notices something of interest (graphics 135 * queue ready, etc.) or 136 * 4. clients that have buffered replies/events are ready 137 * 138 * If the time between INPUT events is 139 * greater than ScreenSaverTime, the display is turned off (or 140 * saved, depending on the hardware). So, WaitForSomething() 141 * has to handle this also (that's why the select() has a timeout. 142 * For more info on ClientsWithInput, see ReadRequestFromClient(). 143 * pClientsReady is an array to store ready client->index values into. 144 *****************/ 145 146int 147WaitForSomething(int *pClientsReady) 148{ 149 int i; 150 struct timeval waittime, *wt; 151 INT32 timeout = 0; 152 fd_set clientsReadable; 153 fd_set clientsWritable; 154 int curclient; 155 int selecterr; 156 int nready; 157 fd_set devicesReadable; 158 CARD32 now = 0; 159 Bool someReady = FALSE; 160 161 FD_ZERO(&clientsReadable); 162 163 /* We need a while loop here to handle 164 crashed connections and the screen saver timeout */ 165 while (1) 166 { 167 /* deal with any blocked jobs */ 168 if (workQueue) 169 ProcessWorkQueue(); 170 if (XFD_ANYSET (&ClientsWithInput)) 171 { 172 if (!SmartScheduleDisable) 173 { 174 someReady = TRUE; 175 waittime.tv_sec = 0; 176 waittime.tv_usec = 0; 177 wt = &waittime; 178 } 179 else 180 { 181 XFD_COPYSET (&ClientsWithInput, &clientsReadable); 182 break; 183 } 184 } 185 if (someReady) 186 { 187 XFD_COPYSET(&AllSockets, &LastSelectMask); 188 XFD_UNSET(&LastSelectMask, &ClientsWithInput); 189 } 190 else 191 { 192 wt = NULL; 193 if (timers) 194 { 195 now = GetTimeInMillis(); 196 timeout = timers->expires - now; 197 if (timeout > 0 && timeout > timers->delta + 250) { 198 /* time has rewound. reset the timers. */ 199 CheckAllTimers(); 200 } 201 202 if (timers) { 203 timeout = timers->expires - now; 204 if (timeout < 0) 205 timeout = 0; 206 waittime.tv_sec = timeout / MILLI_PER_SECOND; 207 waittime.tv_usec = (timeout % MILLI_PER_SECOND) * 208 (1000000 / MILLI_PER_SECOND); 209 wt = &waittime; 210 } 211 } 212 XFD_COPYSET(&AllSockets, &LastSelectMask); 213 } 214 SmartScheduleStopTimer (); 215 216 BlockHandler((pointer)&wt, (pointer)&LastSelectMask); 217 if (NewOutputPending) 218 FlushAllOutput(); 219 /* keep this check close to select() call to minimize race */ 220 if (dispatchException) 221 i = -1; 222 else if (AnyClientsWriteBlocked) 223 { 224 XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable); 225 i = Select (MaxClients, &LastSelectMask, &clientsWritable, NULL, wt); 226 } 227 else 228 { 229 i = Select (MaxClients, &LastSelectMask, NULL, NULL, wt); 230 } 231 selecterr = GetErrno(); 232 WakeupHandler(i, (pointer)&LastSelectMask); 233 SmartScheduleStartTimer (); 234 if (i <= 0) /* An error or timeout occurred */ 235 { 236 if (dispatchException) 237 return 0; 238 if (i < 0) 239 { 240 if (selecterr == EBADF) /* Some client disconnected */ 241 { 242 CheckConnections (); 243 if (! XFD_ANYSET (&AllClients)) 244 return 0; 245 } 246 else if (selecterr == EINVAL) 247 { 248 FatalError("WaitForSomething(): select: %s\n", 249 strerror(selecterr)); 250 } 251 else if (selecterr != EINTR && selecterr != EAGAIN) 252 { 253 ErrorF("WaitForSomething(): select: %s\n", 254 strerror(selecterr)); 255 } 256 } 257 else if (someReady) 258 { 259 /* 260 * If no-one else is home, bail quickly 261 */ 262 XFD_COPYSET(&ClientsWithInput, &LastSelectMask); 263 XFD_COPYSET(&ClientsWithInput, &clientsReadable); 264 break; 265 } 266 if (*checkForInput[0] != *checkForInput[1]) 267 return 0; 268 269 if (timers) 270 { 271 int expired = 0; 272 now = GetTimeInMillis(); 273 if ((int) (timers->expires - now) <= 0) 274 expired = 1; 275 276 while (timers && (int) (timers->expires - now) <= 0) 277 DoTimer(timers, now, &timers); 278 279 if (expired) 280 return 0; 281 } 282 } 283 else 284 { 285 fd_set tmp_set; 286 287 if (*checkForInput[0] == *checkForInput[1]) { 288 if (timers) 289 { 290 int expired = 0; 291 now = GetTimeInMillis(); 292 if ((int) (timers->expires - now) <= 0) 293 expired = 1; 294 295 while (timers && (int) (timers->expires - now) <= 0) 296 DoTimer(timers, now, &timers); 297 298 if (expired) 299 return 0; 300 } 301 } 302 if (someReady) 303 XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask); 304 if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable)) 305 { 306 NewOutputPending = TRUE; 307 XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending); 308 XFD_UNSET(&ClientsWriteBlocked, &clientsWritable); 309 if (! XFD_ANYSET(&ClientsWriteBlocked)) 310 AnyClientsWriteBlocked = FALSE; 311 } 312 313 XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices); 314 XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients); 315 XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections); 316 if (XFD_ANYSET(&tmp_set)) 317 QueueWorkProc(EstablishNewConnections, NULL, 318 (pointer)&LastSelectMask); 319 320 if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable)) 321 break; 322 /* check here for DDXes that queue events during Block/Wakeup */ 323 if (*checkForInput[0] != *checkForInput[1]) 324 return 0; 325 } 326 } 327 328 nready = 0; 329 if (XFD_ANYSET (&clientsReadable)) 330 { 331#ifndef WIN32 332 for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++) 333 { 334 int highest_priority = 0; 335 336 while (clientsReadable.fds_bits[i]) 337 { 338 int client_priority, client_index; 339 340 curclient = mffs (clientsReadable.fds_bits[i]) - 1; 341 client_index = /* raphael: modified */ 342 ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))]; 343#else 344 int highest_priority = 0; 345 fd_set savedClientsReadable; 346 XFD_COPYSET(&clientsReadable, &savedClientsReadable); 347 for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++) 348 { 349 int client_priority, client_index; 350 351 curclient = XFD_FD(&savedClientsReadable, i); 352 client_index = GetConnectionTranslation(curclient); 353#endif 354 /* We implement "strict" priorities. 355 * Only the highest priority client is returned to 356 * dix. If multiple clients at the same priority are 357 * ready, they are all returned. This means that an 358 * aggressive client could take over the server. 359 * This was not considered a big problem because 360 * aggressive clients can hose the server in so many 361 * other ways :) 362 */ 363 client_priority = clients[client_index]->priority; 364 if (nready == 0 || client_priority > highest_priority) 365 { 366 /* Either we found the first client, or we found 367 * a client whose priority is greater than all others 368 * that have been found so far. Either way, we want 369 * to initialize the list of clients to contain just 370 * this client. 371 */ 372 pClientsReady[0] = client_index; 373 highest_priority = client_priority; 374 nready = 1; 375 } 376 /* the following if makes sure that multiple same-priority 377 * clients get batched together 378 */ 379 else if (client_priority == highest_priority) 380 { 381 pClientsReady[nready++] = client_index; 382 } 383#ifndef WIN32 384 clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient); 385 } 386#else 387 FD_CLR(curclient, &clientsReadable); 388#endif 389 } 390 } 391 return nready; 392} 393 394/* If time has rewound, re-run every affected timer. 395 * Timers might drop out of the list, so we have to restart every time. */ 396static void 397CheckAllTimers(void) 398{ 399 OsTimerPtr timer; 400 CARD32 now; 401 402start: 403 now = GetTimeInMillis(); 404 405 for (timer = timers; timer; timer = timer->next) { 406 if (timer->expires - now > timer->delta + 250) { 407 TimerForce(timer); 408 goto start; 409 } 410 } 411} 412 413static void 414DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev) 415{ 416 CARD32 newTime; 417 418 *prev = timer->next; 419 timer->next = NULL; 420 newTime = (*timer->callback)(timer, now, timer->arg); 421 if (newTime) 422 TimerSet(timer, 0, newTime, timer->callback, timer->arg); 423} 424 425OsTimerPtr 426TimerSet(OsTimerPtr timer, int flags, CARD32 millis, 427 OsTimerCallback func, pointer arg) 428{ 429 register OsTimerPtr *prev; 430 CARD32 now = GetTimeInMillis(); 431 432 if (!timer) 433 { 434 timer = malloc(sizeof(struct _OsTimerRec)); 435 if (!timer) 436 return NULL; 437 } 438 else 439 { 440 for (prev = &timers; *prev; prev = &(*prev)->next) 441 { 442 if (*prev == timer) 443 { 444 *prev = timer->next; 445 if (flags & TimerForceOld) 446 (void)(*timer->callback)(timer, now, timer->arg); 447 break; 448 } 449 } 450 } 451 if (!millis) 452 return timer; 453 if (flags & TimerAbsolute) { 454 timer->delta = millis - now; 455 } 456 else { 457 timer->delta = millis; 458 millis += now; 459 } 460 timer->expires = millis; 461 timer->callback = func; 462 timer->arg = arg; 463 if ((int) (millis - now) <= 0) 464 { 465 timer->next = NULL; 466 millis = (*timer->callback)(timer, now, timer->arg); 467 if (!millis) 468 return timer; 469 } 470 for (prev = &timers; 471 *prev && (int) ((*prev)->expires - millis) <= 0; 472 prev = &(*prev)->next) 473 ; 474 timer->next = *prev; 475 *prev = timer; 476 return timer; 477} 478 479Bool 480TimerForce(OsTimerPtr timer) 481{ 482 OsTimerPtr *prev; 483 484 for (prev = &timers; *prev; prev = &(*prev)->next) 485 { 486 if (*prev == timer) 487 { 488 DoTimer(timer, GetTimeInMillis(), prev); 489 return TRUE; 490 } 491 } 492 return FALSE; 493} 494 495 496void 497TimerCancel(OsTimerPtr timer) 498{ 499 OsTimerPtr *prev; 500 501 if (!timer) 502 return; 503 for (prev = &timers; *prev; prev = &(*prev)->next) 504 { 505 if (*prev == timer) 506 { 507 *prev = timer->next; 508 break; 509 } 510 } 511} 512 513void 514TimerFree(OsTimerPtr timer) 515{ 516 if (!timer) 517 return; 518 TimerCancel(timer); 519 free(timer); 520} 521 522void 523TimerCheck(void) 524{ 525 CARD32 now = GetTimeInMillis(); 526 527 while (timers && (int) (timers->expires - now) <= 0) 528 DoTimer(timers, now, &timers); 529} 530 531void 532TimerInit(void) 533{ 534 OsTimerPtr timer; 535 536 while ((timer = timers)) 537 { 538 timers = timer->next; 539 free(timer); 540 } 541} 542 543#ifdef DPMSExtension 544 545#define DPMS_CHECK_MODE(mode,time)\ 546 if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\ 547 DPMSSet(serverClient, mode); 548 549#define DPMS_CHECK_TIMEOUT(time)\ 550 if (time > 0 && (time - timeout) > 0)\ 551 return time - timeout; 552 553static CARD32 554NextDPMSTimeout(INT32 timeout) 555{ 556 /* 557 * Return the amount of time remaining until we should set 558 * the next power level. Fallthroughs are intentional. 559 */ 560 switch (DPMSPowerLevel) 561 { 562 case DPMSModeOn: 563 DPMS_CHECK_TIMEOUT(DPMSStandbyTime) 564 565 case DPMSModeStandby: 566 DPMS_CHECK_TIMEOUT(DPMSSuspendTime) 567 568 case DPMSModeSuspend: 569 DPMS_CHECK_TIMEOUT(DPMSOffTime) 570 571 default: /* DPMSModeOff */ 572 return 0; 573 } 574} 575#endif /* DPMSExtension */ 576 577static CARD32 578ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer arg) 579{ 580 INT32 timeout = now - lastDeviceEventTime.milliseconds; 581 CARD32 nextTimeout = 0; 582 583#ifdef DPMSExtension 584 /* 585 * Check each mode lowest to highest, since a lower mode can 586 * have the same timeout as a higher one. 587 */ 588 if (DPMSEnabled) 589 { 590 DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime) 591 DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime) 592 DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime) 593 594 nextTimeout = NextDPMSTimeout(timeout); 595 } 596 597 /* 598 * Only do the screensaver checks if we're not in a DPMS 599 * power saving mode 600 */ 601 if (DPMSPowerLevel != DPMSModeOn) 602 return nextTimeout; 603#endif /* DPMSExtension */ 604 605 if (!ScreenSaverTime) 606 return nextTimeout; 607 608 if (timeout < ScreenSaverTime) 609 { 610 return nextTimeout > 0 ? 611 min(ScreenSaverTime - timeout, nextTimeout) : 612 ScreenSaverTime - timeout; 613 } 614 615 ResetOsBuffers(); /* not ideal, but better than nothing */ 616 dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive); 617 618 if (ScreenSaverInterval > 0) 619 { 620 nextTimeout = nextTimeout > 0 ? 621 min(ScreenSaverInterval, nextTimeout) : 622 ScreenSaverInterval; 623 } 624 625 return nextTimeout; 626} 627 628static OsTimerPtr ScreenSaverTimer = NULL; 629 630void 631FreeScreenSaverTimer(void) 632{ 633 if (ScreenSaverTimer) { 634 TimerFree(ScreenSaverTimer); 635 ScreenSaverTimer = NULL; 636 } 637} 638 639void 640SetScreenSaverTimer(void) 641{ 642 CARD32 timeout = 0; 643 644#ifdef DPMSExtension 645 if (DPMSEnabled) 646 { 647 /* 648 * A higher DPMS level has a timeout that's either less 649 * than or equal to that of a lower DPMS level. 650 */ 651 if (DPMSStandbyTime > 0) 652 timeout = DPMSStandbyTime; 653 654 else if (DPMSSuspendTime > 0) 655 timeout = DPMSSuspendTime; 656 657 else if (DPMSOffTime > 0) 658 timeout = DPMSOffTime; 659 } 660#endif 661 662 if (ScreenSaverTime > 0) 663 { 664 timeout = timeout > 0 ? 665 min(ScreenSaverTime, timeout) : 666 ScreenSaverTime; 667 } 668 669#ifdef SCREENSAVER 670 if (timeout && !screenSaverSuspended) { 671#else 672 if (timeout) { 673#endif 674 ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout, 675 ScreenSaverTimeoutExpire, NULL); 676 } 677 else if (ScreenSaverTimer) { 678 FreeScreenSaverTimer(); 679 } 680} 681 682