diff --git a/hw/dmx/dmx.h b/hw/dmx/dmx.h index ad364a437..d6f5c65e5 100644 --- a/hw/dmx/dmx.h +++ b/hw/dmx/dmx.h @@ -71,6 +71,9 @@ #include #endif +#include +#include + #include #include "dmxxlibio.h" @@ -85,10 +88,15 @@ typedef enum { PosRelative } PositionType; -typedef struct _DMXIgnore { - struct _DMXIgnore *next; - unsigned long sequence; -} DMXIgnore; +typedef struct _DMXSequence { + struct _DMXSequence *next; + unsigned long sequence; +} DMXSequence; + +typedef struct _DMXQueue { + DMXSequence *head; + DMXSequence **tail; +} DMXQueue; typedef struct _DMXPropTrans { const char *name; @@ -113,9 +121,10 @@ typedef struct _DMXScreenInfo { /*---------- Back-end X server information ----------*/ int fd; + int inDispatch; xcb_connection_t *connection; - xcb_get_input_focus_cookie_t syncCookie; + xcb_get_input_focus_cookie_t sync; Display *beDisplay; /**< Back-end X server's display */ int beWidth; /**< Width of BE display */ @@ -217,8 +226,8 @@ typedef struct _DMXScreenInfo { DMXStatInfo *stat; /**< Statistics about XSync */ Bool needsSync; /**< True if an XSync is pending */ - DMXIgnore *ignoreHead; - DMXIgnore **ignoreTail; + DMXQueue ignore; + DMXQueue request; #ifdef GLXEXT /** Visual information for glxProxy */ diff --git a/hw/dmx/dmxextension.c b/hw/dmx/dmxextension.c index bb1b3cd16..563a58016 100644 --- a/hw/dmx/dmxextension.c +++ b/hw/dmx/dmxextension.c @@ -1192,7 +1192,7 @@ static void dmxBECreateWindowTree(int idx) #endif XLIB_PROLOGUE (dmxScreen); - dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); + dmxAddSequence (&dmxScreen->ignore, NextRequest (dmxScreen->beDisplay)); XMapWindow(dmxScreen->beDisplay, dmxScreen->rootWin); XLIB_EPILOGUE (dmxScreen); @@ -2547,7 +2547,5 @@ int dmxDetachScreen(int idx) RRGetInfo (screenInfo.screens[0]); #endif - dmxDiscardIgnore (dmxScreen, ~0); - return 0; /* Success */ } diff --git a/hw/dmx/dmxinit.c b/hw/dmx/dmxinit.c index 7082e7969..be0f61476 100644 --- a/hw/dmx/dmxinit.c +++ b/hw/dmx/dmxinit.c @@ -295,12 +295,13 @@ Bool dmxOpenDisplay(DMXScreenInfo *dmxScreen) return FALSE; dmxScreen->alive = 1; + dmxScreen->inDispatch = FALSE; dmxScreen->fd = XConnectionNumber (dmxScreen->beDisplay); dmxScreen->connection = XGetXCBConnection (dmxScreen->beDisplay); XSetEventQueueOwner (dmxScreen->beDisplay, XCBOwnsEventQueue); - dmxScreen->syncCookie.sequence = 0; + dmxScreen->sync.sequence = 0; AddEnabledDevice (dmxScreen->fd); diff --git a/hw/dmx/dmxlaunch.c b/hw/dmx/dmxlaunch.c index 63bd572cb..6260d6621 100644 --- a/hw/dmx/dmxlaunch.c +++ b/hw/dmx/dmxlaunch.c @@ -68,8 +68,6 @@ static jmp_buf jumpbuf; static char **xbeArgv = 0; static int nXbeArgv = 0; -static int xbePriority = 0; - static int dmxAddXbeArguments (char **argv, int n) diff --git a/hw/dmx/dmxscrinit.c b/hw/dmx/dmxscrinit.c index 4eeda2abd..48e5fa8ce 100644 --- a/hw/dmx/dmxscrinit.c +++ b/hw/dmx/dmxscrinit.c @@ -315,6 +315,39 @@ dmxSetWindowPixmap (WindowPtr pWin, PixmapPtr pPixmap) DMX_WRAP(SetWindowPixmap, dmxSetWindowPixmap, dmxScreen, pScreen); } +static void +dmxDiscardIgnore (DMXScreenInfo *dmxScreen, + unsigned long sequence) +{ + while (dmxScreen->ignore.head) + { + if ((long) (sequence - dmxScreen->ignore.head->sequence) > 0) + { + DMXSequence *next = dmxScreen->ignore.head->next; + + free (dmxScreen->ignore.head); + + dmxScreen->ignore.head = next; + if (!dmxScreen->ignore.head) + dmxScreen->ignore.tail = &dmxScreen->ignore.head; + } + else + break; + } +} + +static Bool +dmxShouldIgnore (DMXScreenInfo *dmxScreen, + unsigned long sequence) +{ + dmxDiscardIgnore (dmxScreen, sequence); + + if (!dmxScreen->ignore.head) + return FALSE; + + return dmxScreen->ignore.head->sequence == sequence; +} + static Bool dmxScreenEventCheckExpose (ScreenPtr pScreen, xcb_generic_event_t *event) @@ -712,8 +745,15 @@ dmxScreenEventCheckIgnore (ScreenPtr pScreen, return FALSE; } +static Bool +dmxScreenReplyCheckIgnore (ScreenPtr pScreen, + xcb_generic_reply_t *reply) +{ + return FALSE; +} + static void -dmxScreenCheckForError (ScreenPtr pScreen) +dmxScreenCheckForIOError (ScreenPtr pScreen) { DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; @@ -723,7 +763,7 @@ dmxScreenCheckForError (ScreenPtr pScreen) dmxScreen->alive = FALSE; - dmxLogOutput (dmxScreen, "Detect broken connection\n"); + dmxLogOutput (dmxScreen, "Detected broken connection\n"); dmxDetachScreen (pScreen->myNum); for (i = 0; i < dmxNumScreens; i++) @@ -736,6 +776,69 @@ dmxScreenCheckForError (ScreenPtr pScreen) } } +void +dmxBEDispatch (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + xcb_generic_event_t *event; + xcb_generic_reply_t *reply; + + dmxScreen->inDispatch = TRUE; + + while ((event = xcb_poll_for_event (dmxScreen->connection))) + { + if (!dmxScreenEventCheckInput (pScreen, event) && + !dmxScreenEventCheckManageWindow (pScreen, event) && + !dmxScreenEventCheckExpose (pScreen, event) && + +#ifdef RANDR + !dmxScreenEventCheckRR (pScreen, event) && +#endif + + !dmxScreenEventCheckIgnore (pScreen, event)) + { + dmxLogOutput (dmxScreen, "unhandled event type %d\n", + event->response_type); + } + + free (event); + } + + while (dmxScreen->request.head && + xcb_poll_for_reply (dmxScreen->connection, + dmxScreen->request.head->sequence, + (void *) &reply, + NULL)) + { + DMXSequence *head = dmxScreen->request.head; + + if (reply) + { + if (!dmxScreenReplyCheckSync (pScreen, reply) && + !dmxScreenReplyCheckIgnore (pScreen, reply)) + { + dmxLogOutput (dmxScreen, + "unhandled reply sequence %d\n", + reply->sequence); + } + + free (reply); + } + else + { + dmxLogOutput (dmxScreen, "error sequence %d\n", head->sequence); + } + + dmxScreen->request.head = head->next; + if (!dmxScreen->request.head) + dmxScreen->request.tail = &dmxScreen->request.head; + + free (head); + } + + dmxScreen->inDispatch = FALSE; +} + static void dmxScreenBlockHandler (pointer blockData, OSTimePtr pTimeout, @@ -747,7 +850,7 @@ dmxScreenBlockHandler (pointer blockData, if (dmxScreen->beDisplay) { xcb_flush (dmxScreen->connection); - dmxScreenCheckForError (pScreen); + dmxScreenCheckForIOError (pScreen); } } @@ -760,28 +863,7 @@ dmxScreenWakeupHandler (pointer blockData, DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; if (dmxScreen->beDisplay) - { - xcb_generic_event_t *event; - - while ((event = xcb_poll_for_event (dmxScreen->connection))) - { - if (!dmxScreenEventCheckInput (pScreen, event) && - !dmxScreenEventCheckManageWindow (pScreen, event) && - !dmxScreenEventCheckExpose (pScreen, event) && - -#ifdef RANDR - !dmxScreenEventCheckRR (pScreen, event) && -#endif - - !dmxScreenEventCheckIgnore (pScreen, event)) - { - dmxLogOutput (dmxScreen, "unhandled event type %d\n", - event->response_type); - } - - free (event); - } - } + dmxBEDispatch (pScreen); } static void @@ -834,8 +916,11 @@ Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[]) dmxGeneration = serverGeneration; } - dmxScreen->ignoreHead = NULL; - dmxScreen->ignoreTail = &dmxScreen->ignoreHead; + dmxScreen->ignore.head = NULL; + dmxScreen->ignore.tail = &dmxScreen->ignore.head; + + dmxScreen->request.head = NULL; + dmxScreen->request.tail = &dmxScreen->request.head; #ifdef RANDR dmxScreen->beRandr = FALSE; @@ -1170,6 +1255,9 @@ void dmxBECloseScreen(ScreenPtr pScreen) /* Close display */ dmxCloseDisplay (dmxScreen); dmxScreen->beDisplay = NULL; + + dmxClearQueue (&dmxScreen->request); + dmxClearQueue (&dmxScreen->ignore); } /** Close screen number \a idx. */ @@ -1290,52 +1378,35 @@ static Bool dmxSaveScreen(ScreenPtr pScreen, int what) return TRUE; } -void -dmxDiscardIgnore (DMXScreenInfo *dmxScreen, - unsigned long sequence) -{ - while (dmxScreen->ignoreHead) - { - if ((long) (sequence - dmxScreen->ignoreHead->sequence) > 0) - { - DMXIgnore *next = dmxScreen->ignoreHead->next; - - free (dmxScreen->ignoreHead); - - dmxScreen->ignoreHead = next; - if (!dmxScreen->ignoreHead) - dmxScreen->ignoreTail = &dmxScreen->ignoreHead; - } - else - break; - } -} - -void -dmxSetIgnore (DMXScreenInfo *dmxScreen, - unsigned long sequence) -{ - DMXIgnore *i; - - i = malloc (sizeof (DMXIgnore)); - if (!i) - return; - - i->sequence = sequence; - i->next = 0; - - *(dmxScreen->ignoreTail) = i; - dmxScreen->ignoreTail = &i->next; -} - Bool -dmxShouldIgnore (DMXScreenInfo *dmxScreen, - unsigned long sequence) +dmxAddSequence (DMXQueue *q, + unsigned long sequence) { - dmxDiscardIgnore (dmxScreen, sequence); + DMXSequence *s; - if (!dmxScreen->ignoreHead) + s = malloc (sizeof (DMXSequence)); + if (!s) return FALSE; - return dmxScreen->ignoreHead->sequence == sequence; + s->sequence = sequence; + s->next = 0; + + *(q->tail) = s; + q->tail = &s->next; + + return TRUE; +} + +void +dmxClearQueue (DMXQueue *q) +{ + while (q->head) + { + DMXSequence *head = q->head; + + q->head = head->next; + free (head); + } + + q->tail = &q->head; } diff --git a/hw/dmx/dmxscrinit.h b/hw/dmx/dmxscrinit.h index 6bc540f02..8ba05a63c 100644 --- a/hw/dmx/dmxscrinit.h +++ b/hw/dmx/dmxscrinit.h @@ -47,9 +47,9 @@ extern Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[]); extern void dmxBEScreenInit(int idx, ScreenPtr pScreen); extern void dmxBECloseScreen(ScreenPtr pScreen); +extern void dmxBEDispatch (ScreenPtr pScreen); -extern void dmxDiscardIgnore (DMXScreenInfo *dmxScreen, unsigned long sequence); -extern void dmxSetIgnore (DMXScreenInfo *dmxScreen, unsigned long sequence); -extern Bool dmxShouldIgnore (DMXScreenInfo *dmxScreen, unsigned long sequence); +extern Bool dmxAddSequence (DMXQueue *q, unsigned long sequence); +extern void dmxClearQueue (DMXQueue *q); #endif /* DMXSCRINIT_H */ diff --git a/hw/dmx/dmxsync.c b/hw/dmx/dmxsync.c index 1f4326def..08cf15c49 100644 --- a/hw/dmx/dmxsync.c +++ b/hw/dmx/dmxsync.c @@ -55,42 +55,13 @@ #include "dmxstat.h" #include "dmxlog.h" #include "dmxextension.h" +#include "dmxscrinit.h" #include static int dmxSyncInterval = 100; /* Default interval in milliseconds */ static OsTimerPtr dmxSyncTimer; static int dmxSyncPending = 0; -static int dmxSyncCookie = 0; - -static void dmxWaitSync(DMXScreenInfo *dmxScreen) -{ - if (dmxScreen->syncCookie.sequence) - { - if (dmxScreen->beDisplay) - { - if (!dmxStatInterval) { - XLIB_PROLOGUE (dmxScreen); - free (xcb_get_input_focus_reply (dmxScreen->connection, - dmxScreen->syncCookie, - NULL)); - XLIB_EPILOGUE (dmxScreen); - } else { - struct timeval start, stop; - - gettimeofday(&start, 0); - XLIB_PROLOGUE (dmxScreen); - free (xcb_get_input_focus_reply (dmxScreen->connection, - dmxScreen->syncCookie, - NULL)); - XLIB_EPILOGUE (dmxScreen); - gettimeofday(&stop, 0); - dmxStatSync(dmxScreen, &stop, &start, dmxSyncPending); - } - } - - dmxScreen->syncCookie.sequence = 0; - } -} +static int dmxSyncRequest = 0; static void dmxDoSync(DMXScreenInfo *dmxScreen) { @@ -98,33 +69,86 @@ static void dmxDoSync(DMXScreenInfo *dmxScreen) if (!dmxScreen->beDisplay) { - dmxScreen->syncCookie.sequence = 0; + dmxScreen->sync.sequence = 0; return; /* FIXME: Is this correct behavior for sync stats? */ } - dmxScreen->syncCookie = - xcb_get_input_focus_unchecked (dmxScreen->connection); + if (dmxScreen->sync.sequence) + return; - dmxSyncCookie++; + dmxScreen->sync = xcb_get_input_focus_unchecked (dmxScreen->connection); + dmxAddSequence (&dmxScreen->request, dmxScreen->sync.sequence); + dmxSyncRequest++; } static CARD32 dmxSyncCallback(OsTimerPtr timer, CARD32 time, pointer arg) { int i; - if (dmxSyncCookie) { + while (dmxSyncRequest) + { + fd_set rfds; + int ret, fd = 0; + + /* timer expired and there is pending sync replies that need + to be waited for before we can allow further processing + of client requests */ + + FD_ZERO (&rfds); + for (i = 0; i < dmxNumScreens; i++) - if (dmxScreens[i].syncCookie.sequence) dmxWaitSync(&dmxScreens[i]); - dmxSyncCookie = 0; + { + if (dmxScreens[i].beDisplay) + { + xcb_flush (dmxScreens[i].connection); + if (xcb_connection_has_error (dmxScreens[i].connection)) + { + if (dmxScreens[i].sync.sequence) + { + dmxScreens[i].sync.sequence = 0; + dmxSyncRequest--; + } + } + else + { + FD_SET (dmxScreens[i].fd, &rfds); + + if (dmxScreens[i].fd > fd) + fd = dmxScreens[i].fd; + } + } + } + + if (fd) + { + do { + ret = select (fd + 1, &rfds, 0, 0, 0); + } while (ret == -1 && errno == EINTR); + } + + dmxSyncPending++; + + for (i = 0; i < dmxNumScreens; i++) + if (dmxScreens[i].beDisplay) + dmxBEDispatch (screenInfo.screens[i]); + + dmxSyncPending--; } - if (dmxSyncPending) { + if (dmxSyncPending) + { for (i = 0; i < dmxNumScreens; i++) - if (dmxScreens[i].needsSync) dmxDoSync(&dmxScreens[i]); + if (dmxScreens[i].needsSync) + dmxDoSync (&dmxScreens[i]); + dmxSyncPending = 0; - if (dmxSyncCookie) + + if (dmxSyncRequest) return dmxSyncInterval; } + + dmxSyncTimer = NULL; + return 0; /* Do not place on queue again */ } @@ -185,34 +209,81 @@ void dmxSync(DMXScreenInfo *dmxScreen, Bool now) now = TRUE; dmxGeneration = serverGeneration; } - /* Queue sync */ + + /* Queue sync */ if (dmxScreen) { + if (now && dmxScreen->inDispatch) + { + dmxLog (dmxWarning, + "Immediate sync from within back-end dispatch\n"); + free (xcb_get_input_focus_reply + (dmxScreen->connection, + xcb_get_input_focus_unchecked (dmxScreen->connection), + NULL)); + return; + } dmxScreen->needsSync = TRUE; ++dmxSyncPending; } - /* Do sync or set time for later */ - if (now || !dmxScreen) { - if (!TimerForce(dmxSyncTimer)) dmxSyncCallback(NULL, 0, NULL); + /* Do sync or set time for later */ + if (now || !dmxScreen) + { + if (dmxSyncTimer) + { + TimerFree (dmxSyncTimer); + dmxSyncTimer = NULL; + } + + while (dmxSyncRequest || dmxSyncPending) + dmxSyncCallback (NULL, 0, NULL); /* At this point, dmxSyncPending == 0 because * dmxSyncCallback must have been called. */ if (dmxSyncPending) dmxLog(dmxFatal, "dmxSync(%s,%d): dmxSyncPending = %d\n", dmxScreen ? dmxScreen->display : "", now, dmxSyncPending); - } else { - if (dmxSyncCookie == 0 && dmxSyncPending == 1) - dmxSyncTimer = TimerSet(dmxSyncTimer, 0, dmxSyncInterval, - dmxSyncCallback, NULL); } - } else { - /* If dmxSyncInterval is not being used, - * then all the backends are already - * up-to-date. */ + else if (!dmxSyncTimer) + { + dmxSyncTimer = TimerSet(dmxSyncTimer, 0, dmxSyncInterval, + dmxSyncCallback, NULL); + } + } + else + { + /* If dmxSyncInterval is not being used, + * then all the backends are already + * up-to-date. */ if (dmxScreen) { dmxDoSync(dmxScreen); - dmxWaitSync(dmxScreen); + dmxSyncCallback(NULL, 0, NULL); } } } + +Bool +dmxScreenReplyCheckSync (ScreenPtr pScreen, + xcb_generic_reply_t *reply) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (reply->sequence != dmxScreen->sync.sequence) + return FALSE; + + dmxScreen->sync.sequence = 0; + + dmxSyncRequest--; + if (dmxSyncRequest == 0) + { + if (dmxSyncPending == 0) + { + TimerFree (dmxSyncTimer); + dmxSyncTimer = NULL; + } + } + + return TRUE; +} + diff --git a/hw/dmx/dmxsync.h b/hw/dmx/dmxsync.h index b80f54af2..e7575d558 100644 --- a/hw/dmx/dmxsync.h +++ b/hw/dmx/dmxsync.h @@ -40,4 +40,6 @@ extern void dmxSyncActivate(const char *interval); extern void dmxSyncInit(void); extern void dmxSync(DMXScreenInfo *dmxScreen, Bool now); +extern Bool dmxScreenReplyCheckSync (ScreenPtr pScreen, + xcb_generic_reply_t *reply); #endif diff --git a/hw/dmx/dmxwindow.c b/hw/dmx/dmxwindow.c index 7eb5ab9e1..f8828bf74 100644 --- a/hw/dmx/dmxwindow.c +++ b/hw/dmx/dmxwindow.c @@ -179,6 +179,11 @@ void dmxResizeScreenWindow(ScreenPtr pScreen, dmxSync(dmxScreen, False); } +static void dmxSetIgnore (DMXScreenInfo *dmxScreen, unsigned int sequence) +{ + dmxAddSequence (&dmxScreen->ignore, sequence); +} + /** Change the location and size of the "root" window. Called from * #dmxReconfigureRootWindow(). */ void dmxResizeRootWindow(WindowPtr pRoot,