First import
[xorg_rtime.git] / xorg-server-1.4 / hw / dmx / dmxsync.c
blobc1aa43107f40aba3dbcf28b34019ec369371daa8
1 /*
2 * Copyright 2002-2004 Red Hat Inc., Durham, North Carolina.
4 * All Rights Reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation on the rights to use, copy, modify, merge,
10 * publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
29 * Authors:
30 * Rickard E. (Rik) Faith <faith@redhat.com>
34 /** \file
36 * The DMX server code is written to call #dmxSync() whenever an XSync()
37 * might be necessary. However, since XSync() requires a two way
38 * communication with the other X server, eliminating unnecessary
39 * XSync() calls is a key performance optimization. Support for this
40 * optimization is provided here. Statistics about XSync() calls and
41 * latency are gathered in #dmxstat.c.
43 * During the initial conversion from calling XSync() immediately to the
44 * XSync() batching method implemented in this file, it was noted that,
45 * out of more than 300 \a x11perf tests, 8 tests became more than 100
46 * times faster, with 68 more than 50X faster, 114 more than 10X faster,
47 * and 181 more than 2X faster. */
49 #ifdef HAVE_DMX_CONFIG_H
50 #include <dmx-config.h>
51 #endif
53 #include "dmx.h"
54 #include "dmxsync.h"
55 #include "dmxstat.h"
56 #include "dmxlog.h"
57 #include <sys/time.h>
59 static int dmxSyncInterval = 100; /* Default interval in milliseconds */
60 static OsTimerPtr dmxSyncTimer;
61 static int dmxSyncPending;
63 static void dmxDoSync(DMXScreenInfo *dmxScreen)
65 dmxScreen->needsSync = FALSE;
67 if (!dmxScreen->beDisplay)
68 return; /* FIXME: Is this correct behavior for sync stats? */
70 if (!dmxStatInterval) {
71 XSync(dmxScreen->beDisplay, False);
72 } else {
73 struct timeval start, stop;
75 gettimeofday(&start, 0);
76 XSync(dmxScreen->beDisplay, False);
77 gettimeofday(&stop, 0);
78 dmxStatSync(dmxScreen, &stop, &start, dmxSyncPending);
82 static CARD32 dmxSyncCallback(OsTimerPtr timer, CARD32 time, pointer arg)
84 int i;
86 if (dmxSyncPending) {
87 for (i = 0; i < dmxNumScreens; i++) {
88 DMXScreenInfo *dmxScreen = &dmxScreens[i];
89 if (dmxScreen->needsSync) dmxDoSync(dmxScreen);
92 dmxSyncPending = 0;
93 return 0; /* Do not place on queue again */
96 static void dmxSyncBlockHandler(pointer blockData, OSTimePtr pTimeout,
97 pointer pReadMask)
99 TimerForce(dmxSyncTimer);
102 static void dmxSyncWakeupHandler(pointer blockData, int result,
103 pointer pReadMask)
107 /** Request the XSync() batching optimization with the specified \a
108 * interval (in mS). If the \a interval is 0, 100mS is used. If the \a
109 * interval is less than 0, then the XSync() batching optimization is
110 * not requested (e.g., so the -syncbatch -1 command line option can
111 * turn off the default 100mS XSync() batching).
113 * Note that the parameter to this routine is a string, since it will
114 * usually be called from #ddxProcessArgument in #dmxinit.c */
115 void dmxSyncActivate(const char *interval)
117 dmxSyncInterval = (interval ? atoi(interval) : 100);
119 if (dmxSyncInterval < 0) dmxSyncInterval = 0;
122 /** Initialize the XSync() batching optimization, but only if
123 * #dmxSyncActivate was last called with a non-negative value. */
124 void dmxSyncInit(void)
126 if (dmxSyncInterval) {
127 RegisterBlockAndWakeupHandlers(dmxSyncBlockHandler,
128 dmxSyncWakeupHandler,
129 NULL);
130 dmxLog(dmxInfo, "XSync batching with %d ms interval\n",
131 dmxSyncInterval);
132 } else {
133 dmxLog(dmxInfo, "XSync batching disabled\n");
137 /** Request an XSync() to the display used by \a dmxScreen. If \a now
138 * is TRUE, call XSync() immediately instead of waiting for the next
139 * XSync() batching point. Note that if XSync() batching was deselected
140 * with #dmxSyncActivate() before #dmxSyncInit() was called, then no
141 * XSync() batching is performed and this function always calles XSync()
142 * immediately.
144 * (Note that this function uses TimerSet but works correctly in the
145 * face of a server generation. See the source for details.)
147 * If \a dmxScreen is \a NULL, then all pending syncs will be flushed
148 * immediately.
150 void dmxSync(DMXScreenInfo *dmxScreen, Bool now)
152 static unsigned long dmxGeneration = 0;
154 if (dmxSyncInterval) {
155 if (dmxGeneration != serverGeneration) {
156 /* Server generation does a TimerInit, which frees all
157 * timers. So, at this point dmxSyncTimer is either:
158 * 1) NULL, iff dmxGeneration == 0,
159 * 2) freed, if it was on a queue (dmxSyncPending != 0), or
160 * 3) allocated, if it wasn't on a queue (dmxSyncPending == 0)
162 if (dmxSyncTimer && !dmxSyncPending) xfree(dmxSyncTimer);
163 dmxSyncTimer = NULL;
164 now = TRUE;
165 dmxGeneration = serverGeneration;
167 /* Queue sync */
168 if (dmxScreen) {
169 dmxScreen->needsSync = TRUE;
170 ++dmxSyncPending;
173 /* Do sync or set time for later */
174 if (now || !dmxScreen) {
175 if (!TimerForce(dmxSyncTimer)) dmxSyncCallback(NULL, 0, NULL);
176 /* At this point, dmxSyncPending == 0 because
177 * dmxSyncCallback must have been called. */
178 if (dmxSyncPending)
179 dmxLog(dmxFatal, "dmxSync(%s,%d): dmxSyncPending = %d\n",
180 dmxScreen ? dmxScreen->name : "", now, dmxSyncPending);
181 } else {
182 dmxScreen->needsSync = TRUE;
183 if (dmxSyncPending == 1)
184 dmxSyncTimer = TimerSet(dmxSyncTimer, 0, dmxSyncInterval,
185 dmxSyncCallback, NULL);
187 } else {
188 /* If dmxSyncInterval is not being used,
189 * then all the backends are already
190 * up-to-date. */
191 if (dmxScreen) dmxDoSync(dmxScreen);