summaryrefslogtreecommitdiffstats
path: root/meta/recipes-graphics/xorg-xserver/xserver-xf86-dri-lite/cache-xkbcomp-output-for-fast-start-up.patch
blob: b121bba655058fcc11a246cbb304c2654733fec2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
From 0f70ba9d3412b17ac4e08e33e1be3c226c06ea54 Mon Sep 17 00:00:00 2001
From: Yan Li <yan.i.li@intel.com>
Date: Tue, 12 May 2009 17:49:07 +0800
Subject: [PATCH] XKB: cache xkbcomp output for fast start-up v5 for 1.6.1
Organization: Intel

xkbcomp outputs will be cached in files with hashed keymap as
names. This saves boot time for around 1s on commodity netbooks.

Signed-off-by: Yan Li <yan.i.li@intel.com>
---
 configure.ac        |    6 +-
 xkb/README.compiled |    8 +-
 xkb/ddxLoad.c       |  192 +++++++++++++++++++++++++++++++++++++++++---------
 3 files changed, 164 insertions(+), 42 deletions(-)

diff --git a/configure.ac b/configure.ac
index 4c4c797..7a5020a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -476,9 +476,9 @@ AC_ARG_WITH(default-font-path, AS_HELP_STRING([--with-default-font-path=PATH], [
 AC_ARG_WITH(xkb-path,         AS_HELP_STRING([--with-xkb-path=PATH], [Path to XKB base dir (default: ${datadir}/X11/xkb)]),
 				[ XKBPATH="$withval" ],
 				[ XKBPATH="${datadir}/X11/xkb" ])
-AC_ARG_WITH(xkb-output,       AS_HELP_STRING([--with-xkb-output=PATH], [Path to XKB output dir (default: ${datadir}/X11/xkb/compiled)]),
+AC_ARG_WITH(xkb-output,       AS_HELP_STRING([--with-xkb-output=PATH], [Path to XKB output dir (default: ${localstatedir}/cache/xkb)]),
 				[ XKBOUTPUT="$withval" ],
-				[ XKBOUTPUT="compiled" ])
+				[ XKBOUTPUT="${localstatedir}/cache/xkb" ])
 AC_ARG_WITH(serverconfig-path, AS_HELP_STRING([--with-serverconfig-path=PATH],
 				   [Directory where ancillary server config files are installed (default: ${libdir}/xorg)]),
 				[ SERVERCONFIG="$withval" ],
@@ -1757,7 +1757,7 @@ AC_DEFINE_DIR(XKB_BIN_DIRECTORY, bindir, [Path to XKB bin dir])
 XKBOUTPUT_FIRSTCHAR=`echo $XKBOUTPUT | cut -b 1`
 
 if [[ x$XKBOUTPUT_FIRSTCHAR != x/ ]] ; then
-   XKBOUTPUT="$XKB_BASE_DIRECTORY/$XKBOUTPUT"
+   AC_MSG_ERROR([xkb-output must be an absolute path.])
 fi
 
 # XKM_OUTPUT_DIR (used in code) must end in / or file names get hosed
diff --git a/xkb/README.compiled b/xkb/README.compiled
index 71caa2f..a4a2ae0 100644
--- a/xkb/README.compiled
+++ b/xkb/README.compiled
@@ -4,10 +4,10 @@ current keymap and/or any scratch keymaps used by clients.  The X server
 or some other tool might destroy or replace the files in this directory,
 so it is not a safe place to store compiled keymaps for long periods of
 time.  The default keymap for any server is usually stored in:
-     X<num>-default.xkm
-where <num> is the display number of the server in question, which makes
-it possible for several servers *on the same host* to share the same 
-directory.
+     server-<SHA1>.xkm
+
+where <SHA1> is the SHA1 hash of keymap source, so that compiled
+keymap of different keymap sources are stored in different files.
 
 Unless the X server is modified, sharing this directory between servers on
 different hosts could cause problems.
diff --git a/xkb/ddxLoad.c b/xkb/ddxLoad.c
index 4d5dfb6..60a68af 100644
--- a/xkb/ddxLoad.c
+++ b/xkb/ddxLoad.c
@@ -32,6 +32,12 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <xkb-config.h>
 #endif
 
+#ifdef HAVE_SHA1_IN_LIBMD /* Use libmd for SHA1 */
+# include <sha1.h>
+#else /* Use OpenSSL's libcrypto */
+# include <stddef.h>  /* buggy openssl/sha.h wants size_t */
+# include <openssl/sha.h>
+#endif
 #include <stdio.h>
 #include <ctype.h>
 #define	NEED_EVENTS 1
@@ -46,24 +52,13 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #define	XKBSRV_NEED_FILE_FUNCS
 #include <xkbsrv.h>
 #include <X11/extensions/XI.h>
+#include <errno.h>
 #include "xkb.h"
 
 #if defined(CSRG_BASED) || defined(linux) || defined(__GNU__)
 #include <paths.h>
 #endif
 
-	/*
-	 * If XKM_OUTPUT_DIR specifies a path without a leading slash, it is
-	 * relative to the top-level XKB configuration directory.
-	 * Making the server write to a subdirectory of that directory
-	 * requires some work in the general case (install procedure
-	 * has to create links to /var or somesuch on many machines),
-	 * so we just compile into /usr/tmp for now.
-	 */
-#ifndef XKM_OUTPUT_DIR
-#define	XKM_OUTPUT_DIR	"compiled/"
-#endif
-
 #define	PRE_ERROR_MSG "\"The XKEYBOARD keymap compiler (xkbcomp) reports:\""
 #define	ERROR_PREFIX	"\"> \""
 #define	POST_ERROR_MSG1 "\"Errors from xkbcomp are not fatal to the X server\""
@@ -179,6 +174,45 @@ OutputDirectory(
 }
 
 static Bool    	
+Sha1Asc(char sha1Asc[SHA_DIGEST_LENGTH*2+1], const char * input)
+{
+    int i;
+    unsigned char sha1[SHA_DIGEST_LENGTH];
+
+#ifdef HAVE_SHA1_IN_LIBMD /* Use libmd for SHA1 */
+    SHA1_CTX ctx;
+
+    SHA1Init (&ctx);
+    SHA1Update (&ctx, input, strlen(input));
+    SHA1Final (sha1, &ctx);
+#else /* Use OpenSSL's libcrypto */
+    SHA_CTX ctx;
+    int success;
+
+    success = SHA1_Init (&ctx);
+    if (! success)
+	return BadAlloc;
+
+    success = SHA1_Update (&ctx, input, strlen(input));
+    if (! success)
+	return BadAlloc;
+
+    success = SHA1_Final (sha1, &ctx);
+    if (! success)
+	return BadAlloc;
+#endif
+
+    /* convert sha1 to sha1_asc */
+    for(i=0; i<SHA_DIGEST_LENGTH; ++i) {
+        sprintf(sha1Asc+i*2, "%02X", sha1[i]);
+    }
+
+    return Success;
+}
+
+/* call xkbcomp and compile XKB keymap, return xkm file name in
+   nameRtrn */
+static Bool
 XkbDDXCompileKeymapByNames(	XkbDescPtr		xkb,
 				XkbComponentNamesPtr	names,
 				unsigned		want,
@@ -187,7 +221,11 @@ XkbDDXCompileKeymapByNames(	XkbDescPtr		xkb,
 				int			nameRtrnLen)
 {
     FILE *	out;
-    char	*buf = NULL, keymap[PATH_MAX], xkm_output_dir[PATH_MAX];
+    char *	buf = NULL, xkmfile[PATH_MAX], xkm_output_dir[PATH_MAX];
+    char *	tmpXkmFile = NULL;
+    char *	canonicalXkmFileName = NULL;
+    char	sha1Asc[SHA_DIGEST_LENGTH*2+1], xkbKeyMapBuf[100*1024];
+    int	ret, result;
 
     const char	*emptystring = "";
     const char	*xkbbasedirflag = emptystring;
@@ -198,16 +236,70 @@ XkbDDXCompileKeymapByNames(	XkbDescPtr		xkb,
     /* WIN32 has no popen. The input must be stored in a file which is
        used as input for xkbcomp. xkbcomp does not read from stdin. */
     char tmpname[PATH_MAX];
-    const char *xkmfile = tmpname;
+    const char *xkbfile = tmpname;
 #else
-    const char *xkmfile = "-";
+    const char *xkbfile = "-";
 #endif
 
-    snprintf(keymap, sizeof(keymap), "server-%s", display);
+    /* Write keymap source (xkbfile) to memory buffer `xkbKeyMapBuf',
+       of which SHA1 is generated and used as result xkm file name  */
+    memset(xkbKeyMapBuf, 0, sizeof(xkbKeyMapBuf));
+    out = fmemopen(xkbKeyMapBuf, sizeof(xkbKeyMapBuf), "w");
+    if (NULL == out) {
+        ErrorF("[xkb] Open xkbKeyMapBuf for writing failed\n");
+        return False;
+    }
+    ret = XkbWriteXKBKeymapForNames(out, names, xkb, want, need);
+    if (fclose(out) !=0)
+    {
+        ErrorF("[xkb] XkbWriteXKBKeymapForNames error, perhaps xkbKeyMapBuf is too small\n");
+        return False;
+    }
+#ifdef DEBUG
+    if (xkbDebugFlags) {
+       ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n");
+       fputs(xkbKeyMapBuf, stderr);
+    }
+#endif
+    if (!ret) {
+        ErrorF("[xkb] Generating XKB Keymap failed, giving up compiling keymap\n");
+        return False;
+    }
+
+    DebugF("[xkb] computing SHA1 of keymap\n");
+    if (Success == Sha1Asc(sha1Asc, xkbKeyMapBuf)) {
+        snprintf(xkmfile, sizeof(xkmfile), "server-%s", sha1Asc);
+    }
+    else {
+        ErrorF("[xkb] Computing SHA1 of keymap failed, "
+               "using display name instead as xkm file name\n");
+        snprintf(xkmfile, sizeof(xkmfile), "server-%s", display);
+    }
 
-    XkbEnsureSafeMapName(keymap);
+    XkbEnsureSafeMapName(xkmfile);
     OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
 
+    /* set nameRtrn, fail if it's too small */
+    if ((strlen(xkmfile)+1 > nameRtrnLen) && nameRtrn) {
+        ErrorF("[xkb] nameRtrn too small to hold xkmfile name\n");
+        return False;
+    }
+    strncpy(nameRtrn, xkmfile, nameRtrnLen);
+
+    /* if the xkm file already exists, reuse it */
+    canonicalXkmFileName = Xprintf("%s%s.xkm", xkm_output_dir, xkmfile);
+    if (access(canonicalXkmFileName, R_OK) == 0) {
+        /* yes, we can reuse the old xkm file */
+        LogMessage(X_INFO, "XKB: reuse xkmfile %s\n", canonicalXkmFileName);
+        result = True;
+        goto _ret;
+    }
+    LogMessage(X_INFO, "XKB: generating xkmfile %s\n", canonicalXkmFileName);
+
+    /* continue to call xkbcomp to compile the keymap. to avoid race
+       condition, we compile it to a tmpfile then rename it to
+       xkmfile */
+
 #ifdef WIN32
     strcpy(tmpname, Win32TempDir());
     strcat(tmpname, "\\xkb_XXXXXX");
@@ -230,19 +322,30 @@ XkbDDXCompileKeymapByNames(	XkbDescPtr		xkb,
 	}
     }
 
+    if ( (tmpXkmFile = tempnam(xkm_output_dir, NULL)) == NULL ) {
+        ErrorF("[xkb] Can't generate temp xkm file name");
+        result = False;
+        goto _ret;
+    }
+
     buf = Xprintf("\"%s%sxkbcomp\" -w %d %s -xkm \"%s\" "
-		  "-em1 %s -emp %s -eml %s \"%s%s.xkm\"",
+		  "-em1 %s -emp %s -eml %s \"%s\"",
 		  xkbbindir, xkbbindirsep,
 		  ( (xkbDebugFlags < 2) ? 1 :
 		    ((xkbDebugFlags > 10) ? 10 : (int)xkbDebugFlags) ),
-		  xkbbasedirflag, xkmfile,
+		  xkbbasedirflag, xkbfile,
 		  PRE_ERROR_MSG, ERROR_PREFIX, POST_ERROR_MSG1,
-		  xkm_output_dir, keymap);
+		  tmpXkmFile);
 
     if (xkbbasedirflag != emptystring) {
 	xfree(xkbbasedirflag);
     }
     
+    /* there's a potential race condition between calling tempnam()
+       and invoking xkbcomp to write the result file (potential temp
+       file name conflicts), but since xkbcomp is a standalone
+       program, we have to live with this */
+
 #ifndef WIN32
     out= Popen(buf,"w");
 #else
@@ -250,31 +353,43 @@ XkbDDXCompileKeymapByNames(	XkbDescPtr		xkb,
 #endif
     
     if (out!=NULL) {
-#ifdef DEBUG
-    if (xkbDebugFlags) {
-       ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n");
-       XkbWriteXKBKeymapForNames(stderr,names,xkb,want,need);
+        /* write XKBKeyMapBuf to xkbcomp */
+        if (EOF==fputs(xkbKeyMapBuf, out))
+        {
+            ErrorF("[xkb] Sending keymap to xkbcomp failed\n");
+            result = False;
+            goto _ret;
     }
-#endif
-	XkbWriteXKBKeymapForNames(out,names,xkb,want,need);
 #ifndef WIN32
 	if (Pclose(out)==0)
 #else
 	if (fclose(out)==0 && System(buf) >= 0)
 #endif
 	{
+        /* xkbcomp success */
             if (xkbDebugFlags)
                 DebugF("[xkb] xkb executes: %s\n",buf);
-	    if (nameRtrn) {
-		strncpy(nameRtrn,keymap,nameRtrnLen);
-		nameRtrn[nameRtrnLen-1]= '\0';
+
+            /* if canonicalXkmFileName already exists now, we simply
+               overwrite it, this is OK */
+            ret = rename(tmpXkmFile, canonicalXkmFileName);
+            if (0 != ret) {
+                ErrorF("[xkb] Can't rename %s to %s, error: %s\n",
+                       tmpXkmFile, canonicalXkmFileName,
+                       strerror(errno));
+
+                /* in case of error, don't unlink tmpXkmFile, leave it
+                   for debugging */
+
+                result = False;
+                goto _ret;
 	    }
-            if (buf != NULL)
-                xfree (buf);
-	    return True;
+
+            result = True;
+            goto _ret;
 	}
 	else
-	    LogMessage(X_ERROR, "Error compiling keymap (%s)\n", keymap);
+           LogMessage(X_ERROR, "Error compiling keymap (%s)\n", xkbfile);
 #ifdef WIN32
         /* remove the temporary file */
         unlink(tmpname);
@@ -289,9 +404,17 @@ XkbDDXCompileKeymapByNames(	XkbDescPtr		xkb,
     }
     if (nameRtrn)
 	nameRtrn[0]= '\0';
+    result = False;
+
+_ret:
+    if (tmpXkmFile)
+        free(tmpXkmFile);
+    if (canonicalXkmFileName)
+        xfree(canonicalXkmFileName);
     if (buf != NULL)
         xfree (buf);
-    return False;
+
+    return result;
 }
 
 static FILE *
@@ -375,7 +498,6 @@ unsigned	missing;
 	DebugF("Loaded XKB keymap %s, defined=0x%x\n",fileName,(*xkbRtrn)->defined);
     }
     fclose(file);
-    (void) unlink (fileName);
     return (need|want)&(~missing);
 }
 
-- 
1.5.6.5