Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / dmx / dmxsync.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright 2002-2004 Red Hat Inc., Durham, North Carolina.
3 *
4 * All Rights Reserved.
5 *
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:
13 *
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.
17 *
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.
26 */
27
28/*
29 * Authors:
30 * Rickard E. (Rik) Faith <faith@redhat.com>
31 *
32 */
33
34/** \file
35 *
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 \a dmxstat.c.
42 *
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. */
48
49#ifdef HAVE_DMX_CONFIG_H
50#include <dmx-config.h>
51#endif
52
53#include "dmx.h"
54#include "dmxsync.h"
55#include "dmxstat.h"
56#include "dmxlog.h"
57#include <sys/time.h>
58
59static int dmxSyncInterval = 100; /* Default interval in milliseconds */
60static OsTimerPtr dmxSyncTimer;
61static int dmxSyncPending;
62
63static void
64dmxDoSync(DMXScreenInfo * dmxScreen)
65{
66 dmxScreen->needsSync = FALSE;
67
68 if (!dmxScreen->beDisplay)
69 return; /* FIXME: Is this correct behavior for sync stats? */
70
71 if (!dmxStatInterval) {
72 XSync(dmxScreen->beDisplay, False);
73 }
74 else {
75 struct timeval start, stop;
76
77 gettimeofday(&start, 0);
78 XSync(dmxScreen->beDisplay, False);
79 gettimeofday(&stop, 0);
80 dmxStatSync(dmxScreen, &stop, &start, dmxSyncPending);
81 }
82}
83
84static CARD32
85dmxSyncCallback(OsTimerPtr timer, CARD32 time, pointer arg)
86{
87 int i;
88
89 if (dmxSyncPending) {
90 for (i = 0; i < dmxNumScreens; i++) {
91 DMXScreenInfo *dmxScreen = &dmxScreens[i];
92
93 if (dmxScreen->needsSync)
94 dmxDoSync(dmxScreen);
95 }
96 }
97 dmxSyncPending = 0;
98 return 0; /* Do not place on queue again */
99}
100
101static void
102dmxSyncBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadMask)
103{
104 TimerForce(dmxSyncTimer);
105}
106
107static void
108dmxSyncWakeupHandler(pointer blockData, int result, pointer pReadMask)
109{
110}
111
112/** Request the XSync() batching optimization with the specified \a
113 * interval (in mS). If the \a interval is 0, 100mS is used. If the \a
114 * interval is less than 0, then the XSync() batching optimization is
115 * not requested (e.g., so the -syncbatch -1 command line option can
116 * turn off the default 100mS XSync() batching).
117 *
118 * Note that the parameter to this routine is a string, since it will
119 * usually be called from #ddxProcessArgument in \a dmxinit.c */
120void
121dmxSyncActivate(const char *interval)
122{
123 dmxSyncInterval = (interval ? atoi(interval) : 100);
124
125 if (dmxSyncInterval < 0)
126 dmxSyncInterval = 0;
127}
128
129/** Initialize the XSync() batching optimization, but only if
130 * #dmxSyncActivate was last called with a non-negative value. */
131void
132dmxSyncInit(void)
133{
134 if (dmxSyncInterval) {
135 RegisterBlockAndWakeupHandlers(dmxSyncBlockHandler,
136 dmxSyncWakeupHandler, NULL);
137 dmxLog(dmxInfo, "XSync batching with %d ms interval\n",
138 dmxSyncInterval);
139 }
140 else {
141 dmxLog(dmxInfo, "XSync batching disabled\n");
142 }
143}
144
145/** Request an XSync() to the display used by \a dmxScreen. If \a now
146 * is TRUE, call XSync() immediately instead of waiting for the next
147 * XSync() batching point. Note that if XSync() batching was deselected
148 * with #dmxSyncActivate() before #dmxSyncInit() was called, then no
149 * XSync() batching is performed and this function always calles XSync()
150 * immediately.
151 *
152 * (Note that this function uses TimerSet but works correctly in the
153 * face of a server generation. See the source for details.)
154 *
155 * If \a dmxScreen is \a NULL, then all pending syncs will be flushed
156 * immediately.
157 */
158void
159dmxSync(DMXScreenInfo * dmxScreen, Bool now)
160{
161 static unsigned long dmxGeneration = 0;
162
163 if (dmxSyncInterval) {
164 if (dmxGeneration != serverGeneration) {
165 /* Server generation does a TimerInit, which frees all
166 * timers. So, at this point dmxSyncTimer is either:
167 * 1) NULL, iff dmxGeneration == 0,
168 * 2) freed, if it was on a queue (dmxSyncPending != 0), or
169 * 3) allocated, if it wasn't on a queue (dmxSyncPending == 0)
170 */
171 if (dmxSyncTimer && !dmxSyncPending)
172 free(dmxSyncTimer);
173 dmxSyncTimer = NULL;
174 now = TRUE;
175 dmxGeneration = serverGeneration;
176 }
177 /* Queue sync */
178 if (dmxScreen) {
179 dmxScreen->needsSync = TRUE;
180 ++dmxSyncPending;
181 }
182
183 /* Do sync or set time for later */
184 if (now || !dmxScreen) {
185 if (!TimerForce(dmxSyncTimer))
186 dmxSyncCallback(NULL, 0, NULL);
187 /* At this point, dmxSyncPending == 0 because
188 * dmxSyncCallback must have been called. */
189 if (dmxSyncPending)
190 dmxLog(dmxFatal, "dmxSync(%s,%d): dmxSyncPending = %d\n",
191 dmxScreen ? dmxScreen->name : "", now, dmxSyncPending);
192 }
193 else {
194 dmxScreen->needsSync = TRUE;
195 if (dmxSyncPending == 1)
196 dmxSyncTimer = TimerSet(dmxSyncTimer, 0, dmxSyncInterval,
197 dmxSyncCallback, NULL);
198 }
199 }
200 else {
201 /* If dmxSyncInterval is not being used,
202 * then all the backends are already
203 * up-to-date. */
204 if (dmxScreen)
205 dmxDoSync(dmxScreen);
206 }
207}