VirtualBox

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

Last change on this file since 28972 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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