OLD | NEW |
| (Empty) |
1 From 0f70ba9d3412b17ac4e08e33e1be3c226c06ea54 Mon Sep 17 00:00:00 2001 | |
2 From: Yan Li <yan.i.li@intel.com> | |
3 Date: Tue, 12 May 2009 17:49:07 +0800 | |
4 Subject: [PATCH] XKB: cache xkbcomp output for fast start-up v5 for 1.6.1 | |
5 Organization: Intel | |
6 | |
7 xkbcomp outputs will be cached in files with hashed keymap as | |
8 names. This saves boot time for around 1s on commodity netbooks. | |
9 | |
10 Signed-off-by: Yan Li <yan.i.li@intel.com> | |
11 --- | |
12 configure.ac | 6 +- | |
13 xkb/README.compiled | 8 +- | |
14 xkb/ddxLoad.c | 192 +++++++++++++++++++++++++++++++++++++++++--------- | |
15 3 files changed, 164 insertions(+), 42 deletions(-) | |
16 | |
17 diff --git a/configure.ac b/configure.ac | |
18 index 4c4c797..7a5020a 100644 | |
19 --- a/configure.ac | |
20 +++ b/configure.ac | |
21 @@ -476,9 +476,9 @@ AC_ARG_WITH(default-font-path, AS_HELP_STRING([--with-defaul
t-font-path=PATH], [ | |
22 AC_ARG_WITH(xkb-path, AS_HELP_STRING([--with-xkb-path=PATH], [Path to X
KB base dir (default: ${datadir}/X11/xkb)]), | |
23 [ XKBPATH="$withval" ], | |
24 [ XKBPATH="${datadir}/X11/xkb" ]) | |
25 -AC_ARG_WITH(xkb-output, AS_HELP_STRING([--with-xkb-output=PATH], [Path to
XKB output dir (default: ${datadir}/X11/xkb/compiled)]), | |
26 +AC_ARG_WITH(xkb-output, AS_HELP_STRING([--with-xkb-output=PATH], [Path to
XKB output dir (default: ${localstatedir}/cache/xkb)]), | |
27 [ XKBOUTPUT="$withval" ], | |
28 - [ XKBOUTPUT="compiled" ]) | |
29 + [ XKBOUTPUT="${localstatedir}/cache/xkb" ]) | |
30 AC_ARG_WITH(serverconfig-path, AS_HELP_STRING([--with-serverconfig-path=PATH], | |
31 [Directory where ancillary server config file
s are installed (default: ${libdir}/xorg)]), | |
32 [ SERVERCONFIG="$withval" ], | |
33 @@ -1757,7 +1757,7 @@ AC_DEFINE_DIR(XKB_BIN_DIRECTORY, bindir, [Path to XKB bin
dir]) | |
34 XKBOUTPUT_FIRSTCHAR=`echo $XKBOUTPUT | cut -b 1` | |
35 | |
36 if [[ x$XKBOUTPUT_FIRSTCHAR != x/ ]] ; then | |
37 - XKBOUTPUT="$XKB_BASE_DIRECTORY/$XKBOUTPUT" | |
38 + AC_MSG_ERROR([xkb-output must be an absolute path.]) | |
39 fi | |
40 | |
41 # XKM_OUTPUT_DIR (used in code) must end in / or file names get hosed | |
42 diff --git a/xkb/README.compiled b/xkb/README.compiled | |
43 index 71caa2f..a4a2ae0 100644 | |
44 --- a/xkb/README.compiled | |
45 +++ b/xkb/README.compiled | |
46 @@ -4,10 +4,10 @@ current keymap and/or any scratch keymaps used by clients. Th
e X server | |
47 or some other tool might destroy or replace the files in this directory, | |
48 so it is not a safe place to store compiled keymaps for long periods of | |
49 time. The default keymap for any server is usually stored in: | |
50 - X<num>-default.xkm | |
51 -where <num> is the display number of the server in question, which makes | |
52 -it possible for several servers *on the same host* to share the same | |
53 -directory. | |
54 + server-<SHA1>.xkm | |
55 + | |
56 +where <SHA1> is the SHA1 hash of keymap source, so that compiled | |
57 +keymap of different keymap sources are stored in different files. | |
58 | |
59 Unless the X server is modified, sharing this directory between servers on | |
60 different hosts could cause problems. | |
61 diff --git a/xkb/ddxLoad.c b/xkb/ddxLoad.c | |
62 index 4d5dfb6..60a68af 100644 | |
63 --- a/xkb/ddxLoad.c | |
64 +++ b/xkb/ddxLoad.c | |
65 @@ -32,6 +32,12 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
66 #include <xkb-config.h> | |
67 #endif | |
68 | |
69 +#ifdef HAVE_SHA1_IN_LIBMD /* Use libmd for SHA1 */ | |
70 +# include <sha1.h> | |
71 +#else /* Use OpenSSL's libcrypto */ | |
72 +# include <stddef.h> /* buggy openssl/sha.h wants size_t */ | |
73 +# include <openssl/sha.h> | |
74 +#endif | |
75 #include <stdio.h> | |
76 #include <ctype.h> | |
77 #define NEED_EVENTS 1 | |
78 @@ -46,24 +52,13 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
79 #define XKBSRV_NEED_FILE_FUNCS | |
80 #include <xkbsrv.h> | |
81 #include <X11/extensions/XI.h> | |
82 +#include <errno.h> | |
83 #include "xkb.h" | |
84 | |
85 #if defined(CSRG_BASED) || defined(linux) || defined(__GNU__) | |
86 #include <paths.h> | |
87 #endif | |
88 | |
89 - /* | |
90 - * If XKM_OUTPUT_DIR specifies a path without a leading slash, it is | |
91 - * relative to the top-level XKB configuration directory. | |
92 - * Making the server write to a subdirectory of that directory | |
93 - * requires some work in the general case (install procedure | |
94 - * has to create links to /var or somesuch on many machines), | |
95 - * so we just compile into /usr/tmp for now. | |
96 - */ | |
97 -#ifndef XKM_OUTPUT_DIR | |
98 -#define XKM_OUTPUT_DIR "compiled/" | |
99 -#endif | |
100 - | |
101 #define PRE_ERROR_MSG "\"The XKEYBOARD keymap compiler (xkbcomp) reports
:\"" | |
102 #define ERROR_PREFIX "\"> \"" | |
103 #define POST_ERROR_MSG1 "\"Errors from xkbcomp are not fatal to the X se
rver\"" | |
104 @@ -179,6 +174,45 @@ OutputDirectory( | |
105 } | |
106 | |
107 static Bool | |
108 +Sha1Asc(char sha1Asc[SHA_DIGEST_LENGTH*2+1], const char * input) | |
109 +{ | |
110 + int i; | |
111 + unsigned char sha1[SHA_DIGEST_LENGTH]; | |
112 + | |
113 +#ifdef HAVE_SHA1_IN_LIBMD /* Use libmd for SHA1 */ | |
114 + SHA1_CTX ctx; | |
115 + | |
116 + SHA1Init (&ctx); | |
117 + SHA1Update (&ctx, input, strlen(input)); | |
118 + SHA1Final (sha1, &ctx); | |
119 +#else /* Use OpenSSL's libcrypto */ | |
120 + SHA_CTX ctx; | |
121 + int success; | |
122 + | |
123 + success = SHA1_Init (&ctx); | |
124 + if (! success) | |
125 + return BadAlloc; | |
126 + | |
127 + success = SHA1_Update (&ctx, input, strlen(input)); | |
128 + if (! success) | |
129 + return BadAlloc; | |
130 + | |
131 + success = SHA1_Final (sha1, &ctx); | |
132 + if (! success) | |
133 + return BadAlloc; | |
134 +#endif | |
135 + | |
136 + /* convert sha1 to sha1_asc */ | |
137 + for(i=0; i<SHA_DIGEST_LENGTH; ++i) { | |
138 + sprintf(sha1Asc+i*2, "%02X", sha1[i]); | |
139 + } | |
140 + | |
141 + return Success; | |
142 +} | |
143 + | |
144 +/* call xkbcomp and compile XKB keymap, return xkm file name in | |
145 + nameRtrn */ | |
146 +static Bool | |
147 XkbDDXCompileKeymapByNames( XkbDescPtr xkb, | |
148 XkbComponentNamesPtr names, | |
149 unsigned want, | |
150 @@ -187,7 +221,11 @@ XkbDDXCompileKeymapByNames( XkbDescPtr
xkb, | |
151 int nameRtrnLen) | |
152 { | |
153 FILE * out; | |
154 - char *buf = NULL, keymap[PATH_MAX], xkm_output_dir[PATH_MAX]; | |
155 + char * buf = NULL, xkmfile[PATH_MAX], xkm_output_dir[PATH_MAX]; | |
156 + char * tmpXkmFile = NULL; | |
157 + char * canonicalXkmFileName = NULL; | |
158 + char sha1Asc[SHA_DIGEST_LENGTH*2+1], xkbKeyMapBuf[100*1024]; | |
159 + int ret, result; | |
160 | |
161 const char *emptystring = ""; | |
162 const char *xkbbasedirflag = emptystring; | |
163 @@ -198,16 +236,70 @@ XkbDDXCompileKeymapByNames( XkbDescPtr
xkb, | |
164 /* WIN32 has no popen. The input must be stored in a file which is | |
165 used as input for xkbcomp. xkbcomp does not read from stdin. */ | |
166 char tmpname[PATH_MAX]; | |
167 - const char *xkmfile = tmpname; | |
168 + const char *xkbfile = tmpname; | |
169 #else | |
170 - const char *xkmfile = "-"; | |
171 + const char *xkbfile = "-"; | |
172 #endif | |
173 | |
174 - snprintf(keymap, sizeof(keymap), "server-%s", display); | |
175 + /* Write keymap source (xkbfile) to memory buffer `xkbKeyMapBuf', | |
176 + of which SHA1 is generated and used as result xkm file name */ | |
177 + memset(xkbKeyMapBuf, 0, sizeof(xkbKeyMapBuf)); | |
178 + out = fmemopen(xkbKeyMapBuf, sizeof(xkbKeyMapBuf), "w"); | |
179 + if (NULL == out) { | |
180 + ErrorF("[xkb] Open xkbKeyMapBuf for writing failed\n"); | |
181 + return False; | |
182 + } | |
183 + ret = XkbWriteXKBKeymapForNames(out, names, xkb, want, need); | |
184 + if (fclose(out) !=0) | |
185 + { | |
186 + ErrorF("[xkb] XkbWriteXKBKeymapForNames error, perhaps xkbKeyMapBuf is
too small\n"); | |
187 + return False; | |
188 + } | |
189 +#ifdef DEBUG | |
190 + if (xkbDebugFlags) { | |
191 + ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n"); | |
192 + fputs(xkbKeyMapBuf, stderr); | |
193 + } | |
194 +#endif | |
195 + if (!ret) { | |
196 + ErrorF("[xkb] Generating XKB Keymap failed, giving up compiling keymap\
n"); | |
197 + return False; | |
198 + } | |
199 + | |
200 + DebugF("[xkb] computing SHA1 of keymap\n"); | |
201 + if (Success == Sha1Asc(sha1Asc, xkbKeyMapBuf)) { | |
202 + snprintf(xkmfile, sizeof(xkmfile), "server-%s", sha1Asc); | |
203 + } | |
204 + else { | |
205 + ErrorF("[xkb] Computing SHA1 of keymap failed, " | |
206 + "using display name instead as xkm file name\n"); | |
207 + snprintf(xkmfile, sizeof(xkmfile), "server-%s", display); | |
208 + } | |
209 | |
210 - XkbEnsureSafeMapName(keymap); | |
211 + XkbEnsureSafeMapName(xkmfile); | |
212 OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir)); | |
213 | |
214 + /* set nameRtrn, fail if it's too small */ | |
215 + if ((strlen(xkmfile)+1 > nameRtrnLen) && nameRtrn) { | |
216 + ErrorF("[xkb] nameRtrn too small to hold xkmfile name\n"); | |
217 + return False; | |
218 + } | |
219 + strncpy(nameRtrn, xkmfile, nameRtrnLen); | |
220 + | |
221 + /* if the xkm file already exists, reuse it */ | |
222 + canonicalXkmFileName = Xprintf("%s%s.xkm", xkm_output_dir, xkmfile); | |
223 + if (access(canonicalXkmFileName, R_OK) == 0) { | |
224 + /* yes, we can reuse the old xkm file */ | |
225 + LogMessage(X_INFO, "XKB: reuse xkmfile %s\n", canonicalXkmFileName); | |
226 + result = True; | |
227 + goto _ret; | |
228 + } | |
229 + LogMessage(X_INFO, "XKB: generating xkmfile %s\n", canonicalXkmFileName); | |
230 + | |
231 + /* continue to call xkbcomp to compile the keymap. to avoid race | |
232 + condition, we compile it to a tmpfile then rename it to | |
233 + xkmfile */ | |
234 + | |
235 #ifdef WIN32 | |
236 strcpy(tmpname, Win32TempDir()); | |
237 strcat(tmpname, "\\xkb_XXXXXX"); | |
238 @@ -230,19 +322,30 @@ XkbDDXCompileKeymapByNames( XkbDescPtr
xkb, | |
239 } | |
240 } | |
241 | |
242 + if ( (tmpXkmFile = tempnam(xkm_output_dir, NULL)) == NULL ) { | |
243 + ErrorF("[xkb] Can't generate temp xkm file name"); | |
244 + result = False; | |
245 + goto _ret; | |
246 + } | |
247 + | |
248 buf = Xprintf("\"%s%sxkbcomp\" -w %d %s -xkm \"%s\" " | |
249 - "-em1 %s -emp %s -eml %s \"%s%s.xkm\"", | |
250 + "-em1 %s -emp %s -eml %s \"%s\"", | |
251 xkbbindir, xkbbindirsep, | |
252 ( (xkbDebugFlags < 2) ? 1 : | |
253 ((xkbDebugFlags > 10) ? 10 : (int)xkbDebugFlags) ), | |
254 - xkbbasedirflag, xkmfile, | |
255 + xkbbasedirflag, xkbfile, | |
256 PRE_ERROR_MSG, ERROR_PREFIX, POST_ERROR_MSG1, | |
257 - xkm_output_dir, keymap); | |
258 + tmpXkmFile); | |
259 | |
260 if (xkbbasedirflag != emptystring) { | |
261 xfree(xkbbasedirflag); | |
262 } | |
263 | |
264 + /* there's a potential race condition between calling tempnam() | |
265 + and invoking xkbcomp to write the result file (potential temp | |
266 + file name conflicts), but since xkbcomp is a standalone | |
267 + program, we have to live with this */ | |
268 + | |
269 #ifndef WIN32 | |
270 out= Popen(buf,"w"); | |
271 #else | |
272 @@ -250,31 +353,43 @@ XkbDDXCompileKeymapByNames( XkbDescPtr
xkb, | |
273 #endif | |
274 | |
275 if (out!=NULL) { | |
276 -#ifdef DEBUG | |
277 - if (xkbDebugFlags) { | |
278 - ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n"); | |
279 - XkbWriteXKBKeymapForNames(stderr,names,xkb,want,need); | |
280 + /* write XKBKeyMapBuf to xkbcomp */ | |
281 + if (EOF==fputs(xkbKeyMapBuf, out)) | |
282 + { | |
283 + ErrorF("[xkb] Sending keymap to xkbcomp failed\n"); | |
284 + result = False; | |
285 + goto _ret; | |
286 } | |
287 -#endif | |
288 - XkbWriteXKBKeymapForNames(out,names,xkb,want,need); | |
289 #ifndef WIN32 | |
290 if (Pclose(out)==0) | |
291 #else | |
292 if (fclose(out)==0 && System(buf) >= 0) | |
293 #endif | |
294 { | |
295 + /* xkbcomp success */ | |
296 if (xkbDebugFlags) | |
297 DebugF("[xkb] xkb executes: %s\n",buf); | |
298 - if (nameRtrn) { | |
299 - strncpy(nameRtrn,keymap,nameRtrnLen); | |
300 - nameRtrn[nameRtrnLen-1]= '\0'; | |
301 + | |
302 + /* if canonicalXkmFileName already exists now, we simply | |
303 + overwrite it, this is OK */ | |
304 + ret = rename(tmpXkmFile, canonicalXkmFileName); | |
305 + if (0 != ret) { | |
306 + ErrorF("[xkb] Can't rename %s to %s, error: %s\n", | |
307 + tmpXkmFile, canonicalXkmFileName, | |
308 + strerror(errno)); | |
309 + | |
310 + /* in case of error, don't unlink tmpXkmFile, leave it | |
311 + for debugging */ | |
312 + | |
313 + result = False; | |
314 + goto _ret; | |
315 } | |
316 - if (buf != NULL) | |
317 - xfree (buf); | |
318 - return True; | |
319 + | |
320 + result = True; | |
321 + goto _ret; | |
322 } | |
323 else | |
324 - LogMessage(X_ERROR, "Error compiling keymap (%s)\n", keymap); | |
325 + LogMessage(X_ERROR, "Error compiling keymap (%s)\n", xkbfile); | |
326 #ifdef WIN32 | |
327 /* remove the temporary file */ | |
328 unlink(tmpname); | |
329 @@ -289,9 +404,17 @@ XkbDDXCompileKeymapByNames( XkbDescPtr
xkb, | |
330 } | |
331 if (nameRtrn) | |
332 nameRtrn[0]= '\0'; | |
333 + result = False; | |
334 + | |
335 +_ret: | |
336 + if (tmpXkmFile) | |
337 + free(tmpXkmFile); | |
338 + if (canonicalXkmFileName) | |
339 + xfree(canonicalXkmFileName); | |
340 if (buf != NULL) | |
341 xfree (buf); | |
342 - return False; | |
343 + | |
344 + return result; | |
345 } | |
346 | |
347 static FILE * | |
348 @@ -375,7 +498,6 @@ unsigned missing; | |
349 DebugF("Loaded XKB keymap %s, defined=0x%x\n",fileName,(*xkbRtrn)->defin
ed); | |
350 } | |
351 fclose(file); | |
352 - (void) unlink (fileName); | |
353 return (need|want)&(~missing); | |
354 } | |
355 | |
356 -- | |
357 1.5.6.5 | |
358 | |
OLD | NEW |