VirtualBox

source: kBuild/trunk/src/kmk/w32/imagecache.c@ 3387

Last change on this file since 3387 was 3195, checked in by bird, 6 years ago

kmk/win: Catch output from processes spawned by kmk_redirect. Made imagecase threadsafe and made winchildren use it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.3 KB
Line 
1/* $Id: imagecache.c 3195 2018-03-27 18:09:23Z 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 "makeint.h"
32
33#include <Windows.h>
34
35
36/*********************************************************************************************************************************
37* Structures and Typedefs *
38*********************************************************************************************************************************/
39typedef struct EXECCACHEENTRY
40{
41 /** The name hash value. */
42 unsigned uHash;
43 /** The name length. */
44 unsigned cwcName;
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, LOAD_LIBRARY_AS_DATAFILE. */
50 HMODULE hmod1;
51 /** The module handle, DONT_RESOLVE_DLL_REFERENCES. */
52 HMODULE hmod2;
53 /** The executable path. */
54 wchar_t wszName[1];
55} EXECCACHEENTRY;
56typedef EXECCACHEENTRY *PEXECCACHEENTRY;
57
58
59/*********************************************************************************************************************************
60* Global Variables *
61*********************************************************************************************************************************/
62/** Critical section serializing all access. */
63static CRITICAL_SECTION g_CritSect;
64/** Set if initialized. */
65static int volatile g_fInitialized = 0;
66/** The number of cached images. */
67static unsigned g_cCached;
68/** Used noting when entries was last used.
69 * Increased on each kmk_cache_exec_image call. */
70static unsigned g_uNow;
71
72/** The size of the hash table. */
73#define EXECCACHE_HASHTAB_SIZE 128
74/** The hash table. */
75static PEXECCACHEENTRY g_apHashTab[EXECCACHE_HASHTAB_SIZE];
76
77
78/** A sleepy approach to do-once. */
79static void kmk_cache_lazy_init(void)
80{
81 if (_InterlockedCompareExchange(&g_fInitialized, -1, 0) == 0)
82 {
83 InitializeCriticalSection(&g_CritSect);
84 _InterlockedExchange(&g_fInitialized, 1);
85 }
86 else
87 while (g_fInitialized != 1)
88 Sleep(1);
89}
90
91
92/* sdbm:
93 This algorithm was created for sdbm (a public-domain reimplementation of
94 ndbm) database library. it was found to do well in scrambling bits,
95 causing better distribution of the keys and fewer splits. it also happens
96 to be a good general hashing function with good distribution. the actual
97 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
98 is the faster version used in gawk. [there is even a faster, duff-device
99 version] the magic constant 65599 was picked out of thin air while
100 experimenting with different constants, and turns out to be a prime.
101 this is one of the algorithms used in berkeley db (see sleepycat) and
102 elsewhere. */
103
104static unsigned execcache_calc_hash(const wchar_t *pwsz, size_t *pcch)
105{
106 wchar_t const * const pwszStart = pwsz;
107 unsigned hash = 0;
108 int ch;
109
110 while ((ch = *pwsz++) != L'\0')
111 hash = ch + (hash << 6) + (hash << 16) - hash;
112
113 *pcch = (size_t)(pwsz - pwszStart - 1);
114 return hash;
115}
116
117/**
118 * Caches two memory mappings of the specified image so that it isn't flushed
119 * from the kernel's cache mananger.
120 *
121 * Not sure exactly how much this actually helps, but whatever...
122 *
123 * @param pwszExec The executable.
124 */
125extern void kmk_cache_exec_image_w(const wchar_t *pwszExec)
126{
127 /*
128 * Prepare name lookup and to lazy init.
129 */
130 size_t cwcName;
131 const unsigned uHash = execcache_calc_hash(pwszExec, &cwcName);
132 PEXECCACHEENTRY *ppCur = &g_apHashTab[uHash % EXECCACHE_HASHTAB_SIZE];
133 PEXECCACHEENTRY pCur;
134
135 if (g_fInitialized != 1)
136 kmk_cache_lazy_init();
137
138 /*
139 * Do the lookup.
140 */
141 EnterCriticalSection(&g_CritSect);
142 pCur = *ppCur;
143 while (pCur)
144 {
145 if ( pCur->uHash == uHash
146 && pCur->cwcName == cwcName
147 && !memcmp(pCur->wszName, pwszExec, cwcName * sizeof(wchar_t)))
148 {
149 pCur->uLastRef = ++g_uNow;
150 LeaveCriticalSection(&g_CritSect);
151 return;
152 }
153 ppCur = &pCur->pNext;
154 pCur = pCur->pNext;
155 }
156 LeaveCriticalSection(&g_CritSect);
157
158 /*
159 * Not found, create a new entry.
160 */
161 pCur = xmalloc(sizeof(*pCur) + cwcName * sizeof(wchar_t));
162 pCur->uHash = uHash;
163 pCur->cwcName = (unsigned)cwcName;
164 pCur->pNext = NULL;
165 pCur->uLastRef = ++g_uNow;
166 memcpy(pCur->wszName, pwszExec, (cwcName + 1) * sizeof(wchar_t));
167 pCur->hmod1 = LoadLibraryExW(pwszExec, NULL, LOAD_LIBRARY_AS_DATAFILE);
168 if (pCur->hmod1 != NULL)
169 pCur->hmod2 = LoadLibraryExW(pwszExec, NULL, DONT_RESOLVE_DLL_REFERENCES);
170 else
171 pCur->hmod2 = NULL;
172
173 /*
174 * Insert it.
175 * Take into account that we might've been racing other threads,
176 * fortunately we don't evict anything from the cache.
177 */
178 EnterCriticalSection(&g_CritSect);
179 if (*ppCur != NULL)
180 {
181 /* Find new end of chain and check for duplicate. */
182 PEXECCACHEENTRY pCur2 = *ppCur;
183 while (pCur2)
184 {
185 if ( pCur->uHash == uHash
186 && pCur->cwcName == cwcName
187 && !memcmp(pCur->wszName, pwszExec, cwcName * sizeof(wchar_t)))
188 break;
189 ppCur = &pCur->pNext;
190 pCur = pCur->pNext;
191 }
192
193 }
194 if (*ppCur == NULL)
195 {
196 *ppCur = pCur;
197 g_cCached++;
198 LeaveCriticalSection(&g_CritSect);
199 }
200 else
201 {
202 LeaveCriticalSection(&g_CritSect);
203
204 if (pCur->hmod1 != NULL)
205 FreeLibrary(pCur->hmod1);
206 if (pCur->hmod2 != NULL)
207 FreeLibrary(pCur->hmod2);
208 free(pCur);
209 }
210}
211
212extern void kmk_cache_exec_image_a(const char *pszExec)
213{
214 wchar_t wszExec[260];
215 int cwc = MultiByteToWideChar(CP_ACP, 0 /*fFlags*/, pszExec, strlen(pszExec) + 1, wszExec, 260);
216 if (cwc > 0)
217 kmk_cache_exec_image_w(wszExec);
218}
219
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use