1 /* $Id: imagecache.c 2640 2012-09-09 01:49:16Z bird $ */
2 /** @file
3 * kBuild specific executable image cache for Windows.
4 */
5
6 /*
7 * Copyright (c) 2012 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26 /* No GNU coding style here! */
27
28 /*******************************************************************************
29 * Header Files *
30 *******************************************************************************/
31 #include "make.h"
32
33 #include <Windows.h>
34
35
36 /*******************************************************************************
37 * Structures and Typedefs *
38 *******************************************************************************/
39 typedef struct EXECCACHEENTRY
40 {
41 /** The name hash value. */
42 unsigned uHash;
43 /** The name length. */
44 unsigned cchName;
45 /** Pointer to the next name with the same hash. */
46 struct EXECCACHEENTRY *pNext;
47 /** When it was last referenced. */
48 unsigned uLastRef;
49 /** The module handle. */
50 HMODULE hmod1;
51 /** The module handle. */
52 HMODULE hmod2;
53 /** The executable path. */
54 char szName[1];
55 } EXECCACHEENTRY;
56 typedef EXECCACHEENTRY *PEXECCACHEENTRY;
57
58 /*******************************************************************************
59 * Global Variables *
60 *******************************************************************************/
61 /** The number of cached images. */
62 static unsigned g_cCached;
63 /** Used noting when entries was last used.
64 * Increased on each kmk_cache_exec_image call. */
65 static unsigned g_uNow;
66
67 /** The size of the hash table. */
68 #define EXECCACHE_HASHTAB_SIZE 128
69 /** The hash table. */
70 static PEXECCACHEENTRY g_apHashTab[EXECCACHE_HASHTAB_SIZE];
71
72
73 /* sdbm:
74 This algorithm was created for sdbm (a public-domain reimplementation of
75 ndbm) database library. it was found to do well in scrambling bits,
76 causing better distribution of the keys and fewer splits. it also happens
77 to be a good general hashing function with good distribution. the actual
78 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
79 is the faster version used in gawk. [there is even a faster, duff-device
80 version] the magic constant 65599 was picked out of thin air while
81 experimenting with different constants, and turns out to be a prime.
82 this is one of the algorithms used in berkeley db (see sleepycat) and
83 elsewhere. */
84
execcache_calc_hash(const char * psz,unsigned * pcch)85 static unsigned execcache_calc_hash(const char *psz, unsigned *pcch)
86 {
87 unsigned char *puch = (unsigned char *)psz;
88 unsigned hash = 0;
89 int ch;
90
91 while ((ch = *puch++))
92 hash = ch + (hash << 6) + (hash << 16) - hash;
93
94 *pcch = (unsigned)(puch - psz - 1);
95 return hash;
96 }
97
98
kmk_cache_exec_image(const char * pszExec)99 extern void kmk_cache_exec_image(const char *pszExec)
100 {
101 /*
102 * Lookup the name.
103 */
104 unsigned cchName;
105 const unsigned uHash = execcache_calc_hash(pszExec, &cchName);
106 PEXECCACHEENTRY *ppCur = &g_apHashTab[uHash % EXECCACHE_HASHTAB_SIZE];
107 PEXECCACHEENTRY pCur = *ppCur;
108 while (pCur)
109 {
110 if ( pCur->uHash == uHash
111 && pCur->cchName == cchName
112 && !memcmp(pCur->szName, pszExec, cchName))
113 {
114 pCur->uLastRef = ++g_uNow;
115 return;
116 }
117 ppCur = &pCur->pNext;
118 pCur = pCur->pNext;
119 }
120
121 /*
122 * Not found, create a new entry.
123 */
124 pCur = xmalloc(sizeof(*pCur) + cchName);
125 pCur->uHash = uHash;
126 pCur->cchName = cchName;
127 pCur->pNext = NULL;
128 pCur->uLastRef = ++g_uNow;
129 memcpy(pCur->szName, pszExec, cchName + 1);
130 pCur->hmod1 = LoadLibraryEx(pszExec, NULL, LOAD_LIBRARY_AS_DATAFILE);
131 if (pCur->hmod1 != NULL)
132 pCur->hmod2 = LoadLibraryEx(pszExec, NULL, DONT_RESOLVE_DLL_REFERENCES);
133 else
134 pCur->hmod2 = NULL;
135
136 *ppCur = pCur;
137 g_cCached++;
138 }
139
140