VirtualBox

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

Last change on this file since 58029 was 58029, checked in by vboxsync, 10 years ago

VBoxService: Using prefix 'VGSvc', code style/width cleanups. No real changes.

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