summaryrefslogtreecommitdiff
path: root/os/WaitFor.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/WaitFor.c')
-rw-r--r--os/WaitFor.c613
1 files changed, 613 insertions, 0 deletions
diff --git a/os/WaitFor.c b/os/WaitFor.c
new file mode 100644
index 000000000..fbc05399c
--- /dev/null
+++ b/os/WaitFor.c
@@ -0,0 +1,613 @@
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/* $Xorg: WaitFor.c,v 1.4 2001/02/09 02:05:22 xorgcvs Exp $ */
+
+/*****************************************************************
+ * OS Dependent input routines:
+ *
+ * WaitForSomething
+ * TimerForce, TimerSet, TimerCheck, TimerFree
+ *
+ *****************************************************************/
+
+#ifdef WIN32
+#include <X11/Xwinsock.h>
+#endif
+#include "Xos.h" /* for strings, fcntl, time */
+
+#include <errno.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#include <stdio.h>
+#include "X.h"
+#include "misc.h"
+
+#include <X11/Xpoll.h>
+#include "osdep.h"
+#include "dixstruct.h"
+#include "opaque.h"
+
+#ifdef DPMSExtension
+#include "dpms.h"
+extern void DPMSSet();
+extern void DPMSGet();
+extern CARD32 DPMSStandbyTime;
+extern CARD32 DPMSSuspendTime;
+extern CARD32 DPMSOffTime;
+extern BOOL DPMSEnabled;
+extern CARD16 DPMSPowerLevel;
+#endif
+
+extern fd_set AllSockets;
+extern fd_set AllClients;
+extern fd_set LastSelectMask;
+extern fd_set WellKnownConnections;
+extern fd_set EnabledDevices;
+extern fd_set ClientsWithInput;
+extern fd_set ClientsWriteBlocked;
+extern fd_set OutputPending;
+
+extern int ConnectionTranslation[];
+
+extern Bool NewOutputPending;
+extern Bool AnyClientsWriteBlocked;
+
+extern WorkQueuePtr workQueue;
+
+
+#ifdef XTESTEXT1
+/*
+ * defined in xtestext1dd.c
+ */
+extern int playback_on;
+#endif /* XTESTEXT1 */
+
+struct _OsTimerRec {
+ OsTimerPtr next;
+ CARD32 expires;
+ OsTimerCallback callback;
+ pointer arg;
+};
+
+static void DoTimer();
+static OsTimerPtr timers;
+
+/*****************
+ * WaitForSomething:
+ * Make the server suspend until there is
+ * 1. data from clients or
+ * 2. input events available or
+ * 3. ddx notices something of interest (graphics
+ * queue ready, etc.) or
+ * 4. clients that have buffered replies/events are ready
+ *
+ * If the time between INPUT events is
+ * greater than ScreenSaverTime, the display is turned off (or
+ * saved, depending on the hardware). So, WaitForSomething()
+ * has to handle this also (that's why the select() has a timeout.
+ * For more info on ClientsWithInput, see ReadRequestFromClient().
+ * pClientsReady is an array to store ready client->index values into.
+ *****************/
+
+static INT32 timeTilFrob = 0; /* while screen saving */
+
+int
+WaitForSomething(pClientsReady)
+ int *pClientsReady;
+{
+ int i;
+ struct timeval waittime, *wt;
+ INT32 timeout;
+#ifdef DPMSExtension
+ INT32 standbyTimeout, suspendTimeout, offTimeout;
+#endif
+ fd_set clientsReadable;
+ fd_set clientsWritable;
+ int curclient;
+ int selecterr;
+ int nready;
+ fd_set devicesReadable;
+ CARD32 now;
+
+ FD_ZERO(&clientsReadable);
+
+ /* We need a while loop here to handle
+ crashed connections and the screen saver timeout */
+ while (1)
+ {
+ /* deal with any blocked jobs */
+ if (workQueue)
+ ProcessWorkQueue();
+
+ if (XFD_ANYSET (&ClientsWithInput))
+ {
+ XFD_COPYSET (&ClientsWithInput, &clientsReadable);
+ break;
+ }
+#ifdef DPMSExtension
+ if (ScreenSaverTime > 0 || DPMSEnabled || timers)
+#else
+ if (ScreenSaverTime > 0 || timers)
+#endif
+ now = GetTimeInMillis();
+ wt = NULL;
+ if (timers)
+ {
+ while (timers && timers->expires <= now)
+ DoTimer(timers, now, &timers);
+ if (timers)
+ {
+ timeout = timers->expires - now;
+ waittime.tv_sec = timeout / MILLI_PER_SECOND;
+ waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
+ (1000000 / MILLI_PER_SECOND);
+ wt = &waittime;
+ }
+ }
+ if (ScreenSaverTime > 0
+#ifdef DPMSExtension
+ || (DPMSEnabled &&
+ (DPMSStandbyTime > 0 || DPMSSuspendTime > 0 || DPMSOffTime > 0))
+#endif
+ ) {
+#ifdef DPMSExtension
+ if (ScreenSaverTime > 0)
+#endif
+ timeout = (ScreenSaverTime -
+ (now - lastDeviceEventTime.milliseconds));
+#ifdef DPMSExtension
+ if (DPMSStandbyTime > 0)
+ standbyTimeout = (DPMSStandbyTime -
+ (now - lastDeviceEventTime.milliseconds));
+ if (DPMSSuspendTime > 0)
+ suspendTimeout = (DPMSSuspendTime -
+ (now - lastDeviceEventTime.milliseconds));
+ if (DPMSOffTime > 0)
+ offTimeout = (DPMSOffTime -
+ (now - lastDeviceEventTime.milliseconds));
+#endif /* DPMSExtension */
+
+ if (timeout <= 0
+#ifdef DPMSExtension
+ && ScreenSaverTime > 0
+#endif /* DPMSExtension */
+ ) {
+ INT32 timeSinceSave;
+
+ timeSinceSave = -timeout;
+ if (timeSinceSave >= timeTilFrob && timeTilFrob >= 0)
+ {
+ ResetOsBuffers(); /* not ideal, but better than nothing */
+ SaveScreens(SCREEN_SAVER_ON, ScreenSaverActive);
+#ifdef DPMSExtension
+ if (ScreenSaverInterval > 0 &&
+ DPMSPowerLevel == DPMSModeOn)
+#else
+ if (ScreenSaverInterval)
+#endif /* DPMSExtension */
+ /* round up to the next ScreenSaverInterval */
+ timeTilFrob = ScreenSaverInterval *
+ ((timeSinceSave + ScreenSaverInterval) /
+ ScreenSaverInterval);
+ else
+ timeTilFrob = -1;
+ }
+ timeout = timeTilFrob - timeSinceSave;
+ }
+ else
+ {
+ if (ScreenSaverTime > 0 && timeout > ScreenSaverTime)
+ timeout = ScreenSaverTime;
+ timeTilFrob = 0;
+ }
+#ifdef DPMSExtension
+ if (DPMSEnabled)
+ {
+ if (standbyTimeout > 0 && timeout > standbyTimeout)
+ timeout = standbyTimeout;
+ if (suspendTimeout > 0 && timeout > suspendTimeout)
+ timeout = suspendTimeout;
+ if (offTimeout > 0 && timeout > offTimeout)
+ timeout = offTimeout;
+ }
+#endif
+ if (timeout > 0 && (!wt || timeout < (timers->expires - now)))
+ {
+ waittime.tv_sec = timeout / MILLI_PER_SECOND;
+ waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
+ (1000000 / MILLI_PER_SECOND);
+ wt = &waittime;
+ }
+#ifdef DPMSExtension
+ /* don't bother unless it's switched on */
+ if (DPMSEnabled) {
+ /*
+ * If this mode's enabled, and if the time's come
+ * and if we're still at a lesser mode, do it now.
+ */
+ if (DPMSStandbyTime > 0) {
+ if (standbyTimeout <= 0) {
+ if (DPMSPowerLevel < DPMSModeStandby) {
+ DPMSSet(DPMSModeStandby);
+ }
+ }
+ }
+ /*
+ * and ditto. Note that since these modes can have the
+ * same timeouts, they can happen at the same time.
+ */
+ if (DPMSSuspendTime > 0) {
+ if (suspendTimeout <= 0) {
+ if (DPMSPowerLevel < DPMSModeSuspend) {
+ DPMSSet(DPMSModeSuspend);
+ }
+ }
+ }
+ if (DPMSOffTime > 0) {
+ if (offTimeout <= 0) {
+ if (DPMSPowerLevel < DPMSModeOff) {
+ DPMSSet(DPMSModeOff);
+ }
+ }
+ }
+ }
+#endif
+ }
+ XFD_COPYSET(&AllSockets, &LastSelectMask);
+ BlockHandler((pointer)&wt, (pointer)&LastSelectMask);
+ if (NewOutputPending)
+ FlushAllOutput();
+#ifdef XTESTEXT1
+ /* XXX how does this interact with new write block handling? */
+ if (playback_on) {
+ wt = &waittime;
+ XTestComputeWaitTime (&waittime);
+ }
+#endif /* XTESTEXT1 */
+ /* keep this check close to select() call to minimize race */
+ if (dispatchException)
+ i = -1;
+ else if (AnyClientsWriteBlocked)
+ {
+ XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable);
+ i = Select (MAXSOCKS, &LastSelectMask, &clientsWritable, NULL, wt);
+ }
+ else
+ i = Select (MAXSOCKS, &LastSelectMask, NULL, NULL, wt);
+ selecterr = errno;
+ WakeupHandler(i, (pointer)&LastSelectMask);
+#ifdef XTESTEXT1
+ if (playback_on) {
+ i = XTestProcessInputAction (i, &waittime);
+ }
+#endif /* XTESTEXT1 */
+ if (i <= 0) /* An error or timeout occurred */
+ {
+
+ if (dispatchException)
+ return 0;
+ FD_ZERO(&clientsWritable);
+ if (i < 0)
+ if (selecterr == EBADF) /* Some client disconnected */
+ {
+ CheckConnections ();
+ if (! XFD_ANYSET (&AllClients))
+ return 0;
+ }
+ else if (selecterr == EINVAL)
+ {
+ FatalError("WaitForSomething(): select: errno=%d\n",
+ selecterr);
+ }
+ else if (selecterr != EINTR)
+ {
+ ErrorF("WaitForSomething(): select: errno=%d\n",
+ selecterr);
+ }
+ if (timers)
+ {
+ now = GetTimeInMillis();
+ while (timers && timers->expires <= now)
+ DoTimer(timers, now, &timers);
+ }
+ if (*checkForInput[0] != *checkForInput[1])
+ return 0;
+ }
+ else
+ {
+#ifdef WIN32
+ fd_set tmp_set;
+#endif
+ if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable))
+ {
+ NewOutputPending = TRUE;
+ XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
+ XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
+ if (! XFD_ANYSET(&ClientsWriteBlocked))
+ AnyClientsWriteBlocked = FALSE;
+ }
+
+ XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices);
+ XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
+#ifndef WIN32
+ if (LastSelectMask.fds_bits[0] & WellKnownConnections.fds_bits[0])
+#else
+ XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections);
+ if (XFD_ANYSET(&tmp_set))
+#endif
+ QueueWorkProc(EstablishNewConnections, NULL,
+ (pointer)&LastSelectMask);
+#ifdef DPMSExtension
+ if (XFD_ANYSET (&devicesReadable) && (DPMSPowerLevel != DPMSModeOn))
+ DPMSSet(DPMSModeOn);
+#endif
+ if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable))
+ break;
+ }
+ }
+
+ nready = 0;
+ if (XFD_ANYSET (&clientsReadable))
+ {
+#ifndef WIN32
+ for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++)
+ {
+ int highest_priority;
+
+ while (clientsReadable.fds_bits[i])
+ {
+ int client_priority, client_index;
+
+ curclient = ffs (clientsReadable.fds_bits[i]) - 1;
+ client_index = ConnectionTranslation[curclient + (i << 5)];
+#else
+ int highest_priority;
+ fd_set savedClientsReadable;
+ XFD_COPYSET(&clientsReadable, &savedClientsReadable);
+ for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++)
+ {
+ int client_priority, client_index;
+
+ curclient = XFD_FD(&savedClientsReadable, i);
+ client_index = ConnectionTranslation[curclient];
+#endif
+#ifdef XSYNC
+ /* We implement "strict" priorities.
+ * Only the highest priority client is returned to
+ * dix. If multiple clients at the same priority are
+ * ready, they are all returned. This means that an
+ * aggressive client could take over the server.
+ * This was not considered a big problem because
+ * aggressive clients can hose the server in so many
+ * other ways :)
+ */
+ client_priority = clients[client_index]->priority;
+ if (nready == 0 || client_priority > highest_priority)
+ {
+ /* Either we found the first client, or we found
+ * a client whose priority is greater than all others
+ * that have been found so far. Either way, we want
+ * to initialize the list of clients to contain just
+ * this client.
+ */
+ pClientsReady[0] = client_index;
+ highest_priority = client_priority;
+ nready = 1;
+ }
+ /* the following if makes sure that multiple same-priority
+ * clients get batched together
+ */
+ else if (client_priority == highest_priority)
+#endif
+ {
+ pClientsReady[nready++] = client_index;
+ }
+#ifndef WIN32
+ clientsReadable.fds_bits[i] &= ~(((fd_mask)1) << curclient);
+ }
+#else
+ FD_CLR(curclient, &clientsReadable);
+#endif
+ }
+ }
+ return nready;
+}
+
+#if 0
+/*
+ * This is not always a macro.
+ */
+ANYSET(src)
+ FdMask *src;
+{
+ int i;
+
+ for (i=0; i<mskcnt; i++)
+ if (src[ i ])
+ return (TRUE);
+ return (FALSE);
+}
+#endif
+
+static void
+DoTimer(timer, now, prev)
+ register OsTimerPtr timer;
+ CARD32 now;
+ OsTimerPtr *prev;
+{
+ CARD32 newTime;
+
+ *prev = timer->next;
+ timer->next = NULL;
+ newTime = (*timer->callback)(timer, now, timer->arg);
+ if (newTime)
+ TimerSet(timer, 0, newTime, timer->callback, timer->arg);
+}
+
+OsTimerPtr
+TimerSet(timer, flags, millis, func, arg)
+ register OsTimerPtr timer;
+ int flags;
+ CARD32 millis;
+ OsTimerCallback func;
+ pointer arg;
+{
+ register OsTimerPtr *prev;
+ CARD32 now = GetTimeInMillis();
+
+ if (!timer)
+ {
+ timer = (OsTimerPtr)xalloc(sizeof(struct _OsTimerRec));
+ if (!timer)
+ return NULL;
+ }
+ else
+ {
+ for (prev = &timers; *prev; prev = &(*prev)->next)
+ {
+ if (*prev == timer)
+ {
+ *prev = timer->next;
+ if (flags & TimerForceOld)
+ (void)(*timer->callback)(timer, now, timer->arg);
+ break;
+ }
+ }
+ }
+ if (!millis)
+ return timer;
+ if (!(flags & TimerAbsolute))
+ millis += now;
+ timer->expires = millis;
+ timer->callback = func;
+ timer->arg = arg;
+ if (millis <= now)
+ {
+ timer->next = NULL;
+ millis = (*timer->callback)(timer, now, timer->arg);
+ if (!millis)
+ return timer;
+ }
+ for (prev = &timers;
+ *prev && millis > (*prev)->expires;
+ prev = &(*prev)->next)
+ ;
+ timer->next = *prev;
+ *prev = timer;
+ return timer;
+}
+
+Bool
+TimerForce(timer)
+ register OsTimerPtr timer;
+{
+ register OsTimerPtr *prev;
+ register CARD32 newTime;
+
+ for (prev = &timers; *prev; prev = &(*prev)->next)
+ {
+ if (*prev == timer)
+ {
+ DoTimer(timer, GetTimeInMillis(), prev);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+void
+TimerCancel(timer)
+ register OsTimerPtr timer;
+{
+ register OsTimerPtr *prev;
+
+ if (!timer)
+ return;
+ for (prev = &timers; *prev; prev = &(*prev)->next)
+ {
+ if (*prev == timer)
+ {
+ *prev = timer->next;
+ break;
+ }
+ }
+}
+
+void
+TimerFree(timer)
+ register OsTimerPtr timer;
+{
+ if (!timer)
+ return;
+ TimerCancel(timer);
+ xfree(timer);
+}
+
+void
+TimerCheck()
+{
+ register CARD32 now = GetTimeInMillis();
+
+ while (timers && timers->expires <= now)
+ DoTimer(timers, now, &timers);
+}
+
+void
+TimerInit()
+{
+ OsTimerPtr timer;
+
+ while (timer = timers)
+ {
+ timers = timer->next;
+ xfree(timer);
+ }
+}