VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp@ 28598

Last change on this file since 28598 was 28434, checked in by vboxsync, 15 years ago

*: whitespace cleanups by scm and two manually picked nits.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 KB
Line 
1/* $Id: VBoxServicePageSharing.cpp 28434 2010-04-17 18:08:28Z vboxsync $ */
2/** @file
3 * VBoxService - Memory Ballooning.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include <iprt/assert.h>
27#include <iprt/avl.h>
28#include <iprt/mem.h>
29#include <iprt/stream.h>
30#include <iprt/string.h>
31#include <iprt/semaphore.h>
32#include <iprt/system.h>
33#include <iprt/thread.h>
34#include <iprt/time.h>
35#include <VBox/VBoxGuestLib.h>
36#include "VBoxServiceInternal.h"
37#include "VBoxServiceUtils.h"
38
39
40/*******************************************************************************
41* Global Variables *
42*******************************************************************************/
43
44/** The semaphore we're blocking on. */
45static RTSEMEVENTMULTI g_PageSharingEvent = NIL_RTSEMEVENTMULTI;
46
47#if defined(RT_OS_WINDOWS) && !defined(TARGET_NT4)
48#include <tlhelp32.h>
49#include <psapi.h>
50
51typedef struct
52{
53 AVLPVNODECORE Core;
54 HMODULE hModule;
55 char szFileVersion[16];
56 MODULEENTRY32 Info;
57} KNOWN_MODULE, *PKNOWN_MODULE;
58
59static DECLCALLBACK(int) VBoxServicePageSharingEmptyTreeCallback(PAVLPVNODECORE pNode, void *);
60
61static PAVLPVNODECORE pKnownModuleTree = NULL;
62
63/**
64 * Registers a new module with the VMM
65 * @param dwProcessId Process id
66 */
67void VBoxServicePageSharingRegisterModule(HANDLE hProcess, PKNOWN_MODULE pModule)
68{
69 VMMDEVSHAREDREGIONDESC aRegions[VMMDEVSHAREDREGIONDESC_MAX];
70 DWORD dwModuleSize = pModule->Info.modBaseSize;
71 BYTE *pBaseAddress = pModule->Info.modBaseAddr;
72 DWORD cbVersionSize, dummy;
73 BYTE *pVersionInfo;
74
75 cbVersionSize = GetFileVersionInfoSize(pModule->Info.szExePath, &dummy);
76 if (!cbVersionSize)
77 {
78 VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: GetFileVersionInfoSize failed with %d\n", GetLastError());
79 return;
80 }
81 pVersionInfo = (BYTE *)RTMemAlloc(cbVersionSize);
82 if (!pVersionInfo)
83 return;
84
85 if (!GetFileVersionInfo(pModule->Info.szExePath, 0, cbVersionSize, pVersionInfo))
86 {
87 VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: GetFileVersionInfo failed with %d\n", GetLastError());
88 goto end;
89 }
90
91 /* Fetch default code page. */
92 struct LANGANDCODEPAGE {
93 WORD wLanguage;
94 WORD wCodePage;
95 } *lpTranslate;
96
97 UINT cbTranslate;
98 BOOL ret = VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"), (LPVOID *)&lpTranslate, &cbTranslate);
99 if ( !ret
100 || cbTranslate < 4)
101 {
102 VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: VerQueryValue failed with %d (cb=%d)\n", GetLastError(), cbTranslate);
103 goto end;
104 }
105
106 unsigned i;
107 UINT cbFileVersion;
108 char *lpszFileVersion;
109 unsigned cTranslationBlocks = cbTranslate/sizeof(struct LANGANDCODEPAGE);
110
111 for(i = 0; i < cTranslationBlocks; i++)
112 {
113 /* Fetch file version string. */
114 char szFileVersionLocation[256];
115
116 sprintf(szFileVersionLocation, TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"), lpTranslate[i].wLanguage, lpTranslate[i].wCodePage);
117 ret = VerQueryValue(pVersionInfo, szFileVersionLocation, (LPVOID *)&lpszFileVersion, &cbFileVersion);
118 if (ret)
119 break;
120 }
121 if (i == cTranslationBlocks)
122 {
123 VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: no file version found!\n");
124 goto end;
125 }
126
127 _snprintf(pModule->szFileVersion, sizeof(pModule->szFileVersion), "%s", lpszFileVersion);
128 pModule->szFileVersion[RT_ELEMENTS(pModule->szFileVersion) - 1] = 0;
129
130 unsigned idxRegion = 0;
131 do
132 {
133 MEMORY_BASIC_INFORMATION MemInfo[16];
134
135 SIZE_T ret = VirtualQueryEx(hProcess, pBaseAddress, &MemInfo[0], sizeof(MemInfo));
136 Assert(ret);
137 if (!ret)
138 {
139 VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: VirtualQueryEx failed with %d\n", GetLastError());
140 break;
141 }
142
143 unsigned cMemInfoBlocks = ret / sizeof(MemInfo);
144
145 for (unsigned i = 0; i < cMemInfoBlocks; i++)
146 {
147 if ( MemInfo[i].State == MEM_COMMIT
148 && MemInfo[i].Type == MEM_IMAGE)
149 {
150 switch (MemInfo[i].Protect)
151 {
152 case PAGE_EXECUTE:
153 case PAGE_EXECUTE_READ:
154 case PAGE_READONLY:
155 aRegions[idxRegion].GCRegionAddr = (RTGCPTR64)MemInfo[i].BaseAddress;
156 aRegions[idxRegion].cbRegion = MemInfo[i].RegionSize;
157 idxRegion++;
158 break;
159
160 default:
161 break; /* ignore */
162 }
163 }
164
165 pBaseAddress = (BYTE *)MemInfo[i].BaseAddress + MemInfo[i].RegionSize;
166 if (dwModuleSize > MemInfo[i].RegionSize)
167 dwModuleSize -= MemInfo[i].RegionSize;
168 else
169 dwModuleSize = 0;
170
171 if (idxRegion >= RT_ELEMENTS(aRegions))
172 break; /* out of room */
173 }
174 }
175 while (dwModuleSize);
176
177 int rc = VbglR3RegisterSharedModule(pModule->Info.szModule, pModule->szFileVersion, (RTGCPTR64)pModule->Info.modBaseAddr,
178 pModule->Info.modBaseSize, idxRegion, aRegions);
179 AssertRC(rc);
180
181end:
182 RTMemFree(pVersionInfo);
183 return;
184}
185
186/**
187 * Inspect all loaded modules for the specified process
188 * @param dwProcessId Process id
189 */
190void VBoxServicePageSharingInspectModules(DWORD dwProcessId, PAVLPVNODECORE *ppNewTree)
191{
192 HANDLE hProcess, hSnapshot;
193
194 /* Get a list of all the modules in this process. */
195 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
196 FALSE /* no child process handle inheritance */, dwProcessId);
197 if (hProcess == NULL)
198 return;
199
200 hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
201 if (hSnapshot == INVALID_HANDLE_VALUE)
202 {
203 CloseHandle(hProcess);
204 return;
205 }
206
207 MODULEENTRY32 ModuleInfo;
208 BOOL bRet;
209
210 ModuleInfo.dwSize = sizeof(ModuleInfo);
211 bRet = Module32First(hSnapshot, &ModuleInfo);
212 do
213 {
214 /* Found it before? */
215 PAVLPVNODECORE pRec = RTAvlPVGet(ppNewTree, ModuleInfo.modBaseAddr);
216 if (!pRec)
217 {
218 pRec = RTAvlPVRemove(&pKnownModuleTree, ModuleInfo.modBaseAddr);
219 if (!pRec)
220 {
221 /* New module; register it. */
222 PKNOWN_MODULE pModule = (PKNOWN_MODULE)RTMemAllocZ(sizeof(*pModule));
223 Assert(pModule);
224 if (!pModule)
225 break;
226
227 pModule->Info = ModuleInfo;
228 pModule->Core.Key = ModuleInfo.modBaseAddr;
229 pModule->hModule = LoadLibraryEx(ModuleInfo.szExePath, 0, DONT_RESOLVE_DLL_REFERENCES);
230 Assert(pModule->hModule);
231
232 VBoxServicePageSharingRegisterModule(hProcess, pModule);
233
234 pRec = &pModule->Core;
235 }
236 bool ret = RTAvlPVInsert(ppNewTree, pRec);
237 Assert(ret); NOREF(ret);
238 }
239
240 printf( "\n\n MODULE NAME: %s", ModuleInfo.szModule );
241 printf( "\n executable = %s", ModuleInfo.szExePath );
242 printf( "\n process ID = 0x%08X", ModuleInfo.th32ProcessID );
243 printf( "\n base address = 0x%08X", (DWORD) ModuleInfo.modBaseAddr );
244 printf( "\n base size = %d", ModuleInfo.modBaseSize );
245 }
246 while (Module32Next(hSnapshot, &ModuleInfo));
247
248 CloseHandle(hProcess);
249 CloseHandle(hSnapshot);
250}
251
252/**
253 * Inspect all running processes for executables and dlls that might be worth sharing
254 * with other VMs.
255 *
256 */
257void VBoxServicePageSharingInspectGuest()
258{
259 HANDLE hSnapshot;
260 PAVLPVNODECORE pNewTree = NULL;
261
262 hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
263 if (hSnapshot == INVALID_HANDLE_VALUE)
264 return;
265
266 /* Check loaded modules for all running processes. */
267 PROCESSENTRY32 ProcessInfo;
268
269 ProcessInfo.dwSize = sizeof(ProcessInfo);
270 Process32First(hSnapshot, &ProcessInfo);
271
272 do
273 {
274 VBoxServicePageSharingInspectModules(ProcessInfo.th32ProcessID, &pNewTree);
275 }
276 while (Process32Next(hSnapshot, &ProcessInfo));
277
278 CloseHandle(hSnapshot);
279
280 /* Delete leftover modules in the old tree. */
281 RTAvlPVDestroy(&pKnownModuleTree, VBoxServicePageSharingEmptyTreeCallback, NULL);
282
283 /* Activate new module tree. */
284 pKnownModuleTree = pNewTree;
285}
286
287/**
288 * RTAvlPVDestroy callback.
289 */
290static DECLCALLBACK(int) VBoxServicePageSharingEmptyTreeCallback(PAVLPVNODECORE pNode, void *)
291{
292 PKNOWN_MODULE pModule = (PKNOWN_MODULE)pNode;
293
294 /* Defererence module in the hypervisor. */
295 int rc = VbglR3UnregisterSharedModule(pModule->Info.szModule, pModule->szFileVersion, (RTGCPTR64)pModule->Info.modBaseAddr, pModule->Info.modBaseSize);
296 AssertRC(rc);
297
298 if (pModule->hModule)
299 FreeLibrary(pModule->hModule);
300 RTMemFree(pNode);
301 return 0;
302}
303
304
305#elif TARGET_NT4
306void VBoxServicePageSharingInspectGuest()
307{
308 /* not implemented */
309}
310#else
311void VBoxServicePageSharingInspectGuest()
312{
313 /* @todo other platforms */
314}
315#endif
316
317/** @copydoc VBOXSERVICE::pfnPreInit */
318static DECLCALLBACK(int) VBoxServicePageSharingPreInit(void)
319{
320 return VINF_SUCCESS;
321}
322
323
324/** @copydoc VBOXSERVICE::pfnOption */
325static DECLCALLBACK(int) VBoxServicePageSharingOption(const char **ppszShort, int argc, char **argv, int *pi)
326{
327 NOREF(ppszShort);
328 NOREF(argc);
329 NOREF(argv);
330 NOREF(pi);
331 return VINF_SUCCESS;
332}
333
334
335/** @copydoc VBOXSERVICE::pfnInit */
336static DECLCALLBACK(int) VBoxServicePageSharingInit(void)
337{
338 VBoxServiceVerbose(3, "VBoxServicePageSharingInit\n");
339
340 int rc = RTSemEventMultiCreate(&g_PageSharingEvent);
341 AssertRCReturn(rc, rc);
342
343 /* @todo check if page sharing is active. */
344 /* @todo report system name and version */
345 /* Never fail here. */
346 return VINF_SUCCESS;
347}
348
349/** @copydoc VBOXSERVICE::pfnWorker */
350DECLCALLBACK(int) VBoxServicePageSharingWorker(bool volatile *pfShutdown)
351{
352 /*
353 * Tell the control thread that it can continue
354 * spawning services.
355 */
356 RTThreadUserSignal(RTThreadSelf());
357
358 /*
359 * Now enter the loop retrieving runtime data continuously.
360 */
361 for (;;)
362 {
363
364 VBoxServicePageSharingInspectGuest();
365
366 /*
367 * Block for a minute.
368 *
369 * The event semaphore takes care of ignoring interruptions and it
370 * allows us to implement service wakeup later.
371 */
372 if (*pfShutdown)
373 break;
374 int rc = RTSemEventMultiWait(g_PageSharingEvent, 60000);
375 if (*pfShutdown)
376 break;
377 if (rc != VERR_TIMEOUT && RT_FAILURE(rc))
378 {
379 VBoxServiceError("RTSemEventMultiWait failed; rc=%Rrc\n", rc);
380 break;
381 }
382 }
383
384 RTSemEventMultiDestroy(g_PageSharingEvent);
385 g_PageSharingEvent = NIL_RTSEMEVENTMULTI;
386
387 VBoxServiceVerbose(3, "VBoxServicePageSharingWorker: finished thread\n");
388 return 0;
389}
390
391/** @copydoc VBOXSERVICE::pfnTerm */
392static DECLCALLBACK(void) VBoxServicePageSharingTerm(void)
393{
394 VBoxServiceVerbose(3, "VBoxServicePageSharingTerm\n");
395 return;
396}
397
398
399/** @copydoc VBOXSERVICE::pfnStop */
400static DECLCALLBACK(void) VBoxServicePageSharingStop(void)
401{
402 RTSemEventMultiSignal(g_PageSharingEvent);
403}
404
405
406/**
407 * The 'pagesharing' service description.
408 */
409VBOXSERVICE g_PageSharing =
410{
411 /* pszName. */
412 "pagesharing",
413 /* pszDescription. */
414 "Page Sharing",
415 /* pszUsage. */
416 NULL,
417 /* pszOptions. */
418 NULL,
419 /* methods */
420 VBoxServicePageSharingPreInit,
421 VBoxServicePageSharingOption,
422 VBoxServicePageSharingInit,
423 VBoxServicePageSharingWorker,
424 VBoxServicePageSharingStop,
425 VBoxServicePageSharingTerm
426};
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette