VirtualBox

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

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

Very annoying to return informational codes without hitting assertions, so turn it into an error.

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