VirtualBox

Changeset 25901 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jan 18, 2010 4:52:21 PM (15 years ago)
Author:
vboxsync
Message:

CPU hotplug: Merge 4th patch. Implements the Main API and a VBoxManage interface to turn CPU hotplug on/off and to add/remove CPUs while the VM is running

Location:
trunk/src/VBox
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp

    r25840 r25901  
    403403
    404404    STDMETHOD(OnMediumChange)(IMediumAttachment * /* aMediumAttachment */)
     405    {
     406        return S_OK;
     407    }
     408
     409    STDMETHOD(OnCPUChange)(ULONG /*aCPU*/, BOOL /* aRemove */)
    405410    {
    406411        return S_OK;
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp

    r25693 r25901  
    116116            CHECK_ERROR_BREAK(console, Reset());
    117117        }
     118        else if (!strcmp(a->argv[1], "unplugcpu"))
     119        {
     120            if (a->argc <= 1 + 1)
     121            {
     122                errorArgument("Missing argument to '%s'. Expected CPU number.", a->argv[1]);
     123                rc = E_FAIL;
     124                break;
     125            }
     126
     127            unsigned n = parseNum(a->argv[2], 32, "CPU");
     128
     129            CHECK_ERROR_BREAK(sessionMachine, HotUnplugCPU(n));
     130        }
     131        else if (!strcmp(a->argv[1], "plugcpu"))
     132        {
     133            if (a->argc <= 1 + 1)
     134            {
     135                errorArgument("Missing argument to '%s'. Expected CPU number.", a->argv[1]);
     136                rc = E_FAIL;
     137                break;
     138            }
     139
     140            unsigned n = parseNum(a->argv[2], 32, "CPU");
     141
     142            CHECK_ERROR_BREAK(sessionMachine, HotPlugCPU(n));
     143        }
    118144        else if (!strcmp(a->argv[1], "poweroff"))
    119145        {
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp

    r25819 r25901  
    7171    MODIFYVM_VTXVPID,
    7272    MODIFYVM_CPUS,
     73    MODIFYVM_CPUHOTPLUG,
     74    MODIFYVM_PLUGCPU,
     75    MODIFYVM_UNPLUGCPU,
    7376    MODIFYVM_SETCPUID,
    7477    MODIFYVM_DELCPUID,
     
    153156    { "--cpuidremoveall",           MODIFYVM_DELALLCPUID,               RTGETOPT_REQ_NOTHING},
    154157    { "--cpus",                     MODIFYVM_CPUS,                      RTGETOPT_REQ_UINT32 },
     158    { "--cpuhotplug",               MODIFYVM_CPUHOTPLUG,                RTGETOPT_REQ_BOOL_ONOFF },
     159    { "--plugcpu",                  MODIFYVM_PLUGCPU,                   RTGETOPT_REQ_UINT32 },
     160    { "--unplugcpu",                MODIFYVM_UNPLUGCPU,                 RTGETOPT_REQ_UINT32 },
    155161    { "--rtcuseutc",                MODIFYVM_RTCUSEUTC,                 RTGETOPT_REQ_BOOL_ONOFF },
    156162    { "--monitorcount",             MODIFYVM_MONITORCOUNT,              RTGETOPT_REQ_UINT32 },
     
    423429            }
    424430
     431            case MODIFYVM_CPUHOTPLUG:
     432            {
     433                CHECK_ERROR(machine, COMSETTER(CPUHotPlugEnabled)(ValueUnion.f));
     434                break;
     435            }
     436
     437            case MODIFYVM_PLUGCPU:
     438            {
     439                CHECK_ERROR(machine, HotPlugCPU(ValueUnion.u32));
     440                break;
     441            }
     442
     443            case MODIFYVM_UNPLUGCPU:
     444            {
     445                CHECK_ERROR(machine, HotUnplugCPU(ValueUnion.u32));
     446                break;
     447            }
     448
    425449            case MODIFYVM_MONITORCOUNT:
    426450            {
  • trunk/src/VBox/Frontends/VBoxSDL/VBoxSDL.cpp

    r25026 r25901  
    542542
    543543    STDMETHOD(OnMediumChange)(IMediumAttachment * /*aMediumAttachment*/)
     544    {
     545        return S_OK;
     546    }
     547
     548    STDMETHOD(OnCPUChange)(ULONG /*aCPU*/, BOOL /* aRemove */)
    544549    {
    545550        return S_OK;
  • trunk/src/VBox/Frontends/VirtualBox/src/VBoxConsoleView.cpp

    r25583 r25901  
    536536                break;
    537537        }
     538        return S_OK;
     539    }
     540
     541    STDMETHOD(OnCPUChange)(ULONG aCPU, BOOL aRemove)
     542    {
     543        NOREF(aCPU);
     544        NOREF(aRemove);
    538545        return S_OK;
    539546    }
  • trunk/src/VBox/Main/ConsoleImpl.cpp

    r25893 r25901  
    17301730}
    17311731
     1732DECLCALLBACK(int) Console::unplugCpu(Console *pThis, unsigned uCpu)
     1733{
     1734    LogFlowFunc(("pThis=%p uCpu=%u\n", pThis, uCpu));
     1735
     1736    AssertReturn(pThis, VERR_INVALID_PARAMETER);
     1737
     1738    int vrc = PDMR3DeviceDetach(pThis->mpVM, "acpi", 0, uCpu, 0);
     1739    Log(("UnplugCpu: rc=%Rrc\n", vrc));
     1740
     1741    return vrc;
     1742}
     1743
     1744STDMETHODIMP Console::doCPURemove(ULONG aCpu)
     1745{
     1746    HRESULT rc = S_OK;
     1747
     1748    LogFlowThisFuncEnter();
     1749    LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
     1750
     1751    AutoCaller autoCaller(this);
     1752    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     1753
     1754    AutoWriteLock alock(this);
     1755
     1756    if (   mMachineState != MachineState_Running
     1757        && mMachineState != MachineState_Teleporting
     1758        && mMachineState != MachineState_LiveSnapshotting
     1759       )
     1760        return setError(VBOX_E_INVALID_VM_STATE,
     1761            tr("Invalid machine state: %s"),
     1762            Global::stringifyMachineState(mMachineState));
     1763
     1764    /* protect mpVM */
     1765    AutoVMCaller autoVMCaller(this);
     1766    if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
     1767
     1768    /* Check if the CPU is present */
     1769    BOOL fCpuAttached;
     1770    rc = mMachine->GetCPUStatus(aCpu, &fCpuAttached);
     1771    if (FAILED(rc)) return rc;
     1772
     1773    if (!fCpuAttached)
     1774        return setError(E_FAIL,
     1775                        tr("CPU %d is not attached"), aCpu);
     1776
     1777    /* Check if the CPU is unlocked */
     1778    PPDMIBASE pBase;
     1779    int vrc = PDMR3QueryDeviceLun(mpVM, "acpi", 0, aCpu, &pBase);
     1780    bool fLocked = true;
     1781    if (RT_SUCCESS(vrc))
     1782    {
     1783        uint32_t idCpuCore, idCpuPackage;
     1784
     1785        /* Notify the guest if possible. */
     1786        vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(mpVM, aCpu, &idCpuCore, &idCpuPackage);
     1787        AssertRC(vrc);
     1788
     1789        Assert(pBase);
     1790
     1791        PPDMIACPIPORT pPort =
     1792            (PPDMIACPIPORT) pBase->pfnQueryInterface(pBase, PDMINTERFACE_ACPI_PORT);
     1793
     1794        vrc = getVMMDev()->getVMMDevPort()->pfnCpuHotUnplug(getVMMDev()->getVMMDevPort(), idCpuCore, idCpuPackage);
     1795        if (RT_SUCCESS(vrc))
     1796        {
     1797            unsigned cTries = 10;
     1798
     1799            do
     1800            {
     1801                /* It will take some time until the event is processed in the guest. Wait  */
     1802                vrc = pPort ? pPort->pfnGetCpuStatus(pPort, aCpu, &fLocked) : VERR_INVALID_POINTER;
     1803
     1804                if (RT_SUCCESS(vrc) && !fLocked)
     1805                    break;
     1806
     1807                /* Sleep a bit */
     1808                RTThreadSleep(100);
     1809            } while (cTries-- > 0);
     1810        }
     1811        else if (vrc == VERR_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST)
     1812        {
     1813            /* Query one time. It is possible that the user ejected the CPU. */
     1814            vrc = pPort ? pPort->pfnGetCpuStatus(pPort, aCpu, &fLocked) : VERR_INVALID_POINTER;
     1815        }
     1816    }
     1817
     1818    /* If the CPU was unlocked we can detach it now. */
     1819    if (RT_SUCCESS(vrc) && !fLocked)
     1820    {
     1821        /*
     1822         * Call worker in EMT, that's faster and safer than doing everything
     1823         * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
     1824         * here to make requests from under the lock in order to serialize them.
     1825         */
     1826        PVMREQ pReq;
     1827        vrc = VMR3ReqCall(mpVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
     1828                          (PFNRT)Console::unplugCpu, 2,
     1829                          this, aCpu);
     1830
     1831        /* leave the lock before a VMR3* call (EMT will call us back)! */
     1832        alock.leave();
     1833
     1834        if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
     1835        {
     1836            vrc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
     1837            AssertRC(vrc);
     1838            if (RT_SUCCESS(vrc))
     1839                vrc = pReq->iStatus;
     1840        }
     1841        VMR3ReqFree(pReq);
     1842
     1843        if (RT_SUCCESS(vrc))
     1844        {
     1845            /* Detach it from the VM  */
     1846            vrc = VMR3HotUnplugCpu(mpVM, aCpu);
     1847            AssertRC(vrc);
     1848        }
     1849        else
     1850           rc = setError(VBOX_E_VM_ERROR,
     1851                         tr("Hot-Remove failed (rc=%Rrc)"), vrc);
     1852    }
     1853    else
     1854        rc = setError(VBOX_E_VM_ERROR,
     1855                      tr("Hot-Remove was aborted because the CPU may still be used by the guest"), VERR_RESOURCE_BUSY);
     1856
     1857    LogFlowThisFunc(("mMachineState=%d, rc=%08X\n", mMachineState, rc));
     1858    LogFlowThisFuncLeave();
     1859    return rc;
     1860}
     1861
     1862DECLCALLBACK(int) Console::plugCpu(Console *pThis, unsigned uCpu)
     1863{
     1864    LogFlowFunc(("pThis=%p uCpu=%u\n", pThis, uCpu));
     1865
     1866    AssertReturn(pThis, VERR_INVALID_PARAMETER);
     1867
     1868    int rc = VMR3HotPlugCpu(pThis->mpVM, uCpu);
     1869    AssertRC(rc);
     1870
     1871    PCFGMNODE pInst = CFGMR3GetChild(CFGMR3GetRoot(pThis->mpVM), "Devices/acpi/0/");
     1872    AssertRelease(pInst);
     1873    /* nuke anything which might have been left behind. */
     1874    CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%d", uCpu));
     1875
     1876#define RC_CHECK() do { if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; } } while (0)
     1877
     1878    PCFGMNODE pLunL0;
     1879    PCFGMNODE pCfg;
     1880    rc = CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%d", uCpu);     RC_CHECK();
     1881    rc = CFGMR3InsertString(pLunL0, "Driver",       "ACPICpu"); RC_CHECK();
     1882    rc = CFGMR3InsertNode(pLunL0,   "Config",       &pCfg);     RC_CHECK();
     1883
     1884    /*
     1885     * Attach the driver.
     1886     */
     1887    PPDMIBASE pBase;
     1888    rc = PDMR3DeviceAttach(pThis->mpVM, "acpi", 0, uCpu, 0, &pBase); RC_CHECK();
     1889
     1890    Log(("PlugCpu: rc=%Rrc\n", rc));
     1891
     1892    CFGMR3Dump(pInst);
     1893
     1894    return VINF_SUCCESS;
     1895}
     1896
     1897STDMETHODIMP Console::doCPUAdd(ULONG aCpu)
     1898{
     1899    HRESULT rc = S_OK;
     1900
     1901    LogFlowThisFuncEnter();
     1902    LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
     1903
     1904    AutoCaller autoCaller(this);
     1905    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     1906
     1907    AutoWriteLock alock(this);
     1908
     1909    if (   mMachineState != MachineState_Running
     1910        && mMachineState != MachineState_Teleporting
     1911        && mMachineState != MachineState_LiveSnapshotting
     1912        /** @todo r=bird: This should be allowed on paused VMs as well. Later.  */
     1913       )
     1914        return setError(VBOX_E_INVALID_VM_STATE,
     1915            tr("Invalid machine state: %s"),
     1916            Global::stringifyMachineState(mMachineState));
     1917
     1918    /* protect mpVM */
     1919    AutoVMCaller autoVMCaller(this);
     1920    if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
     1921
     1922    /* Check if the CPU is present */
     1923    BOOL fCpuAttached;
     1924    rc = mMachine->GetCPUStatus(aCpu, &fCpuAttached);
     1925    if (FAILED(rc)) return rc;
     1926
     1927    if (fCpuAttached)
     1928        return setError(E_FAIL,
     1929                        tr("CPU %d is already attached"), aCpu);
     1930
     1931    /*
     1932     * Call worker in EMT, that's faster and safer than doing everything
     1933     * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
     1934     * here to make requests from under the lock in order to serialize them.
     1935     */
     1936    PVMREQ pReq;
     1937    int vrc = VMR3ReqCall(mpVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
     1938                          (PFNRT)Console::plugCpu, 2,
     1939                          this, aCpu);
     1940
     1941    /* leave the lock before a VMR3* call (EMT will call us back)! */
     1942    alock.leave();
     1943
     1944    if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
     1945    {
     1946        vrc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
     1947        AssertRC(vrc);
     1948        if (RT_SUCCESS(vrc))
     1949            vrc = pReq->iStatus;
     1950    }
     1951    VMR3ReqFree(pReq);
     1952
     1953    rc = RT_SUCCESS(vrc) ? S_OK :
     1954        setError(VBOX_E_VM_ERROR,
     1955            tr("Could not add CPU to the machine (%Rrc)"),
     1956            vrc);
     1957
     1958    if (RT_SUCCESS(vrc))
     1959    {
     1960        uint32_t idCpuCore, idCpuPackage;
     1961
     1962        /* Notify the guest if possible. */
     1963        vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(mpVM, aCpu, &idCpuCore, &idCpuPackage);
     1964        AssertRC(vrc);
     1965
     1966        vrc = getVMMDev()->getVMMDevPort()->pfnCpuHotPlug(getVMMDev()->getVMMDevPort(), idCpuCore, idCpuPackage);
     1967        /** @todo warning if the guest doesn't support it */
     1968    }
     1969
     1970    LogFlowThisFunc(("mMachineState=%d, rc=%08X\n", mMachineState, rc));
     1971    LogFlowThisFuncLeave();
     1972    return rc;
     1973}
     1974
    17321975STDMETHODIMP Console::Pause()
    17331976{
     
    37303973        while (it != mCallbacks.end())
    37313974            (*it++)->OnMediumChange(aMediumAttachment);
     3975    }
     3976
     3977    LogFlowThisFunc(("Leaving rc=%#x\n", rc));
     3978    return rc;
     3979}
     3980
     3981/**
     3982 * Called by IInternalSessionControl::OnCPUChange().
     3983 *
     3984 * @note Locks this object for writing.
     3985 */
     3986HRESULT Console::onCPUChange(ULONG aCPU, BOOL aRemove)
     3987{
     3988    LogFlowThisFunc(("\n"));
     3989
     3990    AutoCaller autoCaller(this);
     3991    AssertComRCReturnRC(autoCaller.rc());
     3992
     3993    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     3994
     3995    /* Don't do anything if the VM isn't running */
     3996    if (!mpVM)
     3997        return S_OK;
     3998
     3999    HRESULT rc = S_OK;
     4000
     4001    /* protect mpVM */
     4002    AutoVMCaller autoVMCaller(this);
     4003    if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
     4004
     4005    if (aRemove)
     4006        rc = doCPURemove(aCPU);
     4007    else
     4008        rc = doCPUAdd(aCPU);
     4009
     4010    /* notify console callbacks on success */
     4011    if (SUCCEEDED(rc))
     4012    {
     4013        CallbackList::iterator it = mCallbacks.begin();
     4014        while (it != mCallbacks.end())
     4015            (*it++)->OnCPUChange(aCPU, aRemove);
    37324016    }
    37334017
  • trunk/src/VBox/Main/ConsoleImpl2.cpp

    r25867 r25901  
    18511851    if (fACPI)
    18521852    {
     1853        BOOL fCpuHotPlug = false;
    18531854        BOOL fShowCpu = fExtProfile;
    18541855        /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
     
    18561857         * intelppm driver refuses to register an idle state handler.
    18571858         */
    1858         if ((cCpus > 1) ||  fIOAPIC)
     1859        if ((cCpus > 1) || fIOAPIC)
    18591860            fShowCpu = true;
     1861
     1862        hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug);                 H();
    18601863
    18611864        rc = CFGMR3InsertNode(pDevices, "acpi", &pDev);                             RC_CHECK();
     
    18781881
    18791882        rc = CFGMR3InsertInteger(pCfg,  "ShowCpu", fShowCpu);                       RC_CHECK();
     1883        rc = CFGMR3InsertInteger(pCfg,  "CpuHotPlug", fCpuHotPlug);                 RC_CHECK();
    18801884        rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo",          7);                 RC_CHECK();
    18811885        Assert(!afPciDeviceNo[7]);
     
    18861890        rc = CFGMR3InsertString(pLunL0, "Driver",               "ACPIHost");        RC_CHECK();
    18871891        rc = CFGMR3InsertNode(pLunL0,   "Config", &pCfg);                           RC_CHECK();
     1892
     1893        /* Attach the dummy CPU drivers */
     1894        for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
     1895        {
     1896            BOOL fCpuAttached = true;
     1897
     1898            if (fCpuHotPlug)
     1899            {
     1900                hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached);              H();
     1901            }
     1902
     1903            if (fCpuAttached)
     1904            {
     1905                rc = CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%u", iCpuCurr);             RC_CHECK();
     1906                rc = CFGMR3InsertString(pLunL0, "Driver",           "ACPICpu");         RC_CHECK();
     1907                rc = CFGMR3InsertNode(pLunL0,   "Config", &pCfg);                       RC_CHECK();
     1908            }
     1909        }
    18881910    }
    18891911
  • trunk/src/VBox/Main/ConsoleVRDPServer.cpp

    r25860 r25901  
    119119
    120120    STDMETHOD(OnMediumChange)(IMediumAttachment *aAttachment)
     121    {
     122        return S_OK;
     123    }
     124
     125    STDMETHOD(OnCPUChange)(ULONG aCPU, BOOL aRemove)
    121126    {
    122127        return S_OK;
  • trunk/src/VBox/Main/MachineImpl.cpp

    r25880 r25901  
    156156    mMemorySize = 128;
    157157    mCPUCount = 1;
     158    mCPUHotPlugEnabled = false;
    158159    mMemoryBalloonSize = 0;
    159160    mStatisticsUpdateInterval = 0;
     
    189190
    190191    mFirmwareType = FirmwareType_BIOS;
     192
     193    for (size_t i = 0; i < RT_ELEMENTS(mCPUAttached); i++)
     194        mCPUAttached[i] = false;
    191195}
    192196
     
    217221        mSyntheticCpu != that.mSyntheticCpu ||
    218222        mCPUCount != that.mCPUCount ||
     223        mCPUHotPlugEnabled != that.mCPUHotPlugEnabled ||
    219224        mClipboardMode != that.mClipboardMode)
    220225        return false;
     
    223228        if (mBootOrder [i] != that.mBootOrder [i])
    224229            return false;
     230
     231
     232    for (size_t i = 0; i < RT_ELEMENTS(mCPUAttached); i++)
     233    {
     234        if (mCPUAttached[i] != that.mCPUAttached[i])
     235            return false;
     236    }
    225237
    226238    if (mSharedFolders.size() != that.mSharedFolders.size())
     
    10751087STDMETHODIMP Machine::COMSETTER(CPUCount) (ULONG CPUCount)
    10761088{
    1077     /* check RAM limits */
     1089    /* check CPU limits */
    10781090    if (    CPUCount < SchemaDefs::MinCPUCount
    10791091         || CPUCount > SchemaDefs::MaxCPUCount
     
    10881100    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    10891101
     1102    /* We cant go below the current number of CPUs if hotplug is enabled*/
     1103    if (mHWData->mCPUHotPlugEnabled)
     1104    {
     1105        for (unsigned idx = CPUCount; idx < SchemaDefs::MaxCPUCount; idx++)
     1106        {
     1107            if (mHWData->mCPUAttached[idx])
     1108                return setError(E_INVALIDARG,
     1109                                tr(": %lu (must be higher than or equal to %lu)"),
     1110                                CPUCount, idx+1);
     1111        }
     1112    }
     1113
    10901114    HRESULT rc = checkStateDependency(MutableStateDep);
    10911115    if (FAILED(rc)) return rc;
     
    10951119
    10961120    return S_OK;
     1121}
     1122
     1123STDMETHODIMP Machine::COMGETTER(CPUHotPlugEnabled) (BOOL *enabled)
     1124{
     1125    if (!enabled)
     1126        return E_POINTER;
     1127
     1128    AutoCaller autoCaller(this);
     1129    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     1130
     1131    AutoReadLock alock(this);
     1132
     1133    *enabled = mHWData->mCPUHotPlugEnabled;
     1134
     1135    return S_OK;
     1136}
     1137
     1138STDMETHODIMP Machine::COMSETTER(CPUHotPlugEnabled) (BOOL enabled)
     1139{
     1140    HRESULT rc = S_OK;
     1141
     1142    AutoCaller autoCaller(this);
     1143    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     1144
     1145    AutoWriteLock alock(this);
     1146
     1147    rc = checkStateDependency(MutableStateDep);
     1148    if (FAILED(rc)) return rc;
     1149
     1150    if (mHWData->mCPUHotPlugEnabled != enabled)
     1151    {
     1152        if (enabled)
     1153        {
     1154            mHWData.backup();
     1155
     1156            /* Add the amount of CPUs currently attached */
     1157            for (unsigned i = 0; i < mHWData->mCPUCount; i++)
     1158            {
     1159                mHWData->mCPUAttached[i] = true;
     1160            }
     1161        }
     1162        else
     1163        {
     1164            /*
     1165             * We can disable hotplug only if the amount of maximum CPUs is equal
     1166             * to the amount of attached CPUs
     1167             */
     1168            unsigned cCpusAttached = 0;
     1169            unsigned iHighestId = 0;
     1170
     1171            for (unsigned i = 0; i < SchemaDefs::MaxCPUCount; i++)
     1172            {
     1173                if (mHWData->mCPUAttached[i])
     1174                {
     1175                    cCpusAttached++;
     1176                    iHighestId = i;
     1177                }
     1178            }
     1179
     1180            if (   (cCpusAttached != mHWData->mCPUCount)
     1181                || (iHighestId >= mHWData->mCPUCount))
     1182                return setError(E_INVALIDARG,
     1183                                tr("CPU hotplugging can't be disabled because the maximum number of CPUs is not equal to the amount of CPUs attached\n"));
     1184
     1185            mHWData.backup();
     1186        }
     1187    }
     1188
     1189    mHWData->mCPUHotPlugEnabled = enabled;
     1190
     1191    return rc;
    10971192}
    10981193
     
    42574352}
    42584353
     4354STDMETHODIMP Machine::HotPlugCPU(ULONG aCpu)
     4355{
     4356    HRESULT rc = S_OK;
     4357    LogFlowThisFunc(("\n"));
     4358
     4359    AutoCaller autoCaller(this);
     4360    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     4361
     4362    AutoWriteLock alock(this);
     4363
     4364    if (!mHWData->mCPUHotPlugEnabled)
     4365        return setError(E_INVALIDARG, tr("CPU hotplug is not enabled"));
     4366
     4367    if (aCpu >= mHWData->mCPUCount)
     4368        return setError(E_INVALIDARG, tr("CPU id exceeds number of possible CPUs [0:%lu]"), mHWData->mCPUCount-1);
     4369
     4370    if (mHWData->mCPUAttached[aCpu])
     4371        return setError(VBOX_E_OBJECT_IN_USE, tr("CPU %lu is already attached"), aCpu);
     4372
     4373    alock.leave();
     4374    rc = onCPUChange(aCpu, false);
     4375    alock.enter();
     4376    if (FAILED(rc)) return rc;
     4377
     4378    mHWData.backup();
     4379    mHWData->mCPUAttached[aCpu] = true;
     4380
     4381    /* Save settings if online */
     4382    if (Global::IsOnline(mData->mMachineState))
     4383        SaveSettings();
     4384
     4385    return S_OK;
     4386}
     4387
     4388STDMETHODIMP Machine::HotUnplugCPU(ULONG aCpu)
     4389{
     4390    HRESULT rc = S_OK;
     4391    LogFlowThisFunc(("\n"));
     4392
     4393    AutoCaller autoCaller(this);
     4394    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     4395
     4396    AutoWriteLock alock(this);
     4397
     4398    if (!mHWData->mCPUHotPlugEnabled)
     4399        return setError(E_INVALIDARG, tr("CPU hotplug is not enabled"));
     4400
     4401    if (aCpu >= SchemaDefs::MaxCPUCount)
     4402        return setError(E_INVALIDARG,
     4403                        tr("CPU index exceeds maximum CPU count (must be in range [0:%lu])"),
     4404                        SchemaDefs::MaxCPUCount);
     4405
     4406    if (!mHWData->mCPUAttached[aCpu])
     4407        return setError(VBOX_E_OBJECT_NOT_FOUND, tr("CPU %lu is not attached"), aCpu);
     4408
     4409    /* CPU 0 can't be detached */
     4410    if (aCpu == 0)
     4411        return setError(E_INVALIDARG, tr("It is not possible to detach CPU 0"));
     4412
     4413    alock.leave();
     4414    rc = onCPUChange(aCpu, true);
     4415    alock.enter();
     4416    if (FAILED(rc)) return rc;
     4417
     4418    mHWData.backup();
     4419    mHWData->mCPUAttached[aCpu] = false;
     4420
     4421    /* Save settings if online */
     4422    if (Global::IsOnline(mData->mMachineState))
     4423        SaveSettings();
     4424
     4425    return S_OK;
     4426}
     4427
     4428STDMETHODIMP Machine::GetCPUStatus(ULONG aCpu, BOOL *aCpuAttached)
     4429{
     4430    LogFlowThisFunc(("\n"));
     4431
     4432    CheckComArgNotNull(aCpuAttached);
     4433
     4434    *aCpuAttached = false;
     4435
     4436    AutoCaller autoCaller(this);
     4437    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     4438
     4439    AutoReadLock alock(this);
     4440
     4441    /* If hotplug is enabled the CPU is always enabled. */
     4442    if (!mHWData->mCPUHotPlugEnabled)
     4443    {
     4444        if (aCpu < mHWData->mCPUCount)
     4445            *aCpuAttached = true;
     4446    }
     4447    else
     4448    {
     4449        if (aCpu < SchemaDefs::MaxCPUCount)
     4450            *aCpuAttached = mHWData->mCPUAttached[aCpu];
     4451    }
     4452
     4453    return S_OK;
     4454}
     4455
    42594456// public methods for internal purposes
    42604457/////////////////////////////////////////////////////////////////////////////
     
    59606157        mHWData->mSyntheticCpu                = data.fSyntheticCpu;
    59616158
    5962         mHWData->mCPUCount = data.cCPUs;
     6159        mHWData->mCPUCount          = data.cCPUs;
     6160        mHWData->mCPUHotPlugEnabled = data.fCpuHotPlug;
     6161
     6162        // cpu
     6163        if (mHWData->mCPUHotPlugEnabled)
     6164        {
     6165            for (settings::CpuList::const_iterator it = data.llCpus.begin();
     6166                it != data.llCpus.end();
     6167                ++it)
     6168            {
     6169                const settings::Cpu &cpu = *it;
     6170
     6171                mHWData->mCPUAttached[cpu.ulId] = true;
     6172            }
     6173        }
    59636174
    59646175        // cpuid leafs
     
    69837194        }
    69847195
    6985         data.cCPUs = mHWData->mCPUCount;
     7196        data.cCPUs       = mHWData->mCPUCount;
     7197        data.fCpuHotPlug = mHWData->mCPUHotPlugEnabled;
     7198
     7199        data.llCpus.clear();
     7200        if (data.fCpuHotPlug)
     7201        {
     7202            for (unsigned idx = 0; idx < data.cCPUs; idx++)
     7203            {
     7204                if (mHWData->mCPUAttached[idx])
     7205                {
     7206                    settings::Cpu cpu;
     7207                    cpu.ulId = idx;
     7208                    data.llCpus.push_back(cpu);
     7209                }
     7210            }
     7211        }
    69867212
    69877213        // memory
     
    96599885 *  @note Locks this object for reading.
    96609886 */
     9887HRESULT SessionMachine::onCPUChange(ULONG aCPU, BOOL aRemove)
     9888{
     9889    LogFlowThisFunc(("\n"));
     9890
     9891    AutoCaller autoCaller(this);
     9892    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
     9893
     9894    ComPtr<IInternalSessionControl> directControl;
     9895    {
     9896        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     9897        directControl = mData->mSession.mDirectControl;
     9898    }
     9899
     9900    /* ignore notifications sent after #OnSessionEnd() is called */
     9901    if (!directControl)
     9902        return S_OK;
     9903
     9904    return directControl->OnCPUChange(aCPU, aRemove);
     9905}
     9906
     9907/**
     9908 *  @note Locks this object for reading.
     9909 */
    96619910HRESULT SessionMachine::onVRDPServerChange()
    96629911{
  • trunk/src/VBox/Main/SessionImpl.cpp

    r25860 r25901  
    571571
    572572    return mConsole->onMediumChange(aMediumAttachment, aForce);
     573}
     574
     575STDMETHODIMP Session::OnCPUChange(ULONG aCPU, BOOL aRemove)
     576{
     577    LogFlowThisFunc(("\n"));
     578
     579    AutoCaller autoCaller(this);
     580    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
     581
     582    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     583    AssertReturn(mState == SessionState_Open, VBOX_E_INVALID_VM_STATE);
     584    AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
     585
     586    return mConsole->onCPUChange(aCPU, aRemove);
    573587}
    574588
  • trunk/src/VBox/Main/VirtualBoxCallbackImpl.cpp

    r25310 r25901  
    289289}
    290290
     291STDMETHODIMP CallbackWrapper::OnCPUChange(ULONG aCPU, BOOL aRemove)
     292{
     293    if (mConsoleCallback.isNull())
     294        return S_OK;
     295
     296    return mConsoleCallback->OnCPUChange(aCPU, aRemove);
     297}
     298
    291299STDMETHODIMP CallbackWrapper::OnRuntimeError(BOOL fFatal, IN_BSTR id, IN_BSTR message)
    292300{
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r25672 r25901  
    459459           -->
    460460    </const>
    461     <const name="Future"     value="13">
    462       <desc>Settings version greater than "1.10", written by a future VirtualBox version.</desc>
     461    <const name="v1_11"     value="13">
     462      <desc>Settings version "1.10", written by VirtualBox 3.2.x.</desc>
     463      <!-- CPU hot-plug support
     464           -->
     465    </const>
     466    <const name="Future"     value="14">
     467      <desc>Settings version greater than "1.11", written by a future VirtualBox version.</desc>
    463468    </const>
    464469  </enum>
     
    43564361    </attribute>
    43574362
     4363    <attribute name="CPUHotPlugEnabled" type="boolean">
     4364      <desc>
     4365        This setting determines whether VirtualBox allows CPU
     4366        hotplugging for this machine.</desc>
     4367    </attribute>
     4368
    43584369    <attribute name="memorySize" type="unsigned long">
    43594370      <desc>System memory size in megabytes.</desc>
     
    59325943      </param>
    59335944    </method>
     5945
     5946    <method name="HotPlugCPU">
     5947      <desc>
     5948        Plugs a CPU into the machine.
     5949      </desc>
     5950      <param name="cpu" type="unsigned long" dir="in">
     5951        <desc>
     5952          The CPU id to insert.
     5953        </desc>
     5954      </param>
     5955    </method>
     5956
     5957    <method name="HotUnplugCPU">
     5958      <desc>
     5959        Removes a CPU from the machine.
     5960      </desc>
     5961      <param name="cpu" type="unsigned long" dir="in">
     5962        <desc>
     5963          The CPU id to remove.
     5964        </desc>
     5965      </param>
     5966    </method>
     5967
     5968    <method name="GetCPUStatus">
     5969      <desc>
     5970        Plugs a CPU into the machine.
     5971      </desc>
     5972      <param name="cpu" type="unsigned long" dir="in">
     5973        <desc>
     5974          The CPU id to check for.
     5975        </desc>
     5976      </param>
     5977      <param name="attached" type="boolean" dir="return">
     5978        <desc>
     5979          Status of the CPU.
     5980        </desc>
     5981      </param>
     5982    </method>
    59345983</interface>
    59355984
     
    61166165      <param name="mediumAttachment" type="IMediumAttachment" dir="in">
    61176166        <desc>Medium attachment that is subject to change.</desc>
     6167      </param>
     6168    </method>
     6169
     6170    <method name="onCPUChange">
     6171      <desc>
     6172        Notification when a CPU changes.
     6173      </desc>
     6174      <param name="cpu" type="unsigned long" dir="in">
     6175        <desc>The CPU which changed</desc>
     6176      </param>
     6177      <param name="add" type="boolean" dir="in">
     6178        <desc>Flag whether the CPU was added or removed</desc>
    61186179      </param>
    61196180    </method>
     
    1270612767      <param name="mediumAttachment" type="IMediumAttachment" dir="in"/>
    1270712768      <param name="force" type="boolean" dir="in"/>
     12769    </method>
     12770
     12771    <method name="onCPUChange">
     12772      <desc>
     12773        Notification when a CPU changes.
     12774      </desc>
     12775      <param name="cpu" type="unsigned long" dir="in">
     12776        <desc>The CPU which changed</desc>
     12777      </param>
     12778      <param name="add" type="boolean" dir="in">
     12779        <desc>Flag whether the CPU was added or removed</desc>
     12780      </param>
    1270812781    </method>
    1270912782
  • trunk/src/VBox/Main/include/ConsoleImpl.h

    r25859 r25901  
    179179    HRESULT onStorageControllerChange ();
    180180    HRESULT onMediumChange(IMediumAttachment *aMediumAttachment, BOOL aForce);
     181    HRESULT onCPUChange(ULONG aCPU, BOOL aRemove);
    181182    HRESULT onVRDPServerChange();
    182183    HRESULT onUSBControllerChange();
     
    448449                                          const char *pszFormat, bool fPassthrough,
    449450                                          bool fForce);
     451    static DECLCALLBACK(int) unplugCpu (Console *pThis, unsigned uCpu);
     452    static DECLCALLBACK(int) plugCpu (Console *pThis, unsigned uCpu);
    450453    HRESULT doMediumChange(IMediumAttachment *aMediumAttachment, bool fForce);
     454    HRESULT doCPURemove(ULONG aCpu);
     455    HRESULT doCPUAdd(ULONG aCpu);
    451456
    452457#ifdef VBOX_DYNAMIC_NET_ATTACH
  • trunk/src/VBox/Main/include/DisplayImpl.h

    r25069 r25901  
    194194    }
    195195
     196    STDMETHOD(OnCPUChange)(ULONG aCPU, BOOL aRemove)
     197    {
     198        return S_OK;
     199    }
     200
    196201    STDMETHOD(OnVRDPServerChange)()
    197202    {
  • trunk/src/VBox/Main/include/MachineImpl.h

    r25859 r25901  
    296296        BOOL           mSyntheticCpu;
    297297        ULONG          mCPUCount;
     298        BOOL           mCPUHotPlugEnabled;
    298299        BOOL           mAccelerate3DEnabled;
     300
     301        BOOL           mCPUAttached[SchemaDefs::MaxCPUCount];
    299302
    300303        settings::CpuIdLeaf mCpuIdStdLeafs[10];
     
    531534    STDMETHOD(COMGETTER(CPUCount))(ULONG *cpuCount);
    532535    STDMETHOD(COMSETTER(CPUCount))(ULONG cpuCount);
     536    STDMETHOD(COMGETTER(CPUHotPlugEnabled))(BOOL *enabled);
     537    STDMETHOD(COMSETTER(CPUHotPlugEnabled))(BOOL enabled);
    533538    STDMETHOD(COMGETTER(MemoryBalloonSize))(ULONG *memoryBalloonSize);
    534539    STDMETHOD(COMSETTER(MemoryBalloonSize))(ULONG memoryBalloonSize);
     
    634639    STDMETHOD(QuerySavedScreenshotPNGSize)(ULONG *aSize, ULONG *aWidth, ULONG *aHeight);
    635640    STDMETHOD(ReadSavedScreenshotPNGToArray)(ULONG *aWidth, ULONG *aHeight, ComSafeArrayOut(BYTE, aData));
     641    STDMETHOD(HotPlugCPU(ULONG aCpu));
     642    STDMETHOD(HotUnplugCPU(ULONG aCpu));
     643    STDMETHOD(GetCPUStatus(ULONG aCpu, BOOL *aCpuAttached));
    636644
    637645    // public methods only for internal purposes
     
    717725    virtual HRESULT onUSBControllerChange() { return S_OK; }
    718726    virtual HRESULT onStorageControllerChange() { return S_OK; }
     727    virtual HRESULT onCPUChange(ULONG /* aCPU */, BOOL /* aRemove */) { return S_OK; }
    719728    virtual HRESULT onMediumChange(IMediumAttachment * /* mediumAttachment */, BOOL /* force */) { return S_OK; }
    720729    virtual HRESULT onSharedFolderChange() { return S_OK; }
     
    10361045    HRESULT onSerialPortChange(ISerialPort *serialPort);
    10371046    HRESULT onParallelPortChange(IParallelPort *parallelPort);
     1047    HRESULT onCPUChange(ULONG aCPU, BOOL aRemove);
    10381048    HRESULT onVRDPServerChange();
    10391049    HRESULT onUSBControllerChange();
  • trunk/src/VBox/Main/include/SessionImpl.h

    r25642 r25901  
    9696    STDMETHOD(OnStorageControllerChange)();
    9797    STDMETHOD(OnMediumChange)(IMediumAttachment *aMediumAttachment, BOOL aForce);
     98    STDMETHOD(OnCPUChange)(ULONG aCPU, BOOL aRemove);
    9899    STDMETHOD(OnVRDPServerChange)();
    99100    STDMETHOD(OnUSBControllerChange)();
  • trunk/src/VBox/Main/include/VirtualBoxCallbackImpl.h

    r23643 r25901  
    9494    STDMETHOD(OnStorageControllerChange) ();
    9595    STDMETHOD(OnMediumChange)(IMediumAttachment *iMediumAttachment);
     96    STDMETHOD(OnCPUChange)(ULONG aCPU, BOOL aRemove);
    9697    STDMETHOD(OnRuntimeError)(BOOL fFatal, IN_BSTR id, IN_BSTR message);
    9798    STDMETHOD(OnCanShowWindow)(BOOL *canShow);
  • trunk/src/VBox/Main/xml/Settings.cpp

    r25892 r25901  
    3030 *   3) In the settings writer method, write the setting _only_ if the current settings
    3131 *      version (stored in m->sv) is high enough. That is, for VirtualBox 3.2, write it
    32  *      only if (m->sv >= SettingsVersion_v1_10).
     32 *      only if (m->sv >= SettingsVersion_v1_11).
    3333 *
    3434 *   4) In MachineConfigFile::bumpSettingsVersionIfNeeded(), check if the new setting has
     
    8282
    8383/** VirtualBox XML settings version number substring ("x.y")  */
    84 #define VBOX_XML_VERSION        "1.9"
     84#define VBOX_XML_VERSION        "1.11"
    8585
    8686/** VirtualBox XML settings version platform substring */
     
    282282                else if (ulMinor == 10)
    283283                    m->sv = SettingsVersion_v1_10;
    284                 else if (ulMinor > 10)
     284                else if (ulMinor == 11)
     285                    m->sv = SettingsVersion_v1_11;
     286                else if (ulMinor > 11)
    285287                    m->sv = SettingsVersion_Future;
    286288            }
     
    302304        // creating new settings file:
    303305        m->strSettingsVersionFull = VBOX_XML_VERSION_FULL;
    304         m->sv = SettingsVersion_v1_10;
     306        m->sv = SettingsVersion_v1_11;
    305307    }
    306308}
     
    556558
    557559        case SettingsVersion_v1_10:
     560            pcszVersion = "1.10";
     561            m->sv = SettingsVersion_v1_10;
     562            break;
     563
     564        case SettingsVersion_v1_11:
    558565        case SettingsVersion_Future:                // can be set if this code runs on XML files that were created by a future version of VBox;
    559566                                                    // in that case, downgrade to current version when writing since we can't write future versions...
    560             pcszVersion = "1.10";
    561             m->sv = SettingsVersion_v1_10;
     567            pcszVersion = "1.11";
     568            m->sv = SettingsVersion_v1_11;
    562569            break;
    563570
     
    12631270          fPAE(false),
    12641271          cCPUs(1),
     1272          fCpuHotPlug(false),
    12651273          ulMemorySizeMB((uint32_t)-1),
    12661274          ulVRAMSizeMB(8),
     
    12841292    fPAE = true;
    12851293#endif
     1294}
     1295
     1296/**
     1297 * Called from MachineConfigFile::readHardware() to read cpu information.
     1298 * @param elmCpuid
     1299 * @param ll
     1300 */
     1301void MachineConfigFile::readCpuTree(const xml::ElementNode &elmCpu,
     1302                                    CpuList &ll)
     1303{
     1304    xml::NodesLoop nl1(elmCpu, "Cpu");
     1305    const xml::ElementNode *pelmCpu;
     1306    while ((pelmCpu = nl1.forAllNodes()))
     1307    {
     1308        Cpu cpu;
     1309
     1310        if (!pelmCpu->getAttributeValue("id", cpu.ulId))
     1311            throw ConfigFileError(this, pelmCpu, N_("Required Cpu/@id attribute is missing"));
     1312
     1313        ll.push_back(cpu);
     1314    }
    12861315}
    12871316
     
    15601589            }
    15611590
     1591            pelmHwChild->getAttributeValue("hotplug", hw.fCpuHotPlug);
     1592
    15621593            const xml::ElementNode *pelmCPUChild;
     1594            if (hw.fCpuHotPlug)
     1595            {
     1596                if ((pelmCPUChild = pelmHwChild->findChildElement("CpuTree")))
     1597                    readCpuTree(*pelmCPUChild, hw.llCpus);
     1598            }
     1599
    15631600            if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtEx")))
    15641601            {
     
    24682505        pelmCPU->createChild("SyntheticCpu")->setAttribute("enabled", hw.fSyntheticCpu);
    24692506    pelmCPU->setAttribute("count", hw.cCPUs);
     2507
     2508    if (m->sv >= SettingsVersion_v1_11)
     2509    {
     2510        pelmCPU->setAttribute("hotplug", hw.fCpuHotPlug);
     2511
     2512        xml::ElementNode *pelmCpuTree = NULL;
     2513        for (CpuList::const_iterator it = hw.llCpus.begin();
     2514             it != hw.llCpus.end();
     2515             ++it)
     2516        {
     2517            const Cpu &cpu = *it;
     2518
     2519            if (pelmCpuTree == NULL)
     2520                 pelmCpuTree = pelmCPU->createChild("CpuTree");
     2521
     2522            xml::ElementNode *pelmCpu = pelmCpuTree->createChild("Cpu");
     2523            pelmCpu->setAttribute("id", cpu.ulId);
     2524        }
     2525    }
     2526
    24702527    xml::ElementNode *pelmCpuIdTree = NULL;
    24712528    for (CpuIdLeafsList::const_iterator it = hw.llCpuIdLeafs.begin();
     
    30813138       )
    30823139        m->sv = SettingsVersion_v1_10;
     3140
     3141    // Version 1.11 is required for CPU hotplugging
     3142    if (   (m->sv < SettingsVersion_v1_11)
     3143        && (hardwareMachine.fCpuHotPlug)
     3144       )
     3145        m->sv = SettingsVersion_v1_11;
    30833146}
    30843147
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