VirtualBox

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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
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