VirtualBox

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

最後變更 在這個檔案從95851是 95851,由 vboxsync 提交於 3 年 前

VBoxService/PageSharing: sprintf -> RTStrPrintf; strcat -> RTStrCat. bugref:10261

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 27.8 KB
 
1/* $Id: VBoxServicePageSharing.cpp 95851 2022-07-26 23:38:31Z vboxsync $ */
2/** @file
3 * VBoxService - Guest page sharing.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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/** @page pg_vgsvc_pagesharing VBoxService - Page Sharing
20 *
21 * The Page Sharing subservice is responsible for finding memory mappings
22 * suitable page fusions.
23 *
24 * It is the driving force behind the Page Fusion feature in VirtualBox.
25 * Working with PGM and GMM (ring-0) thru the VMMDev interface. Every so often
26 * it reenumerates the memory mappings (executables and shared libraries) of the
27 * guest OS and reports additions and removals to GMM. For each mapping there
28 * is a filename and version as well as and address range and subsections. GMM
29 * will match the mapping with mapping with the same name and version from other
30 * VMs and see if there are any identical pages between the two.
31 *
32 * To increase the hit rate and reduce the volatility, the service launches a
33 * child process which loads all the Windows system DLLs it can. The child
34 * process is necessary as the DLLs are loaded without running the init code,
35 * and therefore not actually callable for other VBoxService code (may crash).
36 *
37 * This is currently only implemented on Windows. There is no technical reason
38 * for it not to be doable for all the other guests too, it's just a matter of
39 * customer demand and engineering time.
40 *
41 */
42
43
44/*********************************************************************************************************************************
45* Header Files *
46*********************************************************************************************************************************/
47#include <iprt/assert.h>
48#include <iprt/avl.h>
49#include <iprt/asm.h>
50#include <iprt/mem.h>
51#include <iprt/ldr.h>
52#include <iprt/process.h>
53#include <iprt/env.h>
54#include <iprt/stream.h>
55#include <iprt/file.h>
56#include <iprt/string.h>
57#include <iprt/semaphore.h>
58#include <iprt/string.h>
59#include <iprt/system.h>
60#include <iprt/thread.h>
61#include <iprt/time.h>
62#include <VBox/err.h>
63#include <VBox/VMMDev.h>
64#include <VBox/VBoxGuestLib.h>
65
66#ifdef RT_OS_WINDOWS
67#include <iprt/nt/nt-and-windows.h>
68# include <tlhelp32.h>
69# include <psapi.h>
70# include <winternl.h>
71#endif
72
73#include "VBoxServiceInternal.h"
74#include "VBoxServiceUtils.h"
75
76
77/*********************************************************************************************************************************
78* Header Files *
79*********************************************************************************************************************************/
80typedef struct
81{
82 AVLPVNODECORE Core;
83#ifdef RT_OS_WINDOWS
84 HMODULE hModule;
85 char szFileVersion[16];
86 MODULEENTRY32 Info;
87#endif
88} VGSVCPGSHKNOWNMOD, *PVGSVCPGSHKNOWNMOD;
89
90
91/*********************************************************************************************************************************
92* Global Variables *
93*********************************************************************************************************************************/
94/** The semaphore we're blocking on. */
95static RTSEMEVENTMULTI g_PageSharingEvent = NIL_RTSEMEVENTMULTI;
96
97static PAVLPVNODECORE g_pKnownModuleTree = NULL;
98static uint64_t g_idSession = 0;
99
100
101/*********************************************************************************************************************************
102* Internal Functions *
103*********************************************************************************************************************************/
104static DECLCALLBACK(int) vgsvcPageSharingEmptyTreeCallback(PAVLPVNODECORE pNode, void *pvUser);
105
106
107#ifdef RT_OS_WINDOWS
108
109/**
110 * Registers a new module with the VMM
111 * @param pModule Module ptr
112 * @param fValidateMemory Validate/touch memory pages or not
113 */
114static void vgsvcPageSharingRegisterModule(PVGSVCPGSHKNOWNMOD pModule, bool fValidateMemory)
115{
116 VMMDEVSHAREDREGIONDESC aRegions[VMMDEVSHAREDREGIONDESC_MAX];
117 DWORD dwModuleSize = pModule->Info.modBaseSize;
118 BYTE *pBaseAddress = pModule->Info.modBaseAddr;
119
120 VGSvcVerbose(3, "vgsvcPageSharingRegisterModule\n");
121
122 DWORD dwDummy;
123 DWORD cbVersion = GetFileVersionInfoSize(pModule->Info.szExePath, &dwDummy);
124 if (!cbVersion)
125 {
126 VGSvcVerbose(3, "vgsvcPageSharingRegisterModule: GetFileVersionInfoSize failed with %d\n", GetLastError());
127 return;
128 }
129 BYTE *pVersionInfo = (BYTE *)RTMemAllocZ(cbVersion);
130 if (!pVersionInfo)
131 return;
132
133 if (!GetFileVersionInfo(pModule->Info.szExePath, 0, cbVersion, pVersionInfo))
134 {
135 VGSvcVerbose(3, "vgsvcPageSharingRegisterModule: GetFileVersionInfo failed with %d\n", GetLastError());
136 goto end;
137 }
138
139 /* Fetch default code page. */
140 struct LANGANDCODEPAGE
141 {
142 WORD wLanguage;
143 WORD wCodePage;
144 } *lpTranslate;
145
146 UINT cbTranslate;
147 BOOL fRet = VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"), (LPVOID *)&lpTranslate, &cbTranslate);
148 if ( !fRet
149 || cbTranslate < 4)
150 {
151 VGSvcVerbose(3, "vgsvcPageSharingRegisterModule: VerQueryValue failed with %d (cb=%d)\n", GetLastError(), cbTranslate);
152 goto end;
153 }
154
155 unsigned i;
156 UINT cbFileVersion;
157 char *pszFileVersion = NULL; /* Shut up MSC */
158 unsigned cTranslationBlocks = cbTranslate/sizeof(struct LANGANDCODEPAGE);
159
160 pModule->szFileVersion[0] = '\0';
161 for (i = 0; i < cTranslationBlocks; i++)
162 {
163 /* Fetch file version string. */
164 char szFileVersionLocation[256];
165
166/** @todo r=bird: Mixing ANSI and TCHAR crap again. This code is a mess. We
167 * always use the wide version of the API and convert to UTF-8/whatever. */
168
169 RTStrPrintf(szFileVersionLocation, sizeof(szFileVersionLocation),
170 "\\StringFileInfo\\%04x%04x\\FileVersion", lpTranslate[i].wLanguage, lpTranslate[i].wCodePage);
171 fRet = VerQueryValue(pVersionInfo, szFileVersionLocation, (LPVOID *)&pszFileVersion, &cbFileVersion);
172 if (fRet)
173 {
174 RTStrCopy(pModule->szFileVersion, sizeof(pModule->szFileVersion), pszFileVersion);
175 break;
176 }
177 }
178 if (i == cTranslationBlocks)
179 {
180 VGSvcVerbose(3, "vgsvcPageSharingRegisterModule: no file version found!\n");
181 goto end;
182 }
183
184 unsigned idxRegion = 0;
185
186 if (fValidateMemory)
187 {
188 do
189 {
190 MEMORY_BASIC_INFORMATION MemInfo;
191 SIZE_T cbRet = VirtualQuery(pBaseAddress, &MemInfo, sizeof(MemInfo));
192 Assert(cbRet);
193 if (!cbRet)
194 {
195 VGSvcVerbose(3, "vgsvcPageSharingRegisterModule: VirtualQueryEx failed with %d\n", GetLastError());
196 break;
197 }
198
199 if ( MemInfo.State == MEM_COMMIT
200 && MemInfo.Type == MEM_IMAGE)
201 {
202 switch (MemInfo.Protect)
203 {
204 case PAGE_EXECUTE:
205 case PAGE_EXECUTE_READ:
206 case PAGE_READONLY:
207 {
208 char *pRegion = (char *)MemInfo.BaseAddress;
209
210 /* Skip the first region as it only contains the image file header. */
211 if (pRegion != (char *)pModule->Info.modBaseAddr)
212 {
213 /* Touch all pages. */
214 while ((uintptr_t)pRegion < (uintptr_t)MemInfo.BaseAddress + MemInfo.RegionSize)
215 {
216 /* Try to trick the optimizer to leave the page touching code in place. */
217 ASMProbeReadByte(pRegion);
218 pRegion += PAGE_SIZE;
219 }
220 }
221#ifdef RT_ARCH_X86
222 aRegions[idxRegion].GCRegionAddr = (RTGCPTR32)MemInfo.BaseAddress;
223#else
224 aRegions[idxRegion].GCRegionAddr = (RTGCPTR64)MemInfo.BaseAddress;
225#endif
226 aRegions[idxRegion].cbRegion = MemInfo.RegionSize;
227 idxRegion++;
228
229 break;
230 }
231
232 default:
233 break; /* ignore */
234 }
235 }
236
237 pBaseAddress = (BYTE *)MemInfo.BaseAddress + MemInfo.RegionSize;
238 if (dwModuleSize > MemInfo.RegionSize)
239 dwModuleSize -= MemInfo.RegionSize;
240 else
241 {
242 dwModuleSize = 0;
243 break;
244 }
245
246 if (idxRegion >= RT_ELEMENTS(aRegions))
247 break; /* out of room */
248 }
249 while (dwModuleSize);
250 }
251 else
252 {
253 /* We can't probe kernel memory ranges, so pretend it's one big region. */
254#ifdef RT_ARCH_X86
255 aRegions[idxRegion].GCRegionAddr = (RTGCPTR32)pBaseAddress;
256#else
257 aRegions[idxRegion].GCRegionAddr = (RTGCPTR64)pBaseAddress;
258#endif
259 aRegions[idxRegion].cbRegion = dwModuleSize;
260 idxRegion++;
261 }
262 VGSvcVerbose(3, "vgsvcPageSharingRegisterModule: VbglR3RegisterSharedModule %s %s base=%p size=%x cregions=%d\n", pModule->Info.szModule, pModule->szFileVersion, pModule->Info.modBaseAddr, pModule->Info.modBaseSize, idxRegion);
263 int rc = VbglR3RegisterSharedModule(pModule->Info.szModule, pModule->szFileVersion, (uintptr_t)pModule->Info.modBaseAddr,
264 pModule->Info.modBaseSize, idxRegion, aRegions);
265 if (RT_FAILURE(rc))
266 VGSvcVerbose(3, "vgsvcPageSharingRegisterModule: VbglR3RegisterSharedModule failed with %Rrc\n", rc);
267
268end:
269 RTMemFree(pVersionInfo);
270 return;
271}
272
273
274/**
275 * Inspect all loaded modules for the specified process
276 *
277 * @param dwProcessId Process id
278 * @param ppNewTree The module tree we're assembling from modules found
279 * in this process. Modules found are moved from
280 * g_pKnownModuleTree or created new.
281 */
282static void vgsvcPageSharingInspectModules(DWORD dwProcessId, PAVLPVNODECORE *ppNewTree)
283{
284 /* Get a list of all the modules in this process. */
285 HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE /* no child process handle inheritance */, dwProcessId);
286 if (hProcess == NULL)
287 {
288 VGSvcVerbose(3, "vgsvcPageSharingInspectModules: OpenProcess %x failed with %d\n", dwProcessId, GetLastError());
289 return;
290 }
291
292 HANDLE hSnapshot = g_pfnCreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
293 if (hSnapshot == INVALID_HANDLE_VALUE)
294 {
295 VGSvcVerbose(3, "vgsvcPageSharingInspectModules: CreateToolhelp32Snapshot failed with %d\n", GetLastError());
296 CloseHandle(hProcess);
297 return;
298 }
299
300 VGSvcVerbose(3, "vgsvcPageSharingInspectModules\n");
301
302 MODULEENTRY32 ModuleInfo;
303 BOOL bRet;
304
305 ModuleInfo.dwSize = sizeof(ModuleInfo);
306 bRet = g_pfnModule32First(hSnapshot, &ModuleInfo);
307 do
308 {
309 /** @todo when changing this make sure VBoxService.exe is excluded! */
310 char *pszDot = strrchr(ModuleInfo.szModule, '.');
311 if ( pszDot
312 && (pszDot[1] == 'e' || pszDot[1] == 'E'))
313 continue; /* ignore executables for now. */
314
315 /* Found it before? */
316 PAVLPVNODECORE pRec = RTAvlPVGet(ppNewTree, ModuleInfo.modBaseAddr);
317 if (!pRec)
318 {
319 pRec = RTAvlPVRemove(&g_pKnownModuleTree, ModuleInfo.modBaseAddr);
320 if (!pRec)
321 {
322 /* New module; register it. */
323 PVGSVCPGSHKNOWNMOD pModule = (PVGSVCPGSHKNOWNMOD)RTMemAllocZ(sizeof(*pModule));
324 Assert(pModule);
325 if (!pModule)
326 break;
327
328 pModule->Info = ModuleInfo;
329 pModule->Core.Key = ModuleInfo.modBaseAddr;
330 pModule->hModule = LoadLibraryEx(ModuleInfo.szExePath, 0, DONT_RESOLVE_DLL_REFERENCES);
331 if (pModule->hModule)
332 vgsvcPageSharingRegisterModule(pModule, true /* validate pages */);
333
334 VGSvcVerbose(3, "\n\n MODULE NAME: %s", ModuleInfo.szModule );
335 VGSvcVerbose(3, "\n executable = %s", ModuleInfo.szExePath );
336 VGSvcVerbose(3, "\n process ID = 0x%08X", ModuleInfo.th32ProcessID );
337 VGSvcVerbose(3, "\n base address = %#010p", (uintptr_t) ModuleInfo.modBaseAddr );
338 VGSvcVerbose(3, "\n base size = %d", ModuleInfo.modBaseSize );
339
340 pRec = &pModule->Core;
341 }
342 bool ret = RTAvlPVInsert(ppNewTree, pRec);
343 Assert(ret); NOREF(ret);
344 }
345 } while (g_pfnModule32Next(hSnapshot, &ModuleInfo));
346
347 CloseHandle(hSnapshot);
348 CloseHandle(hProcess);
349}
350
351
352/**
353 * Inspect all running processes for executables and dlls that might be worth sharing
354 * with other VMs.
355 *
356 */
357static void vgsvcPageSharingInspectGuest(void)
358{
359 VGSvcVerbose(3, "vgsvcPageSharingInspectGuest\n");
360 PAVLPVNODECORE pNewTree = NULL;
361
362 /*
363 * Check loaded modules for all running processes.
364 */
365 if ( g_pfnProcess32First
366 && g_pfnProcess32Next
367 && g_pfnModule32First
368 && g_pfnModule32Next
369 && g_pfnCreateToolhelp32Snapshot)
370 {
371 HANDLE hSnapshot = g_pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
372 if (hSnapshot == INVALID_HANDLE_VALUE)
373 {
374 VGSvcVerbose(3, "vgsvcPageSharingInspectGuest: CreateToolhelp32Snapshot failed with %d\n", GetLastError());
375 return;
376 }
377
378 DWORD const dwProcessId = GetCurrentProcessId();
379
380 PROCESSENTRY32 ProcessInfo;
381 ProcessInfo.dwSize = sizeof(ProcessInfo);
382 g_pfnProcess32First(hSnapshot, &ProcessInfo);
383
384 do
385 {
386 /* Skip our own process. */
387 if (ProcessInfo.th32ProcessID != dwProcessId)
388 vgsvcPageSharingInspectModules(ProcessInfo.th32ProcessID, &pNewTree);
389 }
390 while (g_pfnProcess32Next(hSnapshot, &ProcessInfo));
391
392 CloseHandle(hSnapshot);
393 }
394
395 /*
396 * Check all loaded kernel modules.
397 */
398 if (g_pfnZwQuerySystemInformation)
399 {
400 ULONG cbBuffer = 0;
401 PVOID pBuffer = NULL;
402 PRTL_PROCESS_MODULES pSystemModules;
403
404 NTSTATUS ret = g_pfnZwQuerySystemInformation(SystemModuleInformation, (PVOID)&cbBuffer, 0, &cbBuffer);
405 if (!cbBuffer)
406 {
407 VGSvcVerbose(1, "ZwQuerySystemInformation returned length 0\n");
408 goto skipkernelmodules;
409 }
410
411 pBuffer = RTMemAllocZ(cbBuffer);
412 if (!pBuffer)
413 goto skipkernelmodules;
414
415 ret = g_pfnZwQuerySystemInformation(SystemModuleInformation, pBuffer, cbBuffer, &cbBuffer);
416 if (ret != STATUS_SUCCESS)
417 {
418 VGSvcVerbose(1, "ZwQuerySystemInformation returned %x (1)\n", ret);
419 goto skipkernelmodules;
420 }
421
422 pSystemModules = (PRTL_PROCESS_MODULES)pBuffer;
423 for (unsigned i = 0; i < pSystemModules->NumberOfModules; i++)
424 {
425 VGSvcVerbose(4, "\n\n KERNEL MODULE NAME: %s", pSystemModules->Modules[i].FullPathName[pSystemModules->Modules[i].OffsetToFileName] );
426 VGSvcVerbose(4, "\n executable = %s", pSystemModules->Modules[i].FullPathName );
427 VGSvcVerbose(4, "\n flags = 0x%08X\n", pSystemModules->Modules[i].Flags);
428
429 /* User-mode modules seem to have no flags set; skip them as we detected them above. */
430 if (pSystemModules->Modules[i].Flags == 0)
431 continue;
432
433 /* Found it before? */
434 PAVLPVNODECORE pRec = RTAvlPVGet(&pNewTree, pSystemModules->Modules[i].ImageBase);
435 if (!pRec)
436 {
437 pRec = RTAvlPVRemove(&g_pKnownModuleTree, pSystemModules->Modules[i].ImageBase);
438 if (!pRec)
439 {
440 /* New module; register it. */
441 char szFullFilePath[512];
442 PVGSVCPGSHKNOWNMOD pModule = (PVGSVCPGSHKNOWNMOD)RTMemAllocZ(sizeof(*pModule));
443 Assert(pModule);
444 if (!pModule)
445 break;
446
447/** @todo FullPathName not an UTF-8 string is! An ANSI string it is
448 * according to the SYSTEM locale. Best use RtlAnsiStringToUnicodeString to
449 * convert to UTF-16. */
450 strcpy(pModule->Info.szModule,
451 (const char *)&pSystemModules->Modules[i].FullPathName[pSystemModules->Modules[i].OffsetToFileName]);
452 GetSystemDirectoryA(szFullFilePath, sizeof(szFullFilePath));
453
454 /* skip \Systemroot\system32 */
455 char *lpPath = strchr((char *)&pSystemModules->Modules[i].FullPathName[1], '\\');
456 if (!lpPath)
457 {
458 /* Seen just file names in XP; try to locate the file in the system32 and system32\drivers directories. */
459 RTStrCat(szFullFilePath, sizeof(szFullFilePath), "\\");
460 RTStrCat(szFullFilePath, sizeof(szFullFilePath), (const char *)pSystemModules->Modules[i].FullPathName);
461 VGSvcVerbose(3, "Unexpected kernel module name try %s\n", szFullFilePath);
462 if (RTFileExists(szFullFilePath) == false)
463 {
464 GetSystemDirectoryA(szFullFilePath, sizeof(szFullFilePath));
465 RTStrCat(szFullFilePath, sizeof(szFullFilePath), "\\drivers\\");
466 RTStrCat(szFullFilePath, sizeof(szFullFilePath), (const char *)pSystemModules->Modules[i].FullPathName);
467 VGSvcVerbose(3, "Unexpected kernel module name try %s\n", szFullFilePath);
468 if (RTFileExists(szFullFilePath) == false)
469 {
470 VGSvcVerbose(1, "Unexpected kernel module name %s\n", pSystemModules->Modules[i].FullPathName);
471 RTMemFree(pModule);
472 continue;
473 }
474 }
475 }
476 else
477 {
478 lpPath = strchr(lpPath + 1, '\\');
479 if (!lpPath)
480 {
481 VGSvcVerbose(1, "Unexpected kernel module name %s (2)\n", pSystemModules->Modules[i].FullPathName);
482 RTMemFree(pModule);
483 continue;
484 }
485
486 RTStrCat(szFullFilePath, sizeof(szFullFilePath), lpPath);
487 }
488
489 strcpy(pModule->Info.szExePath, szFullFilePath);
490 pModule->Info.modBaseAddr = (BYTE *)pSystemModules->Modules[i].ImageBase;
491 pModule->Info.modBaseSize = pSystemModules->Modules[i].ImageSize;
492
493 pModule->Core.Key = pSystemModules->Modules[i].ImageBase;
494 vgsvcPageSharingRegisterModule(pModule, false /* don't check memory pages */);
495
496 VGSvcVerbose(3, "\n\n KERNEL MODULE NAME: %s", pModule->Info.szModule );
497 VGSvcVerbose(3, "\n executable = %s", pModule->Info.szExePath );
498 VGSvcVerbose(3, "\n base address = %#010p", (uintptr_t)pModule->Info.modBaseAddr );
499 VGSvcVerbose(3, "\n flags = 0x%08X", pSystemModules->Modules[i].Flags);
500 VGSvcVerbose(3, "\n base size = %d", pModule->Info.modBaseSize );
501
502 pRec = &pModule->Core;
503 }
504 bool fRet = RTAvlPVInsert(&pNewTree, pRec);
505 Assert(fRet); NOREF(fRet);
506 }
507 }
508skipkernelmodules:
509 if (pBuffer)
510 RTMemFree(pBuffer);
511 }
512
513 /* Delete leftover modules in the old tree. */
514 RTAvlPVDestroy(&g_pKnownModuleTree, vgsvcPageSharingEmptyTreeCallback, NULL);
515
516 /* Check all registered modules. */
517 VbglR3CheckSharedModules();
518
519 /* Activate new module tree. */
520 g_pKnownModuleTree = pNewTree;
521}
522
523
524/**
525 * RTAvlPVDestroy callback.
526 */
527static DECLCALLBACK(int) vgsvcPageSharingEmptyTreeCallback(PAVLPVNODECORE pNode, void *pvUser)
528{
529 PVGSVCPGSHKNOWNMOD pModule = (PVGSVCPGSHKNOWNMOD)pNode;
530 bool *pfUnregister = (bool *)pvUser;
531
532 VGSvcVerbose(3, "vgsvcPageSharingEmptyTreeCallback %s %s\n", pModule->Info.szModule, pModule->szFileVersion);
533
534 /* Dereference module in the hypervisor. */
535 if ( !pfUnregister
536 || *pfUnregister)
537 {
538 int rc = VbglR3UnregisterSharedModule(pModule->Info.szModule, pModule->szFileVersion,
539 (uintptr_t)pModule->Info.modBaseAddr, pModule->Info.modBaseSize);
540 AssertRC(rc);
541 }
542
543 if (pModule->hModule)
544 FreeLibrary(pModule->hModule);
545 RTMemFree(pNode);
546 return 0;
547}
548
549
550#else /* !RT_OS_WINDOWS */
551
552static void vgsvcPageSharingInspectGuest(void)
553{
554 /** @todo other platforms */
555}
556
557#endif /* !RT_OS_WINDOWS */
558
559/** @interface_method_impl{VBOXSERVICE,pfnInit} */
560static DECLCALLBACK(int) vgsvcPageSharingInit(void)
561{
562 VGSvcVerbose(3, "vgsvcPageSharingInit\n");
563
564 int rc = RTSemEventMultiCreate(&g_PageSharingEvent);
565 AssertRCReturn(rc, rc);
566
567#ifdef RT_OS_WINDOWS
568 rc = VbglR3GetSessionId(&g_idSession);
569 if (RT_FAILURE(rc))
570 {
571 if (rc == VERR_IO_GEN_FAILURE)
572 VGSvcVerbose(0, "PageSharing: Page sharing support is not available by the host\n");
573 else
574 VGSvcError("vgsvcPageSharingInit: Failed with rc=%Rrc\n", rc);
575
576 rc = VERR_SERVICE_DISABLED;
577
578 RTSemEventMultiDestroy(g_PageSharingEvent);
579 g_PageSharingEvent = NIL_RTSEMEVENTMULTI;
580
581 }
582#endif
583
584 return rc;
585}
586
587
588/**
589 * @interface_method_impl{VBOXSERVICE,pfnWorker}
590 */
591static DECLCALLBACK(int) vgsvcPageSharingWorker(bool volatile *pfShutdown)
592{
593 /*
594 * Tell the control thread that it can continue
595 * spawning services.
596 */
597 RTThreadUserSignal(RTThreadSelf());
598
599 /*
600 * Now enter the loop retrieving runtime data continuously.
601 */
602 for (;;)
603 {
604 bool fEnabled = VbglR3PageSharingIsEnabled();
605 VGSvcVerbose(3, "vgsvcPageSharingWorker: enabled=%d\n", fEnabled);
606
607 if (fEnabled)
608 vgsvcPageSharingInspectGuest();
609
610 /*
611 * Block for a minute.
612 *
613 * The event semaphore takes care of ignoring interruptions and it
614 * allows us to implement service wakeup later.
615 */
616 if (*pfShutdown)
617 break;
618 int rc = RTSemEventMultiWait(g_PageSharingEvent, 60000);
619 if (*pfShutdown)
620 break;
621 if (rc != VERR_TIMEOUT && RT_FAILURE(rc))
622 {
623 VGSvcError("vgsvcPageSharingWorker: RTSemEventMultiWait failed; rc=%Rrc\n", rc);
624 break;
625 }
626#ifdef RT_OS_WINDOWS
627 uint64_t idNewSession = g_idSession;
628 rc = VbglR3GetSessionId(&idNewSession);
629 AssertRC(rc);
630
631 if (idNewSession != g_idSession)
632 {
633 bool fUnregister = false;
634
635 VGSvcVerbose(3, "vgsvcPageSharingWorker: VM was restored!!\n");
636 /* The VM was restored, so reregister all modules the next time. */
637 RTAvlPVDestroy(&g_pKnownModuleTree, vgsvcPageSharingEmptyTreeCallback, &fUnregister);
638 g_pKnownModuleTree = NULL;
639
640 g_idSession = idNewSession;
641 }
642#endif
643 }
644
645 RTSemEventMultiDestroy(g_PageSharingEvent);
646 g_PageSharingEvent = NIL_RTSEMEVENTMULTI;
647
648 VGSvcVerbose(3, "vgsvcPageSharingWorker: finished thread\n");
649 return 0;
650}
651
652#ifdef RT_OS_WINDOWS
653
654/**
655 * This gets control when VBoxService is launched with "pagefusion" by
656 * vgsvcPageSharingWorkerProcess().
657 *
658 * @returns RTEXITCODE_SUCCESS.
659 *
660 * @remarks It won't normally return since the parent drops the shutdown hint
661 * via RTProcTerminate().
662 */
663RTEXITCODE VGSvcPageSharingWorkerChild(void)
664{
665 VGSvcVerbose(3, "vgsvcPageSharingInitFork\n");
666
667 bool fShutdown = false;
668 vgsvcPageSharingInit();
669 vgsvcPageSharingWorker(&fShutdown);
670
671 return RTEXITCODE_SUCCESS;
672}
673
674
675/**
676 * @interface_method_impl{VBOXSERVICE,pfnWorker}
677 */
678static DECLCALLBACK(int) vgsvcPageSharingWorkerProcess(bool volatile *pfShutdown)
679{
680 RTPROCESS hProcess = NIL_RTPROCESS;
681 int rc;
682
683 /*
684 * Tell the control thread that it can continue
685 * spawning services.
686 */
687 RTThreadUserSignal(RTThreadSelf());
688
689 /*
690 * Now enter the loop retrieving runtime data continuously.
691 */
692 for (;;)
693 {
694 bool fEnabled = VbglR3PageSharingIsEnabled();
695 VGSvcVerbose(3, "vgsvcPageSharingWorkerProcess: enabled=%d\n", fEnabled);
696
697 /*
698 * Start a 2nd VBoxService process to deal with page fusion as we do
699 * not wish to dummy load dlls into this process. (First load with
700 * DONT_RESOLVE_DLL_REFERENCES, 2nd normal -> dll init routines not called!)
701 */
702 if ( fEnabled
703 && hProcess == NIL_RTPROCESS)
704 {
705 char szExeName[256];
706 char *pszExeName = RTProcGetExecutablePath(szExeName, sizeof(szExeName));
707 if (pszExeName)
708 {
709 char const *papszArgs[3];
710 papszArgs[0] = pszExeName;
711 papszArgs[1] = "pagefusion";
712 papszArgs[2] = NULL;
713 rc = RTProcCreate(pszExeName, papszArgs, RTENV_DEFAULT, 0 /* normal child */, &hProcess);
714 if (RT_FAILURE(rc))
715 VGSvcError("vgsvcPageSharingWorkerProcess: RTProcCreate %s failed; rc=%Rrc\n", pszExeName, rc);
716 }
717 }
718
719 /*
720 * Block for a minute.
721 *
722 * The event semaphore takes care of ignoring interruptions and it
723 * allows us to implement service wakeup later.
724 */
725 if (*pfShutdown)
726 break;
727 rc = RTSemEventMultiWait(g_PageSharingEvent, 60000);
728 if (*pfShutdown)
729 break;
730 if (rc != VERR_TIMEOUT && RT_FAILURE(rc))
731 {
732 VGSvcError("vgsvcPageSharingWorkerProcess: RTSemEventMultiWait failed; rc=%Rrc\n", rc);
733 break;
734 }
735 }
736
737 if (hProcess != NIL_RTPROCESS)
738 RTProcTerminate(hProcess);
739
740 VGSvcVerbose(3, "vgsvcPageSharingWorkerProcess: finished thread\n");
741 return 0;
742}
743
744#endif /* RT_OS_WINDOWS */
745
746/**
747 * @interface_method_impl{VBOXSERVICE,pfnStop}
748 */
749static DECLCALLBACK(void) vgsvcPageSharingStop(void)
750{
751 RTSemEventMultiSignal(g_PageSharingEvent);
752}
753
754
755/**
756 * @interface_method_impl{VBOXSERVICE,pfnTerm}
757 */
758static DECLCALLBACK(void) vgsvcPageSharingTerm(void)
759{
760 if (g_PageSharingEvent != NIL_RTSEMEVENTMULTI)
761 {
762 RTSemEventMultiDestroy(g_PageSharingEvent);
763 g_PageSharingEvent = NIL_RTSEMEVENTMULTI;
764 }
765}
766
767
768/**
769 * The 'pagesharing' service description.
770 */
771VBOXSERVICE g_PageSharing =
772{
773 /* pszName. */
774 "pagesharing",
775 /* pszDescription. */
776 "Page Sharing",
777 /* pszUsage. */
778 NULL,
779 /* pszOptions. */
780 NULL,
781 /* methods */
782 VGSvcDefaultPreInit,
783 VGSvcDefaultOption,
784 vgsvcPageSharingInit,
785#ifdef RT_OS_WINDOWS
786 vgsvcPageSharingWorkerProcess,
787#else
788 vgsvcPageSharingWorker,
789#endif
790 vgsvcPageSharingStop,
791 vgsvcPageSharingTerm
792};
793
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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