| 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 |