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