- Timestamp:
- Feb 1, 2012 12:59:12 PM (13 years ago)
- Location:
- trunk/src/VBox/Frontends/VBoxBalloonCtrl
- Files:
-
- 1 deleted
- 1 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxBalloonCtrl/Makefile.kmk
r36693 r39929 5 5 6 6 # 7 # Copyright (C) 2011 Oracle Corporation7 # Copyright (C) 2011-2012 Oracle Corporation 8 8 # 9 9 # This file is part of VirtualBox Open Source Edition (OSE), as … … 25 25 VBoxBalloonCtrl_DEFS.win = _WIN32_WINNT=0x0500 26 26 VBoxBalloonCtrl_SOURCES = \ 27 VBoxBalloonCtrl.cpp 27 VBoxWatchdog.cpp \ 28 VBoxWatchdogUtils.cpp \ 29 VBoxModAPIMonitor.cpp \ 30 VBoxModBallooning.cpp 28 31 29 32 include $(KBUILD_PATH)/subfooter.kmk -
trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxWatchdog.cpp
r39802 r39929 5 5 6 6 /* 7 * Copyright (C) 2011 Oracle Corporation7 * Copyright (C) 2011-2012 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 44 44 #include <iprt/getopt.h> 45 45 #include <iprt/initterm.h> 46 #include <iprt/message.h> 46 47 #include <iprt/path.h> 47 48 #include <iprt/process.h> … … 50 51 #include <iprt/string.h> 51 52 #include <iprt/system.h> 52 53 #include <map> 53 #include <iprt/time.h> 54 55 54 56 #include <string> 55 57 #include <signal.h> 56 58 57 #include "VBox BalloonCtrl.h"59 #include "VBoxWatchdogInternal.h" 58 60 59 61 using namespace com; … … 61 63 /* When defined, use a global performance collector instead 62 64 * of a per-machine based one. */ 63 #define VBOX_BALLOONCTRL_GLOBAL_PERFCOL 65 #define VBOX_WATCHDOG_GLOBAL_PERFCOL 66 67 /** External globals. */ 68 bool g_fVerbose = false; 69 ComPtr<IVirtualBox> g_pVirtualBox = NULL; 70 ComPtr<ISession> g_pSession = NULL; 64 71 65 72 /** The critical section for keep our stuff in sync. */ 66 static RTCRITSECT g_MapCritSect;73 static RTCRITSECT g_MapCritSect; 67 74 68 75 /** Set by the signal handler. */ 69 76 static volatile bool g_fCanceled = false; 70 77 78 /** Logging parameters. */ 71 79 static uint32_t g_cHistory = 10; /* Enable log rotation, 10 files. */ 72 80 static uint32_t g_uHistoryFileTime = RT_SEC_1DAY; /* Max 1 day per file. */ 73 81 static uint64_t g_uHistoryFileSize = 100 * _1M; /* Max 100MB per file. */ 74 82 75 static bool g_fVerbose = false;76 77 83 #if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 78 84 /** Run in background. */ … … 81 87 82 88 /** 83 * RTGetOpt-IDs for the command line. 84 */ 85 enum GETOPTDEF_BALLOONCTRL 86 { 87 GETOPTDEF_BALLOONCTRL_BALLOOINC = 1000, 88 GETOPTDEF_BALLOONCTRL_BALLOONDEC, 89 GETOPTDEF_BALLOONCTRL_BALLOONLOWERLIMIT, 90 GETOPTDEF_BALLOONCTRL_BALLOONMAX 89 * The details of the services that has been compiled in. 90 */ 91 static struct 92 { 93 /** Pointer to the service descriptor. */ 94 PCVBOXMODULE pDesc; 95 /** Whether Pre-init was called. */ 96 bool fPreInited; 97 /** Whether the module is enabled or not. */ 98 bool fEnabled; 99 } g_aModules[] = 100 { 101 { &g_ModBallooning, false /* Pre-inited */, true /* Enabled */ } 91 102 }; 92 103 … … 100 111 /** For displayHelp(). */ 101 112 { "--help", 'h', RTGETOPT_REQ_NOTHING }, 102 /** Sets g_ulTimeoutMS. */103 { "--interval", 'i', RTGETOPT_REQ_INT32 },104 /** Sets g_ulMemoryBalloonIncrementMB. */105 { "--balloon-inc", GETOPTDEF_BALLOONCTRL_BALLOOINC, RTGETOPT_REQ_INT32 },106 /** Sets g_ulMemoryBalloonDecrementMB. */107 { "--balloon-dec", GETOPTDEF_BALLOONCTRL_BALLOONDEC, RTGETOPT_REQ_INT32 },108 { "--balloon-lower-limit", GETOPTDEF_BALLOONCTRL_BALLOONLOWERLIMIT, RTGETOPT_REQ_INT32 },109 /** Global max. balloon limit. */110 { "--balloon-max", GETOPTDEF_BALLOONCTRL_BALLOONMAX, RTGETOPT_REQ_INT32 },111 113 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, 112 114 { "--pidfile", 'P', RTGETOPT_REQ_STRING }, … … 125 127 static unsigned long g_ulLowerMemoryLimitMB = 64; 126 128 127 /** Global objects. */129 /** Global static objects. */ 128 130 static ComPtr<IVirtualBoxClient> g_pVirtualBoxClient = NULL; 129 static ComPtr<IVirtualBox> g_pVirtualBox = NULL;130 static ComPtr<ISession> g_pSession = NULL;131 131 static ComPtr<IEventSource> g_pEventSource = NULL; 132 132 static ComPtr<IEventSource> g_pEventSourceClient = NULL; 133 133 static ComPtr<IEventListener> g_pVBoxEventListener = NULL; 134 # ifdef VBOX_ BALLOONCTRL_GLOBAL_PERFCOL134 # ifdef VBOX_WATCHDOG_GLOBAL_PERFCOL 135 135 static ComPtr<IPerformanceCollector> g_pPerfCollector = NULL; 136 136 # endif 137 137 static EventQueue *g_pEventQ = NULL; 138 139 /** A machine's internal entry. */140 typedef struct VBOXBALLOONCTRL_MACHINE141 {142 ComPtr<IMachine> machine;143 unsigned long ulBalloonSizeMax;144 #ifndef VBOX_BALLOONCTRL_GLOBAL_PERFCOL145 ComPtr<IPerformanceCollector> collector;146 #endif147 } VBOXBALLOONCTRL_MACHINE, *PVBOXBALLOONCTRL_MACHINE;148 typedef std::map<Bstr, VBOXBALLOONCTRL_MACHINE> mapVM;149 typedef std::map<Bstr, VBOXBALLOONCTRL_MACHINE>::iterator mapVMIter;150 typedef std::map<Bstr, VBOXBALLOONCTRL_MACHINE>::const_iterator mapVMIterConst;151 138 static mapVM g_mapVM; 152 139 153 140 /* Prototypes. */ 154 #define serviceLogVerbose(a) if (g_fVerbose) { serviceLog a; }155 static void serviceLog(const char *pszFormat, ...);156 157 141 static bool machineIsRunning(MachineState_T enmState); 158 142 static bool machineHandled(const Bstr &strUuid); … … 160 144 static int machineRemove(const Bstr &strUuid); 161 145 static int machineUpdate(const Bstr &strUuid, MachineState_T enmState); 162 163 static unsigned long balloonGetMaxSize(const ComPtr<IMachine> &rptrMachine); 164 static bool balloonIsRequired(PVBOXBALLOONCTRL_MACHINE pMachine); 165 static int balloonUpdate(const Bstr &strUuid, PVBOXBALLOONCTRL_MACHINE pMachine); 166 167 static HRESULT balloonCtrlSetup(); 168 static void balloonCtrlShutdown(); 169 170 static HRESULT createGlobalObjects(); 171 static void deleteGlobalObjects(); 146 static HRESULT watchdogSetup(); 147 static void watchdogTeardown(); 172 148 173 149 #ifdef RT_OS_WINDOWS … … 219 195 if (RT_SUCCESS(rc)) 220 196 { 197 for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++) 198 if (g_aModules[j].fEnabled) 199 { 200 int rc2 = fRegistered 201 ? g_aModules[j].pDesc->pfnOnMachineRegistered(uuid) 202 : g_aModules[j].pDesc->pfnOnMachineUnregistered(uuid); 203 if (RT_FAILURE(rc2)) 204 serviceLog("Module '%s' reported an error: %Rrc\n", 205 g_aModules[j].pDesc->pszName, rc); 206 /* Keep going. */ 207 } 208 209 #if 0 221 210 if (fRegistered && machineHandled(uuid)) 222 211 rc = machineAdd(uuid); … … 224 213 rc = machineRemove(uuid); 225 214 215 int rc2 = RTCritSectLeave(&g_MapCritSect); 216 if (RT_SUCCESS(rc)) 217 rc = rc2; 218 AssertRC(rc); 219 #endif 220 } 221 } 222 break; 223 } 224 225 case VBoxEventType_OnMachineStateChanged: 226 { 227 ComPtr<IMachineStateChangedEvent> pEvent = aEvent; 228 Assert(pEvent); 229 230 MachineState_T machineState; 231 Bstr uuid; 232 233 HRESULT hr = pEvent->COMGETTER(State)(&machineState); 234 if (SUCCEEDED(hr)) 235 hr = pEvent->COMGETTER(MachineId)(uuid.asOutParam()); 236 237 if (SUCCEEDED(hr)) 238 { 239 int rc = RTCritSectEnter(&g_MapCritSect); 240 if (RT_SUCCESS(rc)) 241 { 242 for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++) 243 if (g_aModules[j].fEnabled) 244 { 245 int rc2 = g_aModules[j].pDesc->pfnOnMachineStateChanged(uuid, 246 machineState); 247 if (RT_FAILURE(rc2)) 248 serviceLog("Module '%s' reported an error: %Rrc\n", 249 g_aModules[j].pDesc->pszName, rc); 250 /* Keep going. */ 251 } 252 253 //rc = machineUpdate(uuid, machineState); 226 254 int rc2 = RTCritSectLeave(&g_MapCritSect); 227 255 if (RT_SUCCESS(rc)) … … 233 261 } 234 262 235 case VBoxEventType_OnMachineStateChanged:236 {237 ComPtr<IMachineStateChangedEvent> pEvent = aEvent;238 Assert(pEvent);239 240 MachineState_T machineState;241 Bstr uuid;242 243 HRESULT hr = pEvent->COMGETTER(State)(&machineState);244 if (SUCCEEDED(hr))245 hr = pEvent->COMGETTER(MachineId)(uuid.asOutParam());246 247 if (SUCCEEDED(hr))248 {249 int rc = RTCritSectEnter(&g_MapCritSect);250 if (RT_SUCCESS(rc))251 {252 rc = machineUpdate(uuid, machineState);253 int rc2 = RTCritSectLeave(&g_MapCritSect);254 if (RT_SUCCESS(rc))255 rc = rc2;256 AssertRC(rc);257 }258 }259 break;260 }261 262 263 case VBoxEventType_OnVBoxSVCAvailabilityChanged: 263 264 { … … 266 267 BOOL fAvailable = FALSE; 267 268 pVSACEv->COMGETTER(Available)(&fAvailable); 269 270 /* First, notify all modules. */ 271 for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++) 272 if (g_aModules[j].fEnabled) 273 { 274 int rc2 = g_aModules[j].pDesc->pfnOnServiceStateChanged(RT_BOOL(fAvailable)); 275 if (RT_FAILURE(rc2)) 276 serviceLog("Module '%s' reported an error: %Rrc\n", 277 g_aModules[j].pDesc->pszName, rc2); 278 /* Keep going. */ 279 } 280 281 /* Do global teardown/re-creation stuff. */ 268 282 if (!fAvailable) 269 283 { 270 284 serviceLog("VBoxSVC became unavailable\n"); 271 272 balloonCtrlShutdown(); 273 deleteGlobalObjects(); 285 watchdogTeardown(); 274 286 } 275 287 else 276 288 { 277 289 serviceLog("VBoxSVC became available\n"); 278 HRESULT hrc = createGlobalObjects();290 HRESULT hrc = watchdogSetup(); 279 291 if (FAILED(hrc)) 280 serviceLog("Unable to re-create local COM objects (rc=%Rhrc)!\n", hrc); 281 else 282 { 283 hrc = balloonCtrlSetup(); 284 if (FAILED(hrc)) 285 serviceLog("Unable to re-set up ballooning (rc=%Rhrc)!\n", hrc); 286 } 292 serviceLog("Unable to re-set up watchdog (rc=%Rhrc)!\n", hrc); 287 293 } 294 288 295 break; 289 296 } … … 301 308 typedef ListenerImpl<VirtualBoxEventListener> VirtualBoxEventListenerImpl; 302 309 VBOX_LISTENER_DECLARE(VirtualBoxEventListenerImpl) 303 304 310 305 311 /** … … 344 350 signal(SIGBREAK, SIG_DFL); 345 351 #endif 346 }347 348 /**349 * Retrieves the current delta value350 *351 * @return long Delta (MB) of the balloon to be deflated (<0) or inflated (>0).352 * @param ulCurrentDesktopBalloonSize The balloon's current size.353 * @param ulDesktopFreeMemory The VM's current free memory.354 * @param ulMaxBalloonSize The maximum balloon size (MB) it can inflate to.355 */356 static long getlBalloonDelta(unsigned long ulCurrentDesktopBalloonSize, unsigned long ulDesktopFreeMemory, unsigned long ulMaxBalloonSize)357 {358 if (ulCurrentDesktopBalloonSize > ulMaxBalloonSize)359 return (ulMaxBalloonSize - ulCurrentDesktopBalloonSize);360 361 long lBalloonDelta = 0;362 if (ulDesktopFreeMemory < g_ulLowerMemoryLimitMB)363 {364 /* Guest is running low on memory, we need to365 * deflate the balloon. */366 lBalloonDelta = (g_ulMemoryBalloonDecrementMB * -1);367 368 /* Ensure that the delta will not return a negative369 * balloon size. */370 if ((long)ulCurrentDesktopBalloonSize + lBalloonDelta < 0)371 lBalloonDelta = 0;372 }373 else if (ulMaxBalloonSize > ulCurrentDesktopBalloonSize)374 {375 /* We want to inflate the balloon if we have room. */376 long lIncrement = g_ulMemoryBalloonIncrementMB;377 while (lIncrement >= 16 && (ulDesktopFreeMemory - lIncrement) < g_ulLowerMemoryLimitMB)378 {379 lIncrement = (lIncrement / 2);380 }381 382 if ((ulDesktopFreeMemory - lIncrement) > g_ulLowerMemoryLimitMB)383 lBalloonDelta = lIncrement;384 }385 if (ulCurrentDesktopBalloonSize + lBalloonDelta > ulMaxBalloonSize)386 lBalloonDelta = (ulMaxBalloonSize - ulCurrentDesktopBalloonSize);387 return lBalloonDelta;388 352 } 389 353 … … 435 399 CHECK_ERROR_BREAK(machine, COMGETTER(State)(&machineState)); 436 400 401 #if 0 437 402 if ( balloonGetMaxSize(machine) 438 403 && machineIsRunning(machineState)) … … 441 406 fHandled = true; 442 407 } 408 #endif 443 409 } 444 410 while (0); … … 449 415 /** 450 416 * Adds a specified machine to the list (map) of handled machines. 417 * Does not do locking -- needs to be done by caller! 451 418 * 452 419 * @return IPRT status code. … … 465 432 CHECK_ERROR_BREAK(machine, COMGETTER(State)(&machineState)); 466 433 434 #if 0 467 435 if ( !balloonGetMaxSize(machine) 468 436 || !machineIsRunning(machineState)) … … 471 439 break; 472 440 } 473 474 VBOXBALLOONCTRL_MACHINE m; 441 #endif 442 443 VBOXWATCHDOG_MACHINE m; 475 444 m.machine = machine; 445 446 ////// TODO: Put this in module! 476 447 477 448 /* … … 487 458 m.machine.queryInterfaceTo(&metricObjects[0]); 488 459 489 #ifdef VBOX_ BALLOONCTRL_GLOBAL_PERFCOL460 #ifdef VBOX_WATCHDOG_GLOBAL_PERFCOL 490 461 CHECK_ERROR_BREAK(g_pPerfCollector, SetupMetrics(ComSafeArrayAsInParam(metricNames), 491 462 ComSafeArrayAsInParam(metricObjects), … … 501 472 ComSafeArrayAsOutParam(metricAffected))); 502 473 #endif 474 475 ///////////////// TODO END 476 503 477 /* 504 478 * Add machine to map. … … 507 481 Assert(it == g_mapVM.end()); 508 482 483 /* Register all module payloads. */ 484 /* TODO */ 485 509 486 g_mapVM.insert(std::make_pair(strUuid, m)); 510 487 … … 518 495 /** 519 496 * Removes a specified machine from the list of handled machines. 497 * Does not do locking -- needs to be done by caller! 520 498 * 521 499 * @return IPRT status code. … … 524 502 static int machineRemove(const Bstr &strUuid) 525 503 { 526 int rc = RTCritSectEnter(&g_MapCritSect); 527 if (RT_SUCCESS(rc)) 528 { 529 mapVMIter it = g_mapVM.find(strUuid); 530 if (it != g_mapVM.end()) 531 { 532 /* Must log before erasing the iterator because of the UUID ref! */ 533 serviceLogVerbose(("Removing machine \"%ls\"\n", strUuid.raw())); 534 535 /* 536 * Remove machine from map. 537 */ 538 g_mapVM.erase(it); 539 } 540 else 541 { 542 serviceLogVerbose(("Warning: Removing not added machine \"%ls\"\n", strUuid.raw())); 543 rc = VERR_NOT_FOUND; 544 } 545 546 int rc2 = RTCritSectLeave(&g_MapCritSect); 547 if (RT_SUCCESS(rc)) 548 rc = rc2; 504 int rc = VINF_SUCCESS; 505 506 mapVMIter it = g_mapVM.find(strUuid); 507 if (it != g_mapVM.end()) 508 { 509 /* Must log before erasing the iterator because of the UUID ref! */ 510 serviceLogVerbose(("Removing machine \"%ls\"\n", strUuid.raw())); 511 512 /* 513 * Remove machine from map. 514 */ 515 g_mapVM.erase(it); 516 } 517 else 518 { 519 serviceLogVerbose(("Warning: Removing not added machine \"%ls\"\n", strUuid.raw())); 520 rc = VERR_NOT_FOUND; 549 521 } 550 522 … … 557 529 * fit in our criteria anymore or a machine gets added if we need to handle 558 530 * it now (and didn't before). 531 * Does not do locking -- needs to be done by caller! 559 532 * 560 533 * @return IPRT status code. … … 587 560 * Ballooning stuff - start. 588 561 */ 589 562 #if 0 590 563 /* Our actual ballooning criteria. */ 591 564 if ( !balloonIsRequired(&it->second) … … 601 574 AssertRC(rc); 602 575 } 576 #endif 603 577 } 604 578 … … 610 584 } 611 585 612 /**613 * Retrieves a metric from a specified machine.614 *615 * @return IPRT status code.616 * @param pMachine Pointer to the machine's internal structure.617 * @param strName Name of metric to retrieve.618 * @param pulData Pointer to value to retrieve the actual metric value.619 */620 static int getMetric(PVBOXBALLOONCTRL_MACHINE pMachine, const Bstr& strName, LONG *pulData)621 {622 AssertPtrReturn(pMachine, VERR_INVALID_POINTER);623 AssertPtrReturn(pulData, VERR_INVALID_POINTER);624 625 /* Input. */626 com::SafeArray<BSTR> metricNames(1);627 com::SafeIfaceArray<IUnknown> metricObjects(1);628 pMachine->machine.queryInterfaceTo(&metricObjects[0]);629 630 /* Output. */631 com::SafeArray<BSTR> retNames;632 com::SafeIfaceArray<IUnknown> retObjects;633 com::SafeArray<BSTR> retUnits;634 com::SafeArray<ULONG> retScales;635 com::SafeArray<ULONG> retSequenceNumbers;636 com::SafeArray<ULONG> retIndices;637 com::SafeArray<ULONG> retLengths;638 com::SafeArray<LONG> retData;639 640 /* Query current memory free. */641 strName.cloneTo(&metricNames[0]);642 #ifdef VBOX_BALLOONCTRL_GLOBAL_PERFCOL643 Assert(!g_pPerfCollector.isNull());644 HRESULT hrc = g_pPerfCollector->QueryMetricsData(645 #else646 Assert(!pMachine->collector.isNull());647 HRESULT hrc = pMachine->collector->QueryMetricsData(648 #endif649 ComSafeArrayAsInParam(metricNames),650 ComSafeArrayAsInParam(metricObjects),651 ComSafeArrayAsOutParam(retNames),652 ComSafeArrayAsOutParam(retObjects),653 ComSafeArrayAsOutParam(retUnits),654 ComSafeArrayAsOutParam(retScales),655 ComSafeArrayAsOutParam(retSequenceNumbers),656 ComSafeArrayAsOutParam(retIndices),657 ComSafeArrayAsOutParam(retLengths),658 ComSafeArrayAsOutParam(retData));659 #if 0660 /* Useful for metrics debugging. */661 for (unsigned j = 0; j < retNames.size(); j++)662 {663 Bstr metricUnit(retUnits[j]);664 Bstr metricName(retNames[j]);665 RTPrintf("%-20ls ", metricName.raw());666 const char *separator = "";667 for (unsigned k = 0; k < retLengths[j]; k++)668 {669 if (retScales[j] == 1)670 RTPrintf("%s%d %ls", separator, retData[retIndices[j] + k], metricUnit.raw());671 else672 RTPrintf("%s%d.%02d%ls", separator, retData[retIndices[j] + k] / retScales[j],673 (retData[retIndices[j] + k] * 100 / retScales[j]) % 100, metricUnit.raw());674 separator = ", ";675 }676 RTPrintf("\n");677 }678 #endif679 680 if (SUCCEEDED(hrc))681 *pulData = retData.size() ? retData[retIndices[0]] : 0;682 683 return SUCCEEDED(hrc) ? VINF_SUCCESS : VINF_NOT_SUPPORTED;684 }685 686 /**687 * Determines the maximum balloon size to set for the specified machine.688 *689 * @return unsigned long Balloon size (in MB) to set, 0 if no ballooning required.690 * @param rptrMachine Pointer to interface of specified machine.691 */692 static unsigned long balloonGetMaxSize(const ComPtr<IMachine> &rptrMachine)693 {694 /*695 * Try to retrieve the balloon maximum size via the following order:696 * - command line parameter ("--balloon-max")697 * - per-VM parameter ("VBoxInternal/Guest/BalloonSizeMax")698 * - global parameter ("VBoxInternal/Guest/BalloonSizeMax")699 */700 unsigned long ulBalloonMax = g_ulMemoryBalloonMaxMB; /* Use global limit as default. */701 if (!ulBalloonMax) /* Not set by command line? */702 {703 /* Try per-VM approach. */704 Bstr strValue;705 HRESULT rc = rptrMachine->GetExtraData(Bstr("VBoxInternal/Guest/BalloonSizeMax").raw(),706 strValue.asOutParam());707 if ( SUCCEEDED(rc)708 && !strValue.isEmpty())709 {710 ulBalloonMax = Utf8Str(strValue).toUInt32();711 }712 }713 if (!ulBalloonMax) /* Still not set by per-VM value? */714 {715 /* Try global approach. */716 Bstr strValue;717 HRESULT rc = g_pVirtualBox->GetExtraData(Bstr("VBoxInternal/Guest/BalloonSizeMax").raw(),718 strValue.asOutParam());719 if ( SUCCEEDED(rc)720 && !strValue.isEmpty())721 {722 ulBalloonMax = Utf8Str(strValue).toUInt32();723 }724 }725 return ulBalloonMax;726 }727 728 /**729 * Determines whether ballooning is required to the specified machine.730 *731 * @return bool True if ballooning is required, false if not.732 * @param strUuid UUID of the specified machine.733 */734 static bool balloonIsRequired(PVBOXBALLOONCTRL_MACHINE pMachine)735 {736 AssertPtrReturn(pMachine, false);737 738 /* Only do ballooning if we have a maximum balloon size set. */739 pMachine->ulBalloonSizeMax = pMachine->machine.isNull()740 ? 0 : balloonGetMaxSize(pMachine->machine);741 742 return pMachine->ulBalloonSizeMax ? true : false;743 }744 745 /**746 * Does the actual ballooning and assumes the machine is747 * capable and ready for ballooning.748 *749 * @return IPRT status code.750 * @param strUuid UUID of the specified machine.751 * @param pMachine Pointer to the machine's internal structure.752 */753 static int balloonUpdate(const Bstr &strUuid, PVBOXBALLOONCTRL_MACHINE pMachine)754 {755 AssertPtrReturn(pMachine, VERR_INVALID_POINTER);756 757 /*758 * Get metrics collected at this point.759 */760 LONG lMemFree, lBalloonCur;761 int vrc = getMetric(pMachine, L"Guest/RAM/Usage/Free", &lMemFree);762 if (RT_SUCCESS(vrc))763 vrc = getMetric(pMachine, L"Guest/RAM/Usage/Balloon", &lBalloonCur);764 765 if (RT_SUCCESS(vrc))766 {767 /* If guest statistics are not up and running yet, skip this iteration768 * and try next time. */769 if (lMemFree <= 0)770 {771 #ifdef DEBUG772 serviceLogVerbose(("%ls: No metrics available yet!\n", strUuid.raw()));773 #endif774 return VINF_SUCCESS;775 }776 777 lMemFree /= 1024;778 lBalloonCur /= 1024;779 780 serviceLogVerbose(("%ls: Balloon: %ld, Free mem: %ld, Max ballon: %ld\n",781 strUuid.raw(),782 lBalloonCur, lMemFree, pMachine->ulBalloonSizeMax));783 784 /* Calculate current balloon delta. */785 long lDelta = getlBalloonDelta(lBalloonCur, lMemFree, pMachine->ulBalloonSizeMax);786 if (lDelta) /* Only do ballooning if there's really smth. to change ... */787 {788 lBalloonCur = lBalloonCur + lDelta;789 Assert(lBalloonCur > 0);790 791 serviceLog("%ls: %s balloon by %ld to %ld ...\n",792 strUuid.raw(),793 lDelta > 0 ? "Inflating" : "Deflating", lDelta, lBalloonCur);794 795 HRESULT rc;796 797 /* Open a session for the VM. */798 CHECK_ERROR(pMachine->machine, LockMachine(g_pSession, LockType_Shared));799 800 do801 {802 /* Get the associated console. */803 ComPtr<IConsole> console;804 CHECK_ERROR_BREAK(g_pSession, COMGETTER(Console)(console.asOutParam()));805 806 ComPtr <IGuest> guest;807 rc = console->COMGETTER(Guest)(guest.asOutParam());808 if (SUCCEEDED(rc))809 CHECK_ERROR_BREAK(guest, COMSETTER(MemoryBalloonSize)(lBalloonCur));810 else811 serviceLog("Error: Unable to set new balloon size %ld for machine \"%ls\", rc=%Rhrc",812 lBalloonCur, strUuid.raw(), rc);813 } while (0);814 815 /* Unlock the machine again. */816 g_pSession->UnlockMachine();817 }818 }819 else820 serviceLog("Error: Unable to retrieve metrics for machine \"%ls\", rc=%Rrc",821 strUuid.raw(), vrc);822 return vrc;823 }824 825 586 static void vmListDestroy() 826 587 { … … 833 594 while (it != g_mapVM.end()) 834 595 { 835 #ifndef VBOX_ BALLOONCTRL_GLOBAL_PERFCOL596 #ifndef VBOX_WATCHDOG_GLOBAL_PERFCOL 836 597 it->second.collector.setNull(); 837 598 #endif … … 902 663 } 903 664 904 static int balloonCtrlCheck() 905 { 906 static uint64_t uLast = UINT64_MAX; 907 uint64_t uNow = RTTimeProgramMilliTS() / g_ulTimeoutMS; 908 if (uLast == uNow) 909 return VINF_SUCCESS; 910 uLast = uNow; 911 912 int rc = RTCritSectEnter(&g_MapCritSect); 913 if (RT_SUCCESS(rc)) 914 { 915 mapVMIter it = g_mapVM.begin(); 916 while (it != g_mapVM.end()) 917 { 918 MachineState_T machineState; 919 HRESULT hrc = it->second.machine->COMGETTER(State)(&machineState); 920 if (SUCCEEDED(hrc)) 665 /** 666 * Lazily calls the pfnPreInit method on each service. 667 * 668 * @returns VBox status code, error message displayed. 669 */ 670 static int watchdogLazyPreInit(void) 671 { 672 for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++) 673 if (!g_aModules[j].fPreInited) 674 { 675 int rc = g_aModules[j].pDesc->pfnPreInit(); 676 if (RT_FAILURE(rc)) 921 677 { 922 rc = machineUpdate(it->first /* UUID */, machineState);923 if (RT_FAILURE(rc))924 break;678 serviceLog("Module '%s' failed pre-init: %Rrc\n", 679 g_aModules[j].pDesc->pszName, rc); 680 return rc; 925 681 } 926 it++; 927 } 928 929 int rc2 = RTCritSectLeave(&g_MapCritSect); 930 if (RT_SUCCESS(rc)) 931 rc = rc2; 932 } 682 g_aModules[j].fPreInited = true; 683 } 684 return VINF_SUCCESS; 685 } 686 687 /** 688 * Starts all registered modules. 689 * 690 * @return IPRT status code. 691 * @return int 692 */ 693 static int watchdogStartModules() 694 { 695 int rc = VINF_SUCCESS; 696 697 for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++) 698 if (g_aModules[j].fEnabled) 699 { 700 rc = g_aModules[j].pDesc->pfnInit(); 701 if (RT_FAILURE(rc)) 702 { 703 if (rc != VERR_SERVICE_DISABLED) 704 { 705 serviceLog("Module '%s' failed to initialize: %Rrc\n", 706 g_aModules[j].pDesc->pszName, rc); 707 return rc; 708 } 709 g_aModules[j].fEnabled = false; 710 serviceLog(0, "Module '%s' was disabled because of missing functionality\n", 711 g_aModules[j].pDesc->pszName); 712 713 } 714 } 933 715 934 716 return rc; 935 717 } 936 718 937 static HRESULT balloonCtrlSetup() 938 { 939 HRESULT rc = S_OK; 940 941 serviceLog("Setting up ballooning ...\n"); 942 943 do 944 { 945 /* 946 * Setup metrics. 947 */ 948 #ifdef VBOX_BALLOONCTRL_GLOBAL_PERFCOL 949 CHECK_ERROR_BREAK(g_pVirtualBox, COMGETTER(PerformanceCollector)(g_pPerfCollector.asOutParam())); 950 #endif 951 952 /* 953 * Build up initial VM list. 954 */ 955 int vrc = vmListBuild(); 956 if (RT_FAILURE(vrc)) 957 { 958 rc = VBOX_E_IPRT_ERROR; 959 break; 960 } 961 962 } while (0); 719 static int watchdogShutdownModules() 720 { 721 int rc = VINF_SUCCESS; 722 723 for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++) 724 if (g_aModules[j].fEnabled) 725 { 726 int rc2 = g_aModules[j].pDesc->pfnStop(); 727 if (RT_FAILURE(rc2)) 728 { 729 serviceLog("Module '%s' failed to stop: %Rrc\n", 730 g_aModules[j].pDesc->pszName, rc); 731 /* Keep original rc. */ 732 if (RT_SUCCESS(rc)) 733 rc = rc2; 734 } 735 /* Keep going. */ 736 } 737 738 for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++) 739 if (g_aModules[j].fEnabled) 740 { 741 g_aModules[j].pDesc->pfnTerm(); 742 } 963 743 964 744 return rc; 965 745 } 966 746 967 static void balloonCtrlShutdown() 968 { 969 serviceLog("Shutting down ballooning ...\n"); 970 971 vmListDestroy(); 972 973 #ifdef VBOX_BALLOONCTRL_GLOBAL_PERFCOL 974 g_pPerfCollector.setNull(); 975 #endif 976 } 977 978 static RTEXITCODE balloonCtrlMain(HandlerArg *a) 747 static RTEXITCODE watchdogMain(HandlerArg *a) 979 748 { 980 749 HRESULT rc = S_OK; … … 1019 788 1020 789 /* 1021 * Set up ballooning stuff.790 * Set up modules. 1022 791 */ 1023 rc = balloonCtrlSetup();792 rc = watchdogStartModules(); 1024 793 if (FAILED(rc)) 1025 794 break; … … 1030 799 * Do the actual work. 1031 800 */ 801 /* 1032 802 vrc = balloonCtrlCheck(); 1033 803 if (RT_FAILURE(vrc)) … … 1035 805 serviceLog("Error while doing ballooning control; rc=%Rrc\n", vrc); 1036 806 break; 1037 } 807 }*/ 808 for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++) 809 if (g_aModules[j].fEnabled) 810 { 811 int rc2 = g_aModules[j].pDesc->pfnMain(); 812 if (RT_FAILURE(rc2)) 813 serviceLog("Module '%s' reported an error: %Rrc\n", 814 g_aModules[j].pDesc->pszName, rc); 815 /* Keep going. */ 816 } 1038 817 1039 818 /* … … 1066 845 g_pEventSourceClient.setNull(); 1067 846 1068 balloonCtrlShutdown(); 847 vrc = watchdogShutdownModules(); 848 AssertRC(vrc); 1069 849 1070 850 RTCritSectDelete(&g_MapCritSect); … … 1078 858 } 1079 859 1080 staticvoid serviceLog(const char *pszFormat, ...)860 void serviceLog(const char *pszFormat, ...) 1081 861 { 1082 862 va_list args; … … 1159 939 } 1160 940 1161 static void displayHelp() 1162 { 1163 RTStrmPrintf(g_pStdErr, "\nUsage: VBoxBalloonCtrl [options]\n\nSupported options (default values in brackets):\n"); 941 /** 942 * Displays the help. 943 * 944 * @param pszImage Name of program name (image). 945 */ 946 static void displayHelp(const char *pszImage) 947 { 948 AssertPtrReturnVoid(pszImage); 949 950 RTStrmPrintf(g_pStdErr, "\nUsage: %s [options]\n\nSupported options (default values in brackets):\n", 951 pszImage); 1164 952 for (unsigned i = 0; 1165 953 i < RT_ELEMENTS(g_aOptions); … … 1182 970 break; 1183 971 1184 case 'i': /* Interval. */1185 pcszDescr = "Sets the check interval in ms (30 seconds).";1186 break;1187 1188 972 #if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 1189 973 case 'b': … … 1191 975 break; 1192 976 #endif 1193 case GETOPTDEF_BALLOONCTRL_BALLOOINC:1194 pcszDescr = "Sets the ballooning increment in MB (256 MB).";1195 break;1196 1197 case GETOPTDEF_BALLOONCTRL_BALLOONDEC:1198 pcszDescr = "Sets the ballooning decrement in MB (128 MB).";1199 break;1200 1201 case GETOPTDEF_BALLOONCTRL_BALLOONLOWERLIMIT:1202 pcszDescr = "Sets the ballooning lower limit in MB (64 MB).";1203 break;1204 1205 case GETOPTDEF_BALLOONCTRL_BALLOONMAX:1206 pcszDescr = "Sets the balloon maximum limit in MB (0 MB).";1207 break;1208 1209 977 case 'P': 1210 978 pcszDescr = "Name of the PID file which is created when the daemon was started."; … … 1231 999 } 1232 1000 1233 RTStrmPrintf(g_pStdErr, "\nUse environment variable VBOXBALLOONCTRL_RELEASE_LOG for logging options.\n" 1234 "Set \"VBoxInternal/Guest/BalloonSizeMax\" for a per-VM maximum ballooning size.\n"); 1235 } 1236 1237 static void deleteGlobalObjects() 1238 { 1239 serviceLogVerbose(("Deleting local objects ...\n")); 1240 1241 g_pSession.setNull(); 1242 g_pVirtualBox.setNull(); 1001 RTStrmPrintf(g_pStdErr, "Module options:\n"); 1002 1003 /** @todo Add module options here. */ 1004 1005 /** @todo Change VBOXBALLOONCTRL_RELEASE_LOG to WATCHDOG*. */ 1006 RTStrmPrintf(g_pStdErr, "\nUse environment variable VBOXBALLOONCTRL_RELEASE_LOG for logging options.\n"); 1243 1007 } 1244 1008 … … 1248 1012 * @return HRESULT 1249 1013 */ 1250 static HRESULT createGlobalObjects()1014 static HRESULT watchdogSetup() 1251 1015 { 1252 1016 serviceLogVerbose(("Creating local objects ...\n")); 1253 1017 1254 HRESULT hrc = g_pVirtualBoxClient->COMGETTER(VirtualBox)(g_pVirtualBox.asOutParam());1255 if (FAILED( hrc))1256 { 1257 RTMsgError("Failed to get VirtualBox object (rc=%Rhrc)!", hrc);1018 HRESULT rc = g_pVirtualBoxClient->COMGETTER(VirtualBox)(g_pVirtualBox.asOutParam()); 1019 if (FAILED(rc)) 1020 { 1021 RTMsgError("Failed to get VirtualBox object (rc=%Rhrc)!", rc); 1258 1022 } 1259 1023 else 1260 1024 { 1261 hrc = g_pSession.createInprocObject(CLSID_Session); 1262 if (FAILED(hrc)) 1263 RTMsgError("Failed to create a session object (rc=%Rhrc)!", hrc); 1264 } 1265 1266 return hrc; 1025 rc = g_pSession.createInprocObject(CLSID_Session); 1026 if (FAILED(rc)) 1027 RTMsgError("Failed to create a session object (rc=%Rhrc)!", rc); 1028 } 1029 1030 do 1031 { 1032 /* 1033 * Setup metrics. 1034 */ 1035 #ifdef VBOX_WATCHDOG_GLOBAL_PERFCOL 1036 CHECK_ERROR_BREAK(g_pVirtualBox, COMGETTER(PerformanceCollector)(g_pPerfCollector.asOutParam())); 1037 #endif 1038 1039 /* 1040 * Build up initial VM list. 1041 */ 1042 int vrc = vmListBuild(); 1043 if (RT_FAILURE(vrc)) 1044 { 1045 rc = VBOX_E_IPRT_ERROR; 1046 break; 1047 } 1048 1049 } while (0); 1050 1051 return rc; 1052 } 1053 1054 static void watchdogTeardown() 1055 { 1056 serviceLogVerbose(("Deleting local objects ...\n")); 1057 1058 vmListDestroy(); 1059 1060 #ifdef VBOX_WATCHDOG_GLOBAL_PERFCOL 1061 g_pPerfCollector.setNull(); 1062 #endif 1063 1064 g_pSession.setNull(); 1065 g_pVirtualBox.setNull(); 1267 1066 } 1268 1067 … … 1277 1076 return RTMsgInitFailure(rc); 1278 1077 1279 RTPrintf(VBOX_PRODUCT " Balloon Control" VBOX_VERSION_STRING "\n"1078 RTPrintf(VBOX_PRODUCT " Watchdog " VBOX_VERSION_STRING "\n" 1280 1079 "(C) " VBOX_C_YEAR " " VBOX_VENDOR "\n" 1281 1080 "All rights reserved.\n\n"); … … 1289 1088 RTGETOPTUNION ValueUnion; 1290 1089 RTGETOPTSTATE GetState; 1291 RTGetOptInit(&GetState, argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), 1, 0 /*fFlags*/); 1090 RTGetOptInit(&GetState, argc, argv, 1091 g_aOptions, RT_ELEMENTS(g_aOptions), 1 /* First */, 0 /*fFlags*/); 1292 1092 while ((c = RTGetOpt(&GetState, &ValueUnion))) 1293 1093 { … … 1295 1095 { 1296 1096 case 'h': 1297 displayHelp( );1097 displayHelp(argv[0]); 1298 1098 return 0; 1299 1300 case 'i': /* Interval. */1301 g_ulTimeoutMS = ValueUnion.u32;1302 if (g_ulTimeoutMS < 500)1303 g_ulTimeoutMS = 500;1304 break;1305 1099 1306 1100 case 'v': … … 1317 1111 return 0; 1318 1112 1319 case GETOPTDEF_BALLOONCTRL_BALLOOINC:1320 g_ulMemoryBalloonIncrementMB = ValueUnion.u32;1321 break;1322 1323 case GETOPTDEF_BALLOONCTRL_BALLOONDEC:1324 g_ulMemoryBalloonDecrementMB = ValueUnion.u32;1325 break;1326 1327 case GETOPTDEF_BALLOONCTRL_BALLOONLOWERLIMIT:1328 g_ulLowerMemoryLimitMB = ValueUnion.u32;1329 break;1330 1331 case GETOPTDEF_BALLOONCTRL_BALLOONMAX:1332 g_ulMemoryBalloonMaxMB = ValueUnion.u32;1333 break;1334 1335 1113 case 'P': 1336 1114 pszPidFile = ValueUnion.psz; … … 1354 1132 1355 1133 default: 1356 rc = RTGetOptPrintError(c, &ValueUnion); 1357 return rc; 1134 { 1135 bool fFound = false; 1136 1137 /** @todo Add "--disable-<module>" etc. here! */ 1138 1139 if (!fFound) 1140 { 1141 rc = watchdogLazyPreInit(); 1142 if (rc != RTEXITCODE_SUCCESS) 1143 return rc; 1144 1145 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aModules); j++) 1146 { 1147 rc = g_aModules[j].pDesc->pfnOption(&ValueUnion, c); 1148 fFound = rc == 0; 1149 if (fFound) 1150 break; 1151 if (rc != -1) 1152 return rc; 1153 } 1154 } 1155 if (!fFound) 1156 return RTGetOptPrintError(c, &ValueUnion); 1157 continue; 1158 } 1358 1159 } 1359 1160 } … … 1431 1232 HRESULT hrc = com::Initialize(); 1432 1233 if (FAILED(hrc)) 1433 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM !");1234 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM (%Rhrc)!", hrc); 1434 1235 1435 1236 hrc = g_pVirtualBoxClient.createInprocObject(CLSID_VirtualBoxClient); 1436 1237 if (FAILED(hrc)) 1437 1238 { 1438 RTMsgError(" failed to create the VirtualBoxClient object!");1239 RTMsgError("Failed to create the VirtualBoxClient object (%Rhrc)!", hrc); 1439 1240 com::ErrorInfo info; 1440 1241 if (!info.isFullAvailable() && !info.isBasicAvailable()) … … 1448 1249 } 1449 1250 1450 hrc = createGlobalObjects();1251 hrc = watchdogSetup(); 1451 1252 if (FAILED(hrc)) 1452 1253 return RTEXITCODE_FAILURE; 1453 1254 1454 1255 HandlerArg handlerArg = { argc, argv }; 1455 RTEXITCODE rcExit = balloonCtrlMain(&handlerArg);1256 RTEXITCODE rcExit = watchdogMain(&handlerArg); 1456 1257 1457 1258 EventQueue::getMainEventQueue()->processEventQueue(0); 1458 1259 1459 deleteGlobalObjects();1260 watchdogTeardown(); 1460 1261 1461 1262 g_pVirtualBoxClient.setNull();
Note:
See TracChangeset
for help on using the changeset viewer.