VirtualBox

Changeset 39929 in vbox for trunk


Ignore:
Timestamp:
Feb 1, 2012 12:59:12 PM (13 years ago)
Author:
vboxsync
Message:

VBoxBalloonCtrl: Starting to implement modules concept for ballooning and API monitor (work in progress).

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  
    55
    66#
    7 # Copyright (C) 2011 Oracle Corporation
     7# Copyright (C) 2011-2012 Oracle Corporation
    88#
    99# This file is part of VirtualBox Open Source Edition (OSE), as
     
    2525 VBoxBalloonCtrl_DEFS.win   = _WIN32_WINNT=0x0500
    2626 VBoxBalloonCtrl_SOURCES    = \
    27         VBoxBalloonCtrl.cpp
     27        VBoxWatchdog.cpp      \
     28        VBoxWatchdogUtils.cpp \
     29        VBoxModAPIMonitor.cpp \
     30        VBoxModBallooning.cpp
    2831
    2932include $(KBUILD_PATH)/subfooter.kmk
  • trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxWatchdog.cpp

    r39802 r39929  
    55
    66/*
    7  * Copyright (C) 2011 Oracle Corporation
     7 * Copyright (C) 2011-2012 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    4444#include <iprt/getopt.h>
    4545#include <iprt/initterm.h>
     46#include <iprt/message.h>
    4647#include <iprt/path.h>
    4748#include <iprt/process.h>
     
    5051#include <iprt/string.h>
    5152#include <iprt/system.h>
    52 
    53 #include <map>
     53#include <iprt/time.h>
     54
     55
    5456#include <string>
    5557#include <signal.h>
    5658
    57 #include "VBoxBalloonCtrl.h"
     59#include "VBoxWatchdogInternal.h"
    5860
    5961using namespace com;
     
    6163/* When defined, use a global performance collector instead
    6264 * of a per-machine based one. */
    63 #define VBOX_BALLOONCTRL_GLOBAL_PERFCOL
     65#define VBOX_WATCHDOG_GLOBAL_PERFCOL
     66
     67/** External globals. */
     68bool                 g_fVerbose    = false;
     69ComPtr<IVirtualBox>  g_pVirtualBox = NULL;
     70ComPtr<ISession>     g_pSession    = NULL;
    6471
    6572/** The critical section for keep our stuff in sync. */
    66 static RTCRITSECT g_MapCritSect;
     73static RTCRITSECT    g_MapCritSect;
    6774
    6875/** Set by the signal handler. */
    6976static volatile bool g_fCanceled = false;
    7077
     78/** Logging parameters. */
    7179static uint32_t      g_cHistory = 10;                   /* Enable log rotation, 10 files. */
    7280static uint32_t      g_uHistoryFileTime = RT_SEC_1DAY;  /* Max 1 day per file. */
    7381static uint64_t      g_uHistoryFileSize = 100 * _1M;    /* Max 100MB per file. */
    7482
    75 static bool          g_fVerbose = false;
    76 
    7783#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    7884/** Run in background. */
     
    8187
    8288/**
    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 */
     91static 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 */ }
    91102};
    92103
     
    100111    /** For displayHelp(). */
    101112    { "--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 },
    111113    { "--verbose",              'v',                                       RTGETOPT_REQ_NOTHING },
    112114    { "--pidfile",              'P',                                       RTGETOPT_REQ_STRING },
     
    125127static unsigned long g_ulLowerMemoryLimitMB = 64;
    126128
    127 /** Global objects. */
     129/** Global static objects. */
    128130static ComPtr<IVirtualBoxClient> g_pVirtualBoxClient = NULL;
    129 static ComPtr<IVirtualBox> g_pVirtualBox = NULL;
    130 static ComPtr<ISession> g_pSession = NULL;
    131131static ComPtr<IEventSource> g_pEventSource = NULL;
    132132static ComPtr<IEventSource> g_pEventSourceClient = NULL;
    133133static ComPtr<IEventListener> g_pVBoxEventListener = NULL;
    134 # ifdef VBOX_BALLOONCTRL_GLOBAL_PERFCOL
     134# ifdef VBOX_WATCHDOG_GLOBAL_PERFCOL
    135135static ComPtr<IPerformanceCollector> g_pPerfCollector = NULL;
    136136# endif
    137137static EventQueue *g_pEventQ = NULL;
    138 
    139 /** A machine's internal entry. */
    140 typedef struct VBOXBALLOONCTRL_MACHINE
    141 {
    142     ComPtr<IMachine> machine;
    143     unsigned long ulBalloonSizeMax;
    144 #ifndef VBOX_BALLOONCTRL_GLOBAL_PERFCOL
    145     ComPtr<IPerformanceCollector> collector;
    146 #endif
    147 } 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;
    151138static mapVM g_mapVM;
    152139
    153140/* Prototypes. */
    154 #define serviceLogVerbose(a) if (g_fVerbose) { serviceLog a; }
    155 static void serviceLog(const char *pszFormat, ...);
    156 
    157141static bool machineIsRunning(MachineState_T enmState);
    158142static bool machineHandled(const Bstr &strUuid);
     
    160144static int machineRemove(const Bstr &strUuid);
    161145static 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();
     146static HRESULT watchdogSetup();
     147static void watchdogTeardown();
    172148
    173149#ifdef RT_OS_WINDOWS
     
    219195                        if (RT_SUCCESS(rc))
    220196                        {
     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
    221210                            if (fRegistered && machineHandled(uuid))
    222211                                rc = machineAdd(uuid);
     
    224213                                 rc = machineRemove(uuid);
    225214
     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);
    226254                            int rc2 = RTCritSectLeave(&g_MapCritSect);
    227255                            if (RT_SUCCESS(rc))
     
    233261                }
    234262
    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 
    262263                case VBoxEventType_OnVBoxSVCAvailabilityChanged:
    263264                {
     
    266267                    BOOL fAvailable = FALSE;
    267268                    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. */
    268282                    if (!fAvailable)
    269283                    {
    270284                        serviceLog("VBoxSVC became unavailable\n");
    271 
    272                         balloonCtrlShutdown();
    273                         deleteGlobalObjects();
     285                        watchdogTeardown();
    274286                    }
    275287                    else
    276288                    {
    277289                        serviceLog("VBoxSVC became available\n");
    278                         HRESULT hrc = createGlobalObjects();
     290                        HRESULT hrc = watchdogSetup();
    279291                        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);
    287293                    }
     294
    288295                    break;
    289296                }
     
    301308typedef ListenerImpl<VirtualBoxEventListener> VirtualBoxEventListenerImpl;
    302309VBOX_LISTENER_DECLARE(VirtualBoxEventListenerImpl)
    303 
    304310
    305311/**
     
    344350    signal(SIGBREAK, SIG_DFL);
    345351#endif
    346 }
    347 
    348 /**
    349  * Retrieves the current delta value
    350  *
    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 to
    365          * deflate the balloon. */
    366         lBalloonDelta = (g_ulMemoryBalloonDecrementMB * -1);
    367 
    368         /* Ensure that the delta will not return a negative
    369          * 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;
    388352}
    389353
     
    435399        CHECK_ERROR_BREAK(machine, COMGETTER(State)(&machineState));
    436400
     401    #if 0
    437402        if (   balloonGetMaxSize(machine)
    438403            && machineIsRunning(machineState))
     
    441406            fHandled = true;
    442407        }
     408    #endif
    443409    }
    444410    while (0);
     
    449415/**
    450416 * Adds a specified machine to the list (map) of handled machines.
     417 * Does not do locking -- needs to be done by caller!
    451418 *
    452419 * @return  IPRT status code.
     
    465432        CHECK_ERROR_BREAK(machine, COMGETTER(State)(&machineState));
    466433
     434    #if 0
    467435        if (   !balloonGetMaxSize(machine)
    468436            || !machineIsRunning(machineState))
     
    471439            break;
    472440        }
    473 
    474         VBOXBALLOONCTRL_MACHINE m;
     441    #endif
     442
     443        VBOXWATCHDOG_MACHINE m;
    475444        m.machine = machine;
     445
     446////// TODO: Put this in module!
    476447
    477448        /*
     
    487458        m.machine.queryInterfaceTo(&metricObjects[0]);
    488459
    489 #ifdef VBOX_BALLOONCTRL_GLOBAL_PERFCOL
     460#ifdef VBOX_WATCHDOG_GLOBAL_PERFCOL
    490461        CHECK_ERROR_BREAK(g_pPerfCollector, SetupMetrics(ComSafeArrayAsInParam(metricNames),
    491462                                                         ComSafeArrayAsInParam(metricObjects),
     
    501472                                                    ComSafeArrayAsOutParam(metricAffected)));
    502473#endif
     474
     475///////////////// TODO END
     476
    503477        /*
    504478         * Add machine to map.
     
    507481        Assert(it == g_mapVM.end());
    508482
     483        /* Register all module payloads. */
     484        /* TODO */
     485
    509486        g_mapVM.insert(std::make_pair(strUuid, m));
    510487
     
    518495/**
    519496 * Removes a specified machine from the list of handled machines.
     497 * Does not do locking -- needs to be done by caller!
    520498 *
    521499 * @return  IPRT status code.
     
    524502static int machineRemove(const Bstr &strUuid)
    525503{
    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;
    549521    }
    550522
     
    557529 * fit in our criteria anymore or a machine gets added if we need to handle
    558530 * it now (and didn't before).
     531 * Does not do locking -- needs to be done by caller!
    559532 *
    560533 * @return  IPRT status code.
     
    587560         * Ballooning stuff - start.
    588561         */
    589 
     562#if 0
    590563        /* Our actual ballooning criteria. */
    591564        if (   !balloonIsRequired(&it->second)
     
    601574            AssertRC(rc);
    602575        }
     576#endif
    603577    }
    604578
     
    610584}
    611585
    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_PERFCOL
    643     Assert(!g_pPerfCollector.isNull());
    644     HRESULT hrc = g_pPerfCollector->QueryMetricsData(
    645 #else
    646     Assert(!pMachine->collector.isNull());
    647     HRESULT hrc = pMachine->collector->QueryMetricsData(
    648 #endif
    649                                                 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 0
    660     /* 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             else
    672                 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 #endif
    679 
    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 is
    747  * 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 iteration
    768          * and try next time. */
    769         if (lMemFree <= 0)
    770         {
    771 #ifdef DEBUG
    772             serviceLogVerbose(("%ls: No metrics available yet!\n", strUuid.raw()));
    773 #endif
    774             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             do
    801             {
    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                 else
    811                     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     else
    820         serviceLog("Error: Unable to retrieve metrics for machine \"%ls\", rc=%Rrc",
    821                    strUuid.raw(), vrc);
    822     return vrc;
    823 }
    824 
    825586static void vmListDestroy()
    826587{
     
    833594        while (it != g_mapVM.end())
    834595        {
    835 #ifndef VBOX_BALLOONCTRL_GLOBAL_PERFCOL
     596#ifndef VBOX_WATCHDOG_GLOBAL_PERFCOL
    836597            it->second.collector.setNull();
    837598#endif
     
    902663}
    903664
    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 */
     670static 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))
    921677            {
    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;
    925681            }
    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 */
     693static 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        }
    933715
    934716    return rc;
    935717}
    936718
    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);
     719static 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        }
    963743
    964744    return rc;
    965745}
    966746
    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)
     747static RTEXITCODE watchdogMain(HandlerArg *a)
    979748{
    980749    HRESULT rc = S_OK;
     
    1019788
    1020789        /*
    1021          * Set up ballooning stuff.
     790         * Set up modules.
    1022791         */
    1023         rc = balloonCtrlSetup();
     792        rc = watchdogStartModules();
    1024793        if (FAILED(rc))
    1025794            break;
     
    1030799             * Do the actual work.
    1031800             */
     801            /*
    1032802            vrc = balloonCtrlCheck();
    1033803            if (RT_FAILURE(vrc))
     
    1035805                serviceLog("Error while doing ballooning control; rc=%Rrc\n", vrc);
    1036806                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                }
    1038817
    1039818            /*
     
    1066845        g_pEventSourceClient.setNull();
    1067846
    1068         balloonCtrlShutdown();
     847        vrc = watchdogShutdownModules();
     848        AssertRC(vrc);
    1069849
    1070850        RTCritSectDelete(&g_MapCritSect);
     
    1078858}
    1079859
    1080 static void serviceLog(const char *pszFormat, ...)
     860void serviceLog(const char *pszFormat, ...)
    1081861{
    1082862    va_list args;
     
    1159939}
    1160940
    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 */
     946static 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);
    1164952    for (unsigned i = 0;
    1165953         i < RT_ELEMENTS(g_aOptions);
     
    1182970                break;
    1183971
    1184             case 'i': /* Interval. */
    1185                 pcszDescr = "Sets the check interval in ms (30 seconds).";
    1186                 break;
    1187 
    1188972#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    1189973            case 'b':
     
    1191975                break;
    1192976#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 
    1209977            case 'P':
    1210978                pcszDescr = "Name of the PID file which is created when the daemon was started.";
     
    1231999    }
    12321000
    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");
    12431007}
    12441008
     
    12481012 * @return  HRESULT
    12491013 */
    1250 static HRESULT createGlobalObjects()
     1014static HRESULT watchdogSetup()
    12511015{
    12521016    serviceLogVerbose(("Creating local objects ...\n"));
    12531017
    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);
    12581022    }
    12591023    else
    12601024    {
    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
     1054static 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();
    12671066}
    12681067
     
    12771076        return RTMsgInitFailure(rc);
    12781077
    1279     RTPrintf(VBOX_PRODUCT " Balloon Control " VBOX_VERSION_STRING "\n"
     1078    RTPrintf(VBOX_PRODUCT " Watchdog " VBOX_VERSION_STRING "\n"
    12801079             "(C) " VBOX_C_YEAR " " VBOX_VENDOR "\n"
    12811080             "All rights reserved.\n\n");
     
    12891088    RTGETOPTUNION ValueUnion;
    12901089    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*/);
    12921092    while ((c = RTGetOpt(&GetState, &ValueUnion)))
    12931093    {
     
    12951095        {
    12961096            case 'h':
    1297                 displayHelp();
     1097                displayHelp(argv[0]);
    12981098                return 0;
    1299 
    1300             case 'i': /* Interval. */
    1301                 g_ulTimeoutMS = ValueUnion.u32;
    1302                 if (g_ulTimeoutMS < 500)
    1303                     g_ulTimeoutMS = 500;
    1304                 break;
    13051099
    13061100            case 'v':
     
    13171111                return 0;
    13181112
    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 
    13351113            case 'P':
    13361114                pszPidFile = ValueUnion.psz;
     
    13541132
    13551133            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            }
    13581159        }
    13591160    }
     
    14311232    HRESULT hrc = com::Initialize();
    14321233    if (FAILED(hrc))
    1433         return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM!");
     1234        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM (%Rhrc)!", hrc);
    14341235
    14351236    hrc = g_pVirtualBoxClient.createInprocObject(CLSID_VirtualBoxClient);
    14361237    if (FAILED(hrc))
    14371238    {
    1438         RTMsgError("failed to create the VirtualBoxClient object!");
     1239        RTMsgError("Failed to create the VirtualBoxClient object (%Rhrc)!", hrc);
    14391240        com::ErrorInfo info;
    14401241        if (!info.isFullAvailable() && !info.isBasicAvailable())
     
    14481249    }
    14491250
    1450     hrc = createGlobalObjects();
     1251    hrc = watchdogSetup();
    14511252    if (FAILED(hrc))
    14521253        return RTEXITCODE_FAILURE;
    14531254
    14541255    HandlerArg handlerArg = { argc, argv };
    1455     RTEXITCODE rcExit = balloonCtrlMain(&handlerArg);
     1256    RTEXITCODE rcExit = watchdogMain(&handlerArg);
    14561257
    14571258    EventQueue::getMainEventQueue()->processEventQueue(0);
    14581259
    1459     deleteGlobalObjects();
     1260    watchdogTeardown();
    14601261
    14611262    g_pVirtualBoxClient.setNull();
Note: See TracChangeset for help on using the changeset viewer.

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