Index: /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxModBallooning.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxModBallooning.cpp	(revision 59906)
+++ /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxModBallooning.cpp	(revision 59907)
@@ -31,4 +31,8 @@
 #define VBOX_MOD_BALLOONING_NAME "balloon"
 
+/*********************************************************************************************************************************
+*   Local Structures                                                                                                             *
+*********************************************************************************************************************************/
+
 /**
  * The module's RTGetOpt-IDs for the command line.
@@ -58,38 +62,59 @@
 };
 
-static unsigned long g_ulMemoryBalloonTimeoutMS = 0;
-static unsigned long g_ulMemoryBalloonIncrementMB = 0;
-static unsigned long g_ulMemoryBalloonDecrementMB = 0;
-/** Global balloon limit is 0, so disabled. Can be overridden by a per-VM
- *  "VBoxInternal/Guest/BalloonSizeMax" value. */
-static unsigned long g_ulMemoryBalloonMaxMB = 0;
-static unsigned long g_ulMemoryBalloonLowerLimitMB = 0;
-static unsigned long g_ulMemoryBalloonSafetyMB = _1K;
-
 /** The ballooning module's payload. */
 typedef struct VBOXWATCHDOG_BALLOONCTRL_PAYLOAD
 {
-    /** The maximum ballooning size for the VM.
+    /** The maximum ballooning size for the VM set last.
      *  Specify 0 for ballooning disabled. */
-    unsigned long ulBalloonSizeMax;
+    unsigned long ulBalloonMaxLast;
 } VBOXWATCHDOG_BALLOONCTRL_PAYLOAD, *PVBOXWATCHDOG_BALLOONCTRL_PAYLOAD;
 
+/*********************************************************************************************************************************
+*   Globals                                                                                                                      *
+*********************************************************************************************************************************/
+
+static unsigned long g_ulMemoryBalloonTimeoutMS    = 30 * 1000;
+static unsigned long g_ulMemoryBalloonIncrementMB  = 256;
+static unsigned long g_ulMemoryBalloonDecrementMB  = 128;
+/** Command line: Global balloon limit (in MB) for all VMs. Default is 0, which means
+ *  no global limit is set. See balloonGetMaxSize() for more information. */
+static unsigned long g_ulMemoryBalloonMaxMB        = 0;
+static unsigned long g_ulMemoryBalloonLowerLimitMB = 128;
+static unsigned long g_ulMemoryBalloonSafetyMB     = 1024;
+
+/*********************************************************************************************************************************
+*   Local Function Prototypes                                                                                                    *
+*********************************************************************************************************************************/
+static int balloonSetSize(PVBOXWATCHDOG_MACHINE pMachine, unsigned long ulBalloonCur);
 
 /**
  * Retrieves the current delta value
  *
- * @return  long                                Delta (MB) of the balloon to be deflated (<0) or inflated (>0).
- * @param   ulCurrentDesktopBalloonSize         The balloon's current size.
- * @param   ulDesktopFreeMemory                 The VM's current free memory.
- * @param   ulMaxBalloonSize                    The maximum balloon size (MB) it can inflate to.
- */
-static long balloonGetDelta(unsigned long ulCurrentDesktopBalloonSize,
-                            unsigned long ulDesktopFreeMemory, unsigned long ulMaxBalloonSize)
-{
-    if (ulCurrentDesktopBalloonSize > ulMaxBalloonSize)
-        return (ulMaxBalloonSize - ulCurrentDesktopBalloonSize);
+ * @return  long                Delta (MB) of the balloon to be deflated (<0) or inflated (>0).
+ * @param   pMachine            Pointer to the machine's internal structure.
+ * @param   ulGuestMemFree      The guest's current free memory (MB).
+ * @param   ulBalloonOld        The balloon's current (old) size (MB).
+ * @param   ulBalloonNew        The balloon's new size (MB).
+ * @param   ulBalloonMax        The maximum ballooning size (MB) it can inflate to.
+ */
+static long balloonGetDelta(PVBOXWATCHDOG_MACHINE pMachine,
+                            unsigned long ulGuestMemFree,
+                            unsigned long ulBalloonOld, unsigned long ulBalloonNew, unsigned long ulBalloonMax)
+{
+    serviceLogVerbose(("[%ls] ulGuestMemFree=%RU32, ulBalloonOld=%RU32, ulBalloonNew=%RU32, ulBalloonMax=%RU32\n",
+                       pMachine->strName.raw(), ulGuestMemFree, ulBalloonOld, ulBalloonNew, ulBalloonMax));
+
+    /* Make sure that the requested new ballooning size does not
+     * exceed the maximum ballooning size (if set). */
+    if (   ulBalloonMax
+        && (ulBalloonNew > ulBalloonMax))
+    {
+        ulBalloonNew = ulBalloonMax;
+    }
+
+RT_BREAKPOINT();
 
     long lBalloonDelta = 0;
-    if (ulDesktopFreeMemory < g_ulMemoryBalloonLowerLimitMB)
+    if (ulGuestMemFree < g_ulMemoryBalloonLowerLimitMB)
     {
         /* Guest is running low on memory, we need to
@@ -99,23 +124,28 @@
         /* Ensure that the delta will not return a negative
          * balloon size. */
-        if ((long)ulCurrentDesktopBalloonSize + lBalloonDelta < 0)
+        if ((long)ulBalloonOld + lBalloonDelta < 0)
             lBalloonDelta = 0;
     }
-    else if (ulMaxBalloonSize > ulCurrentDesktopBalloonSize)
+    else if (ulBalloonNew > ulBalloonOld) /* Inflate. */
     {
         /* We want to inflate the balloon if we have room. */
-        long lIncrement = g_ulMemoryBalloonIncrementMB;
-        while (lIncrement >= 16 && (ulDesktopFreeMemory - lIncrement) < g_ulMemoryBalloonLowerLimitMB)
-        {
-            lIncrement = (lIncrement / 2);
-        }
-
-        if ((ulDesktopFreeMemory - lIncrement) > g_ulMemoryBalloonLowerLimitMB)
-            lBalloonDelta = lIncrement;
-    }
-    if (ulCurrentDesktopBalloonSize + lBalloonDelta > ulMaxBalloonSize)
-        lBalloonDelta = (ulMaxBalloonSize - ulCurrentDesktopBalloonSize);
-
-    /* Limit the ballooning to the available memory, leaving some free.
+        unsigned long ulIncrement = g_ulMemoryBalloonIncrementMB;
+        while (ulIncrement >= 16 && (ulGuestMemFree - ulIncrement) < g_ulMemoryBalloonLowerLimitMB)
+            ulIncrement = (ulIncrement / 2);
+
+        if ((ulGuestMemFree - ulIncrement) > g_ulMemoryBalloonLowerLimitMB)
+            lBalloonDelta = (long)ulIncrement;
+
+        /* Make sure we're still within bounds. */
+        Assert(lBalloonDelta >= 0);
+        if (ulBalloonOld + lBalloonDelta > ulBalloonNew)
+            lBalloonDelta = RT_MIN(g_ulMemoryBalloonIncrementMB, ulBalloonNew - ulBalloonOld);
+    }
+    else if (ulBalloonNew < ulBalloonOld) /* Deflate. */
+    {
+        lBalloonDelta = RT_CLAMP(g_ulMemoryBalloonDecrementMB, 0, ulBalloonOld - ulBalloonNew) * -1;
+    }
+
+    /* Limit the ballooning to the available host memory, leaving some free.
      * If anything fails clamp the delta to 0. */
     if (lBalloonDelta < 0)
@@ -141,41 +171,121 @@
  * Determines the maximum balloon size to set for the specified machine.
  *
- * @return  unsigned long           Balloon size (in MB) to set, 0 if no ballooning required.
- * @param   rptrMachine             Pointer to interface of specified machine.
- */
-static unsigned long balloonGetMaxSize(const ComPtr<IMachine> &rptrMachine)
-{
+ * @return  unsigned long           Maximum ballooning size (in MB), 0 if no maximum set.
+ * @param   pMachine                Machine to determine maximum ballooning size for.
+ */
+static unsigned long balloonGetMaxSize(PVBOXWATCHDOG_MACHINE pMachine)
+{
+    const ComPtr<IMachine> &rptrMachine = pMachine->machine;
+
     /*
-     * Try to retrieve the balloon maximum size via the following order:
-     *  - command line parameter ("--balloon-max")
-     *  Legacy (VBoxBalloonCtrl):
-     *  - per-VM parameter ("VBoxInternal/Guest/BalloonSizeMax")
-     *  Global:
-     *  - global parameter ("VBoxInternal/Guest/BalloonSizeMax")
-     *  New:
-     *  - per-VM parameter ("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax")
+     * Is a maximum ballooning size set? Make sure we're within bounds.
      *
-     *  By default (e.g. if none of above is set), ballooning is disabled.
+     * The maximum balloning size can be set
+     * - via global extra-data ("VBoxInternal/Guest/BalloonSizeMax")
+     * - via command line ("--balloon-max")
+     *
+     * Precedence from top to bottom.
      */
-    unsigned long ulBalloonMax = g_ulMemoryBalloonMaxMB;
-    if (!ulBalloonMax)
-    {
-        int vrc = cfgGetValueULong(g_pVirtualBox, rptrMachine,
-                                  "VBoxInternal/Guest/BalloonSizeMax", "VBoxInternal/Guest/BalloonSizeMax", &ulBalloonMax, 0 /* Ballooning disabled */);
-        if (RT_FAILURE(vrc))
+    unsigned long ulBalloonMax = 0;
+    char szSource[64];
+
+    Bstr strValue;
+    HRESULT hr = g_pVirtualBox->GetExtraData(Bstr("VBoxInternal/Guest/BalloonSizeMax").raw(),
+                                             strValue.asOutParam());
+    if (   SUCCEEDED(hr)
+        && strValue.isNotEmpty())
+    {
+        ulBalloonMax = Utf8Str(strValue).toUInt32();
+        if (g_fVerbose)
+            RTStrPrintf(szSource, sizeof(szSource), "global extra-data");
+    }
+
+    if (strValue.isEmpty())
+    {
+        Assert(ulBalloonMax == 0);
+
+        ulBalloonMax = g_ulMemoryBalloonMaxMB;
+        if (g_fVerbose)
+            RTStrPrintf(szSource, sizeof(szSource), "command line");
+    }
+
+    serviceLogVerbose(("[%ls] Maximum balloning size is (%s): %RU32MB\n", pMachine->strName.raw(), szSource, ulBalloonMax));
+    return ulBalloonMax;
+}
+
+/**
+ * Determines the current (set) balloon size of the specified machine.
+ *
+ * @return  IPRT status code.
+ * @param   pMachine                Machine to determine maximum ballooning size for.
+ * @param   pulBalloonCur           Where to store the current (set) balloon size (in MB) on success.
+ */
+static int balloonGetCurrentSize(PVBOXWATCHDOG_MACHINE pMachine, unsigned long *pulBalloonCur)
+{
+    LONG lBalloonCur;
+    int vrc = getMetric(pMachine, L"Guest/RAM/Usage/Balloon", &lBalloonCur);
+    if (RT_SUCCESS(vrc))
+    {
+        lBalloonCur /= 1024; /* Convert to MB. */
+        if (pulBalloonCur)
+            *pulBalloonCur = (unsigned long)lBalloonCur;
+    }
+
+    return vrc;
+}
+
+/**
+ * Determines the requested balloon size to set for the specified machine.
+ *
+ * @return  unsigned long           Requested ballooning size (in MB), 0 if ballooning should be disabled.
+ * @param   pMachine                Machine to determine maximum ballooning size for.
+ */
+static unsigned long balloonGetRequestedSize(PVBOXWATCHDOG_MACHINE pMachine)
+{
+    const ComPtr<IMachine> &rptrMachine = pMachine->machine;
+
+    /*
+     * The maximum balloning size can be set
+     * - via per-VM extra-data ("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax")
+     * - via per-VM extra-data (legacy) ("VBoxInternal/Guest/BalloonSizeMax")
+     *
+     * Precedence from top to bottom.
+     */
+    unsigned long ulBalloonReq;
+    char szSource[64];
+
+    Bstr strValue;
+    HRESULT hr = rptrMachine->GetExtraData(Bstr("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax").raw(),
+                                           strValue.asOutParam());
+    if (   SUCCEEDED(hr)
+        && strValue.isNotEmpty())
+    {
+        ulBalloonReq = Utf8Str(strValue).toUInt32();
+        if (g_fVerbose)
+            RTStrPrintf(szSource, sizeof(szSource), "per-VM extra-data");
+    }
+    else
+    {
+        hr = rptrMachine->GetExtraData(Bstr("VBoxInternal/Guest/BalloonSizeMax").raw(),
+                                       strValue.asOutParam());
+        if (   SUCCEEDED(hr)
+            && strValue.isNotEmpty())
         {
-            /* Try (new) VBoxWatch per-VM approach. */
-            Bstr strValue;
-            HRESULT rc = rptrMachine->GetExtraData(Bstr("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax").raw(),
-                                                   strValue.asOutParam());
-            if (   SUCCEEDED(rc)
-                && !strValue.isEmpty())
-            {
-                ulBalloonMax = Utf8Str(strValue).toUInt32();
-            }
+            ulBalloonReq = Utf8Str(strValue).toUInt32();
+            if (g_fVerbose)
+                RTStrPrintf(szSource, sizeof(szSource), "per-VM extra-data (legacy)");
         }
     }
 
-    return ulBalloonMax;
+    if (   FAILED(hr)
+        || strValue.isEmpty())
+    {
+        ulBalloonReq = 0;
+        if (g_fVerbose)
+            RTStrPrintf(szSource, sizeof(szSource), "none (disabled)");
+    }
+
+    serviceLogVerbose(("[%ls] Requested balloning size is (%s): %RU32MB\n", pMachine->strName.raw(), szSource, ulBalloonReq));
+    return ulBalloonReq;
 }
 
@@ -206,26 +316,4 @@
 }
 
-/**
- * Determines whether ballooning is required to the specified machine.
- *
- * @return  bool                    True if ballooning is required, false if not.
- * @param   pMachine                Machine to determine ballooning for.
- */
-static bool balloonIsRequired(PVBOXWATCHDOG_MACHINE pMachine)
-{
-    AssertPtrReturn(pMachine, false);
-
-    /* Only do ballooning if we have a maximum balloon size set. */
-    PVBOXWATCHDOG_BALLOONCTRL_PAYLOAD pData = (PVBOXWATCHDOG_BALLOONCTRL_PAYLOAD)
-                                              payloadFrom(pMachine, VBOX_MOD_BALLOONING_NAME);
-    AssertPtr(pData);
-    pData->ulBalloonSizeMax = pMachine->machine.isNull()
-                              ? 0 : balloonGetMaxSize(pMachine->machine);
-
-    /** @todo Add grouping as a criteria! */
-
-    return pData->ulBalloonSizeMax ? true : false;
-}
-
 int balloonMachineSetup(const Bstr& strUuid)
 {
@@ -280,8 +368,7 @@
  *
  * @return  IPRT status code.
- * @param   strUuid                 UUID of the specified machine.
  * @param   pMachine                Pointer to the machine's internal structure.
  */
-static int balloonMachineUpdate(const Bstr &strUuid, PVBOXWATCHDOG_MACHINE pMachine)
+static int balloonMachineUpdate(PVBOXWATCHDOG_MACHINE pMachine)
 {
     AssertPtrReturn(pMachine, VERR_INVALID_POINTER);
@@ -290,23 +377,23 @@
      * Get metrics collected at this point.
      */
-    LONG lMemFree, lBalloonCur;
-    int vrc = getMetric(pMachine, L"Guest/RAM/Usage/Free", &lMemFree);
+    LONG lGuestMemFree;
+    unsigned long ulBalloonCur;
+
+    int vrc = getMetric(pMachine, L"Guest/RAM/Usage/Free", &lGuestMemFree);
     if (RT_SUCCESS(vrc))
-        vrc = getMetric(pMachine, L"Guest/RAM/Usage/Balloon", &lBalloonCur);
+        vrc = balloonGetCurrentSize(pMachine, &ulBalloonCur);
 
     if (RT_SUCCESS(vrc))
     {
-        /* If guest statistics are not up and running yet, skip this iteration
-         * and try next time. */
-        if (lMemFree <= 0)
+        /* If guest statistics are not up and running yet, skip this iteration and try next time. */
+        if (lGuestMemFree <= 0)
         {
 #ifdef DEBUG
-            serviceLogVerbose(("%ls: No metrics available yet!\n", strUuid.raw()));
+            serviceLogVerbose(("[%ls] No metrics available yet!\n", pMachine->strName.raw()));
 #endif
             return VINF_SUCCESS;
         }
 
-        lMemFree /= 1024;
-        lBalloonCur /= 1024;
+        lGuestMemFree /= 1024;
 
         PVBOXWATCHDOG_BALLOONCTRL_PAYLOAD pData = (PVBOXWATCHDOG_BALLOONCTRL_PAYLOAD)
@@ -314,50 +401,79 @@
         AssertPtr(pData);
 
-        serviceLogVerbose(("%ls: Balloon: %ld, Free mem: %ld, Max ballon: %ld\n",
-                           strUuid.raw(),
-                           lBalloonCur, lMemFree, pData->ulBalloonSizeMax));
+        /* Determine the current set maximum balloon size. */
+        unsigned long ulBalloonMax = balloonGetMaxSize(pMachine);
+
+        /* Determine the requested balloon size. */
+        unsigned long ulBalloonReq = balloonGetRequestedSize(pMachine);
+
+        serviceLogVerbose(("[%ls] Free RAM (MB): %RI32, Ballooning: Current=%RU32MB, Requested=%RU32MB, Maximum=%RU32MB\n",
+                           pMachine->strName.raw(), lGuestMemFree, ulBalloonCur, ulBalloonReq, ulBalloonMax));
+
+        if (   ulBalloonMax
+            && (ulBalloonReq > ulBalloonMax))
+        {
+            serviceLog("[%ls] Warning: Requested ballooning size (%RU32MB) exceeds set maximum ballooning size (%RU32MB), limiting ...\n",
+                       pMachine->strName.raw(), ulBalloonReq, ulBalloonMax);
+        }
 
         /* Calculate current balloon delta. */
-        long lDelta = balloonGetDelta(lBalloonCur, lMemFree, pData->ulBalloonSizeMax);
-        if (lDelta) /* Only do ballooning if there's really smth. to change ... */
+        long lBalloonDelta = balloonGetDelta(pMachine,
+                                             (unsigned long)lGuestMemFree, ulBalloonCur, ulBalloonReq, ulBalloonMax);
+#ifdef DEBUG
+        serviceLogVerbose(("[%ls] lBalloonDelta=%RI32\n", pMachine->strName.raw(), lBalloonDelta));
+#endif
+        if (lBalloonDelta) /* Only do ballooning if there's really smth. to change ... */
         {
-            lBalloonCur = lBalloonCur + lDelta;
-            Assert(lBalloonCur > 0);
-
-            serviceLog("%ls: %s balloon by %ld to %ld ...\n",
-                       strUuid.raw(),
-                       lDelta > 0 ? "Inflating" : "Deflating", lDelta, lBalloonCur);
-
-            if (!g_fDryrun)
-            {
-                /* Open a session for the VM. */
-                HRESULT rc;
-                CHECK_ERROR(pMachine->machine, LockMachine(g_pSession, LockType_Shared));
-
-                do
-                {
-                    /* Get the associated console. */
-                    ComPtr<IConsole> console;
-                    CHECK_ERROR_BREAK(g_pSession, COMGETTER(Console)(console.asOutParam()));
-
-                    ComPtr <IGuest> guest;
-                    rc = console->COMGETTER(Guest)(guest.asOutParam());
-                    if (SUCCEEDED(rc))
-                        CHECK_ERROR_BREAK(guest, COMSETTER(MemoryBalloonSize)(lBalloonCur));
-                    else
-                        serviceLog("Error: Unable to set new balloon size %ld for machine \"%ls\", rc=%Rhrc\n",
-                                   lBalloonCur, strUuid.raw(), rc);
-                    if (FAILED(rc))
-                        vrc = VERR_COM_IPRT_ERROR;
-                } while (0);
-
-                /* Unlock the machine again. */
-                g_pSession->UnlockMachine();
-            }
+            ulBalloonCur = ulBalloonCur + lBalloonDelta;
+
+            serviceLog("[%ls] %s balloon by %RU32MB to %RU32MB ...\n",
+                       pMachine->strName.raw(), lBalloonDelta > 0 ? "Inflating" : "Deflating", RT_ABS(lBalloonDelta), ulBalloonCur);
+
+            vrc = balloonSetSize(pMachine, ulBalloonCur);
+            if (RT_SUCCESS(vrc))
+                pData->ulBalloonMaxLast = ulBalloonMax;
         }
     }
     else
-        serviceLog("Error: Unable to retrieve metrics for machine \"%ls\", rc=%Rrc\n",
-                   strUuid.raw(), vrc);
+        serviceLog("Error: Unable to retrieve metrics for machine '%ls', rc=%Rrc\n",
+                   pMachine->strName.raw(), vrc);
+    return vrc;
+}
+
+static int balloonSetSize(PVBOXWATCHDOG_MACHINE pMachine, unsigned long ulBalloonCur)
+{
+    int vrc = VINF_SUCCESS;
+
+    serviceLogVerbose(("[%ls] Setting balloon size to %RU32MB ...\n", pMachine->strName.raw(), ulBalloonCur));
+
+    if (g_fDryrun)
+        return VINF_SUCCESS;
+
+    /* Open a session for the VM. */
+    HRESULT rc;
+    CHECK_ERROR_RET(pMachine->machine, LockMachine(g_pSession, LockType_Shared), VERR_ACCESS_DENIED);
+
+    do
+    {
+        /* Get the associated console. */
+        ComPtr<IConsole> console;
+        CHECK_ERROR_BREAK(g_pSession, COMGETTER(Console)(console.asOutParam()));
+
+        ComPtr <IGuest> guest;
+        rc = console->COMGETTER(Guest)(guest.asOutParam());
+        if (SUCCEEDED(rc))
+            CHECK_ERROR_BREAK(guest, COMSETTER(MemoryBalloonSize)((LONG)ulBalloonCur));
+        else
+            serviceLog("Error: Unable to set new balloon size %RU32 for machine '%ls', rc=%Rhrc\n",
+                       ulBalloonCur, pMachine->strName.raw(), rc);
+        if (FAILED(rc))
+            vrc = VERR_COM_IPRT_ERROR;
+
+    } while (0);
+
+
+    /* Unlock the machine again. */
+    CHECK_ERROR_RET(g_pSession,  UnlockMachine(), VERR_ACCESS_DENIED);
+
     return vrc;
 }
@@ -465,9 +581,8 @@
 static DECLCALLBACK(int) VBoxModBallooningMain(void)
 {
-    static uint64_t uLast = UINT64_MAX;
-    uint64_t uNow = RTTimeProgramMilliTS() / g_ulMemoryBalloonTimeoutMS;
-    if (uLast == uNow)
+    static uint64_t s_msLast = RTTimeMilliTS();
+    uint64_t msDelta = RTTimeMilliTS() - s_msLast;
+    if (msDelta <= g_ulMemoryBalloonTimeoutMS)
         return VINF_SUCCESS;
-    uLast = uNow;
 
     int rc = VINF_SUCCESS;
@@ -480,9 +595,7 @@
 
         /* Our actual ballooning criteria. */
-        if (   balloonIsPossible(state)
-            && balloonIsRequired(&it->second))
+        if (balloonIsPossible(state))
         {
-            rc = balloonMachineUpdate(it->first /* UUID */,
-                                      &it->second /* Machine */);
+            rc = balloonMachineUpdate(&it->second);
             AssertRC(rc);
         }
@@ -493,4 +606,5 @@
     }
 
+    s_msLast = RTTimeMilliTS();
     return rc;
 }
@@ -514,5 +628,5 @@
                           sizeof(VBOXWATCHDOG_BALLOONCTRL_PAYLOAD), (void**)&pData);
     if (RT_SUCCESS(rc))
-        rc = balloonMachineUpdate(strUuid, pMachine);
+        rc = balloonMachineUpdate(pMachine);
 
     return rc;
@@ -538,5 +652,5 @@
         return VINF_SUCCESS;
 
-    return balloonMachineUpdate(strUuid, pMachine);
+    return balloonMachineUpdate(pMachine);
 }
 
Index: /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxWatchdog.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxWatchdog.cpp	(revision 59906)
+++ /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxWatchdog.cpp	(revision 59907)
@@ -369,4 +369,6 @@
         VBOXWATCHDOG_MACHINE m;
         m.machine = machine;
+        CHECK_ERROR_BREAK(machine, COMGETTER(Name)(m.strName.asOutParam()));
+
         int rc2 = groupAdd(m.groups, strGroups.c_str(), 0 /* Flags */);
         AssertRC(rc2);
Index: /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxWatchdogInternal.h
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxWatchdogInternal.h	(revision 59906)
+++ /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxWatchdogInternal.h	(revision 59907)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2011-2012 Oracle Corporation
+ * Copyright (C) 2011-2016 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -88,4 +88,6 @@
 {
     ComPtr<IMachine> machine;
+    /** The machine's name. For logging. */
+    Bstr strName;
 #ifndef VBOX_WATCHDOG_GLOBAL_PERFCOL
     ComPtr<IPerformanceCollector> collector;
Index: /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxWatchdogUtils.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxWatchdogUtils.cpp	(revision 59906)
+++ /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxWatchdogUtils.cpp	(revision 59907)
@@ -158,5 +158,5 @@
     AssertReturn(cbSize, VERR_INVALID_PARAMETER);
 
-    void *pvData = RTMemAlloc(cbSize);
+    void *pvData = RTMemAllocZ(cbSize);
     AssertPtrReturn(pvData, VERR_NO_MEMORY);
 
