VirtualBox

Ignore:
Timestamp:
Dec 2, 2018 4:30:13 PM (6 years ago)
Author:
vboxsync
Message:

GuestControl: Dropped the HostCommand reference counting and sharing ability since we only need it for the session closing request/message/command/wussname. This means we can use iprt/list.h and run no risk of bad_alloc during EnqueueCommand(). bugref:9313

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostServices/GuestControl/service.cpp

    r75871 r75872  
    111111typedef struct HostCommand
    112112{
    113     /** Entry on the GstCtrlService::mHostCmdList list. */
    114     RTLISTNODE m_ListEntry;
    115     /** Reference counter for facilitating sending to both session and root. */
    116     uint32_t m_cRefs;
     113    /** Entry on the ClientState::m_HostCmdList list. */
     114    RTLISTNODE      m_ListEntry;
    117115    union
    118116    {
    119117        /** The top two twomost bits are exploited for message destination.
    120118         * See VBOX_GUESTCTRL_DST_XXX.  */
    121         uint64_t m_idContextAndDst;
     119        uint64_t    m_idContextAndDst;
    122120        /** The context ID this command belongs to (extracted from the first parameter). */
    123         uint32_t m_idContext;
     121        uint32_t    m_idContext;
    124122    };
    125123    /** Dynamic structure for holding the HGCM parms */
     
    131129
    132130    HostCommand()
    133         : m_cRefs(1)
    134         , m_idContextAndDst(0)
     131        : m_idContextAndDst(0)
    135132        , mMsgType(UINT32_MAX)
    136133        , mParmCount(0)
     
    140137    }
    141138
    142 
    143     /**
    144      * Retains a reference to the command.
    145      */
    146     uint32_t Retain(void)
    147     {
    148         uint32_t cRefs = ++m_cRefs;
    149         Log4(("[Cmd %RU32 (%s)] Adding reference, new m_cRefs=%u\n", mMsgType, GstCtrlHostFnName((eHostFn)mMsgType), cRefs));
    150         Assert(cRefs < 4);
    151         return cRefs;
    152     }
    153 
    154 
    155139    /**
    156140     * Releases the host command, properly deleting it if no further references.
    157141     */
    158     uint32_t SaneRelease(void)
    159     {
    160         uint32_t cRefs = --m_cRefs;
    161         Log4(("[Cmd %RU32] sane release - cRefs=%u\n", mMsgType, cRefs));
    162         Assert(cRefs < 4);
    163 
    164         if (!cRefs)
    165         {
    166             LogFlowThisFunc(("[Cmd %RU32 (%s)] destroying\n", mMsgType, GstCtrlHostFnName((eHostFn)mMsgType)));
    167             RTListNodeRemove(&m_ListEntry);
    168             if (mpParms)
    169             {
    170                 for (uint32_t i = 0; i < mParmCount; i++)
    171                     if (mpParms[i].type == VBOX_HGCM_SVC_PARM_PTR)
    172                     {
    173                         RTMemFree(mpParms[i].u.pointer.addr);
    174                         mpParms[i].u.pointer.addr = NULL;
    175                     }
    176                 RTMemFree(mpParms);
    177                 mpParms = NULL;
    178             }
    179             mParmCount = 0;
    180             delete this;
    181         }
    182         return cRefs;
     142    void Delete(void)
     143    {
     144        LogFlowThisFunc(("[Cmd %RU32 (%s)] destroying\n", mMsgType, GstCtrlHostFnName((eHostFn)mMsgType)));
     145        Assert(m_ListEntry.pNext == NULL);
     146        if (mpParms)
     147        {
     148            for (uint32_t i = 0; i < mParmCount; i++)
     149                if (mpParms[i].type == VBOX_HGCM_SVC_PARM_PTR)
     150                {
     151                    RTMemFree(mpParms[i].u.pointer.addr);
     152                    mpParms[i].u.pointer.addr = NULL;
     153                }
     154            RTMemFree(mpParms);
     155            mpParms = NULL;
     156        }
     157        mParmCount = 0;
     158        delete this;
    183159    }
    184160
     
    201177        Assert(mpParms == NULL);
    202178        Assert(mParmCount == 0);
    203         Assert(m_cRefs == 1);
     179        Assert(RTListIsEmpty(&m_ListEntry));
    204180
    205181        /*
     
    482458{
    483459    PVBOXHGCMSVCHELPERS     m_pSvcHelpers;
     460    /** Host command list to process (HostCommand). */
     461    RTLISTANCHOR            m_HostCmdList;
    484462    /** The HGCM client ID. */
    485463    uint32_t                m_idClient;
    486     /** Host command list to process. */
    487     HostCmdList mHostCmdList;
     464    /** The session ID for this client, UINT32_MAX if not set or master. */
     465    uint32_t                m_idSession;
     466    /** Set if master. */
     467    bool                    m_fIsMaster;
     468
     469    /** Set if we've got a pending wait cancel. */
     470    bool                    m_fPendingCancel;
    488471    /** Pending client call (GUEST_MSG_PEEK_WAIT or GUEST_MSG_WAIT), zero if none pending.
    489472     *
     
    491474     * from the waiting call until a new host command is available. */
    492475    guestControl::eGuestFn  m_enmIsPending;
    493     /** The client's pending connection. */
     476    /** Pending peek/wait request details. */
    494477    ClientRequest           m_PendingReq;
    495     /** Set if we've got a pending wait cancel. */
    496     bool                    m_fPendingCancel;
    497     /** Set if master. */
    498     bool                    m_fIsMaster;
    499     /** The session ID for this client, UINT32_MAX if not set or master. */
    500     uint32_t                m_idSession;
    501478
    502479
     
    504481        : m_pSvcHelpers(NULL)
    505482        , m_idClient(0)
     483        , m_idSession(UINT32_MAX)
     484        , m_fIsMaster(false)
     485        , m_fPendingCancel(false)
    506486        , m_enmIsPending((guestControl::eGuestFn)0)
    507         , m_fPendingCancel(false)
    508         , m_fIsMaster(false)
    509         , m_idSession(UINT32_MAX)
    510487        , mHostCmdRc(VINF_SUCCESS)
    511488        , mHostCmdTries(0)
    512489        , mPeekCount(0)
    513     { }
     490    {
     491        RTListInit(&m_HostCmdList);
     492    }
    514493
    515494    ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers, uint32_t idClient)
    516495        : m_pSvcHelpers(pSvcHelpers)
    517496        , m_idClient(idClient)
     497        , m_idSession(UINT32_MAX)
     498        , m_fIsMaster(false)
     499        , m_fPendingCancel(false)
    518500        , m_enmIsPending((guestControl::eGuestFn)0)
    519         , m_fPendingCancel(false)
    520         , m_fIsMaster(false)
    521         , m_idSession(UINT32_MAX)
    522501        , mHostCmdRc(VINF_SUCCESS)
    523502        , mHostCmdTries(0)
    524503        , mPeekCount(0)
    525     { }
     504    {
     505        RTListInit(&m_HostCmdList);
     506    }
    526507
    527508    /**
    528509     * Used by for Service::hostProcessCommand().
    529510     */
    530     int EnqueueCommand(HostCommand *pHostCmd)
    531     {
    532         AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
    533 
    534         try
    535         {
    536             mHostCmdList.push_back(pHostCmd);
    537         }
    538         catch (std::bad_alloc &)
    539         {
    540             return VERR_NO_MEMORY;
    541         }
    542 
    543         pHostCmd->Retain();
    544         return VINF_SUCCESS;
     511    void EnqueueCommand(HostCommand *pHostCmd)
     512    {
     513        AssertPtr(pHostCmd);
     514        RTListAppend(&m_HostCmdList, &pHostCmd->m_ListEntry);
    545515    }
    546516
     
    560530            rc = VINF_SUCCESS;
    561531
    562             HostCmdList::iterator ItFirstCmd = mHostCmdList.begin();
    563             if (ItFirstCmd != mHostCmdList.end())
     532            HostCommand *pFirstCmd = RTListGetFirstCpp(&m_HostCmdList, HostCommand, m_ListEntry);
     533            if (pFirstCmd)
    564534            {
    565                 HostCommand *pFirstCmd = (*ItFirstCmd);
    566                 AssertPtrReturn(pFirstCmd, VERR_INVALID_POINTER);
    567 
    568                 LogFlowThisFunc(("[Client %RU32] Current host command is %RU32 (CID=%RU32, cParms=%RU32, m_cRefs=%RU32)\n",
    569                                  m_idClient, pFirstCmd->mMsgType, pFirstCmd->m_idContext, pFirstCmd->mParmCount, pFirstCmd->m_cRefs));
     535                LogFlowThisFunc(("[Client %RU32] Current host command is %RU32 (CID=%#RX32, cParms=%RU32)\n",
     536                                 m_idClient, pFirstCmd->mMsgType, pFirstCmd->m_idContext, pFirstCmd->mParmCount));
    570537
    571538                if (m_enmIsPending == GUEST_MSG_PEEK_WAIT)
     
    577544                    m_PendingReq.mParms    = NULL;
    578545                    m_PendingReq.mNumParms = 0;
    579                     m_enmIsPending            = (guestControl::eGuestFn)0;
     546                    m_enmIsPending         = (guestControl::eGuestFn)0;
    580547                }
    581548                else if (m_enmIsPending == GUEST_MSG_WAIT)
     
    676643    void OldDitchFirstHostCmd()
    677644    {
    678         Assert(!mHostCmdList.empty());
    679         HostCommand *pFirstCmd = *mHostCmdList.begin();
    680         AssertPtr(pFirstCmd);
    681         pFirstCmd->SaneRelease();
    682         mHostCmdList.pop_front();
     645        HostCommand *pFirstCmd = RTListGetFirstCpp(&m_HostCmdList, HostCommand, m_ListEntry);
     646        Assert(pFirstCmd);
     647        RTListNodeRemove(&pFirstCmd->m_ListEntry);
    683648
    684649        /* Reset state else. */
     
    697662        AssertPtrReturn(pConnection, VERR_INVALID_POINTER);
    698663        AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
    699         Assert(*mHostCmdList.begin() == pHostCmd);
     664        Assert(RTListNodeIsFirst(&m_HostCmdList, &pHostCmd->m_ListEntry));
    700665
    701666        LogFlowFunc(("[Client %RU32] pConnection=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32, mPeekCount=%RU32\n",
     
    744709        if (fRemove)
    745710        {
    746             Assert(*mHostCmdList.begin() == pHostCmd);
     711            Assert(RTListNodeIsFirst(&m_HostCmdList, &pHostCmd->m_ListEntry));
    747712            OldDitchFirstHostCmd();
    748713        }
     
    762727         * If the host command list is empty, the request must wait for one to be posted.
    763728         */
    764         if (mHostCmdList.empty())
     729        HostCommand *pFirstCmd = RTListGetFirstCpp(&m_HostCmdList, HostCommand, m_ListEntry);
     730        if (!pFirstCmd)
    765731        {
    766732            if (!m_fPendingCancel)
     
    786752         * Return first host command.
    787753         */
    788         HostCmdList::iterator curCmd = mHostCmdList.begin();
    789         Assert(curCmd != mHostCmdList.end());
    790         HostCommand *pHostCmd = *curCmd;
    791         AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
    792 
    793         return OldRun(pConnection, pHostCmd);
     754        return OldRun(pConnection, pFirstCmd);
    794755    }
    795756
     
    899860    /** User data pointer to be supplied to the host callback function. */
    900861    void *mpvHostData;
    901     /** List containing all buffered host commands. */
    902     RTLISTANCHOR mHostCmdList;
    903862    /** Map containing all connected clients, key is HGCM client ID. */
    904863    ClientStateMap  mClientStateMap; /**< @todo Use VBOXHGCMSVCFNTABLE::cbClient for this! */
     
    921880        , m_cPreparedSessions(0)
    922881    {
    923         RTListInit(&mHostCmdList);
    924882        RTListInit(&m_PreparedSessions);
    925883    }
     
    10571015     * Cancel all pending host commands, replying with GUEST_DISCONNECTED if final recipient.
    10581016     */
    1059     while (!pClient->mHostCmdList.empty())
    1060     {
    1061         HostCommand *pHostCmd = *pClient->mHostCmdList.begin();
    1062         pClient->mHostCmdList.pop_front();
    1063 
    1064         uint32_t idFunction = pHostCmd->mMsgType;
    1065         uint32_t idContext  = pHostCmd->m_idContext;
    1066         if (pHostCmd->SaneRelease() == 0)
    1067         {
    1068             VBOXHGCMSVCPARM Parm;
    1069             HGCMSvcSetU32(&Parm, idContext);
    1070             int rc2 = pThis->hostCallback(GUEST_DISCONNECTED, 1, &Parm);
    1071             LogFlowFunc(("Cancelled host command %u (%s) with idContext=%#x -> %Rrc\n",
    1072                          idFunction, GstCtrlHostFnName((eHostFn)idFunction), idContext, rc2));
    1073             RT_NOREF(rc2, idFunction);
    1074         }
     1017    HostCommand *pCur, *pNext;
     1018    RTListForEachSafeCpp(&pClient->m_HostCmdList, pCur, pNext, HostCommand, m_ListEntry)
     1019    {
     1020        RTListNodeRemove(&pCur->m_ListEntry);
     1021
     1022        VBOXHGCMSVCPARM Parm;
     1023        HGCMSvcSetU32(&Parm, pCur->m_idContext);
     1024        int rc2 = pThis->hostCallback(GUEST_DISCONNECTED, 1, &Parm);
     1025        LogFlowFunc(("Cancelled host command %u (%s) with idContext=%#x -> %Rrc\n",
     1026                     pCur->mMsgType, GstCtrlHostFnName((eHostFn)pCur->mMsgType), pCur->m_idContext, rc2));
     1027        RT_NOREF(rc2);
     1028
     1029        pCur->Delete();
    10751030    }
    10761031
     
    10991054    if (pThis->mClientStateMap.empty())
    11001055        pThis->m_fLegacyMode = true;
    1101 
    1102     /*
    1103      * Host command sanity check.
    1104      */
    1105     Assert(RTListIsEmpty(&pThis->mHostCmdList) || !pThis->mClientStateMap.empty());
    11061056
    11071057    return VINF_SUCCESS;
     
    12401190     * Return information about the first command if one is pending in the list.
    12411191     */
    1242     HostCmdList::iterator itFirstCmd = pClient->mHostCmdList.begin();
    1243     if (itFirstCmd != pClient->mHostCmdList.end())
    1244     {
    1245         HostCommand *pFirstCmd = *itFirstCmd;
     1192    HostCommand *pFirstCmd = RTListGetFirstCpp(&pClient->m_HostCmdList, HostCommand, m_ListEntry);
     1193    if (pFirstCmd)
     1194    {
    12461195        pFirstCmd->setPeekReturn(paParms, cParms);
    12471196        LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_XXXX -> VINF_SUCCESS (idMsg=%u (%s), cParms=%u)\n",
     
    13031252
    13041253    /*
    1305      * Return information aobut the first command if one is pending in the list.
    1306      */
    1307     HostCmdList::iterator itFirstCmd = pClient->mHostCmdList.begin();
    1308     if (itFirstCmd != pClient->mHostCmdList.end())
    1309     {
    1310         HostCommand *pFirstCmd = *itFirstCmd;
     1254     * Return information about the first command if one is pending in the list.
     1255     */
     1256    HostCommand *pFirstCmd = RTListGetFirstCpp(&pClient->m_HostCmdList, HostCommand, m_ListEntry);
     1257    if (pFirstCmd)
     1258    {
    13111259
    13121260        ASSERT_GUEST_MSG_RETURN(pFirstCmd->mMsgType == idMsgExpected || idMsgExpected == UINT32_MAX,
     
    13741322            if (rc != VERR_CANCELLED)
    13751323            {
    1376                 pClient->mHostCmdList.erase(itFirstCmd);
    1377                 pFirstCmd->SaneRelease();
     1324                RTListNodeRemove(&pFirstCmd->m_ListEntry);
     1325                pFirstCmd->Delete();
    13781326            }
    13791327            else
     
    14561404     * Do the job.
    14571405     */
    1458     if (!pClient->mHostCmdList.empty())
    1459     {
    1460         HostCommand *pFirstCmd = *pClient->mHostCmdList.begin();
     1406    HostCommand *pFirstCmd = RTListGetFirstCpp(&pClient->m_HostCmdList, HostCommand, m_ListEntry);
     1407    if (pFirstCmd)
     1408    {
    14611409        if (   pFirstCmd->mMsgType == idMsg
    14621410            || idMsg == UINT32_MAX)
     
    14681416                 * Remove the command from the queue.
    14691417                 */
    1470                 Assert(*pClient->mHostCmdList.begin() == pFirstCmd);
    1471                 pClient->mHostCmdList.pop_front();
     1418                Assert(RTListNodeIsFirst(&pClient->m_HostCmdList, &pFirstCmd->m_ListEntry) );
     1419                RTListNodeRemove(&pFirstCmd->m_ListEntry);
    14721420
    14731421                /*
     
    15561504                 * Free the command.
    15571505                 */
    1558                 pFirstCmd->SaneRelease();
     1506                pFirstCmd->Delete();
    15591507            }
    15601508            else
     
    18981846     * Execute the request.
    18991847     */
    1900     if (!pClient->mHostCmdList.empty())
     1848    if (!RTListIsEmpty(&pClient->m_HostCmdList))
    19011849        pClient->OldDitchFirstHostCmd();
    19021850
     
    21332081    /*
    21342082     * If no client is connected at all we don't buffer any host commands
    2135      * and immediately return an error to the host. This avoids the host
     2083     * and immediately return an error to the host.  This avoids the host
    21362084     * waiting for a response from the guest side in case VBoxService on
    21372085     * the guest is not running/system is messed up somehow.
     
    21432091    }
    21442092
     2093    /*
     2094     * Create a host command for each destination.
     2095     * Note! There is currently only one scenario in which we send a host
     2096     *       command to two recipients.
     2097     */
    21452098    HostCommand *pHostCmd = new (std::nothrow) HostCommand();
    21462099    AssertReturn(pHostCmd, VERR_NO_MEMORY);
    2147 
    21482100    int rc = pHostCmd->Init(idFunction, cParms, paParms);
    21492101    if (RT_SUCCESS(rc))
    21502102    {
    2151         RTListAppend(&mHostCmdList, &pHostCmd->m_ListEntry);
    2152         LogFlowFunc(("Handling host command m_idContextAndDst=%#RX64, idFunction=%RU32, cParms=%RU32, paParms=%p, cClients=%zu\n",
    2153                      pHostCmd->m_idContextAndDst, idFunction, cParms, paParms, mClientStateMap.size()));
    2154 
    2155         /*
    2156          * Find the message destination and post it to the client.  If the
    2157          * session ID doesn't match any particular client it goes to the master.
    2158          */
    2159         AssertMsg(!mClientStateMap.empty(), ("Client state map is empty when it should not be!\n"));
    2160 
    2161         /* Dispatch to the session. */
    2162         if (pHostCmd->m_idContextAndDst & VBOX_GUESTCTRL_DST_SESSION)
    2163         {
    2164             rc = VWRN_NOT_FOUND;
    2165             uint32_t const idSession = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pHostCmd->m_idContext);
    2166             for (ClientStateMapIter It = mClientStateMap.begin(); It != mClientStateMap.end(); ++It)
     2103        uint64_t const fDestinations = pHostCmd->m_idContextAndDst & VBOX_GUESTCTRL_DST_BOTH;
     2104        HostCommand   *pHostCmd2     = NULL;
     2105        if (fDestinations != VBOX_GUESTCTRL_DST_BOTH)
     2106        { /* likely */ }
     2107        else
     2108        {
     2109            pHostCmd2 = new (std::nothrow) HostCommand();
     2110            if (pHostCmd2)
     2111                rc = pHostCmd2->Init(idFunction, cParms, paParms);
     2112            else
     2113                rc = VERR_NO_MEMORY;
     2114        }
     2115        if (RT_SUCCESS(rc))
     2116        {
     2117            LogFlowFunc(("Handling host command m_idContextAndDst=%#RX64, idFunction=%RU32, cParms=%RU32, paParms=%p, cClients=%zu\n",
     2118                         pHostCmd->m_idContextAndDst, idFunction, cParms, paParms, mClientStateMap.size()));
     2119
     2120            /*
     2121             * Find the message destination and post it to the client.  If the
     2122             * session ID doesn't match any particular client it goes to the master.
     2123             */
     2124            AssertMsg(!mClientStateMap.empty(), ("Client state map is empty when it should not be!\n"));
     2125
     2126            /* Dispatch to the session. */
     2127            if (fDestinations & VBOX_GUESTCTRL_DST_SESSION)
    21672128            {
    2168                 ClientState *pClient = It->second;
    2169                 if (pClient->m_idSession == idSession)
     2129                rc = VWRN_NOT_FOUND;
     2130                uint32_t const idSession = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pHostCmd->m_idContext);
     2131                for (ClientStateMapIter It = mClientStateMap.begin(); It != mClientStateMap.end(); ++It)
    21702132                {
    2171                     rc = pClient->EnqueueCommand(pHostCmd);
    2172                     if (RT_SUCCESS(rc))
     2133                    ClientState *pClient = It->second;
     2134                    if (pClient->m_idSession == idSession)
    21732135                    {
     2136                        RTListAppend(&pClient->m_HostCmdList, &pHostCmd->m_ListEntry);
     2137                        pHostCmd  = pHostCmd2;
     2138                        pHostCmd2 = NULL;
     2139
    21742140                        int rc2 = pClient->Wakeup();
    21752141                        LogFlowFunc(("Woke up client ID=%RU32 -> rc=%Rrc\n", pClient->m_idClient, rc2));
    21762142                        RT_NOREF(rc2);
     2143                        rc = VINF_SUCCESS;
     2144                        break;
    21772145                    }
    2178                     break;
    21792146                }
    21802147            }
    2181         }
    2182 
    2183         /* Does the message go to the root service? */
    2184         if (   (pHostCmd->m_idContextAndDst & VBOX_GUESTCTRL_DST_ROOT_SVC)
    2185             && RT_SUCCESS(rc))
    2186         {
    2187             ClientStateMapIter It = mClientStateMap.find(m_idMasterClient);
    2188             if (It != mClientStateMap.end())
     2148
     2149            /* Does the message go to the root service? */
     2150            if (   (fDestinations & VBOX_GUESTCTRL_DST_ROOT_SVC)
     2151                && RT_SUCCESS(rc))
    21892152            {
    2190                 ClientState *pClient = It->second;
    2191                 int rc2 = pClient->EnqueueCommand(pHostCmd);
    2192                 if (RT_SUCCESS(rc2))
     2153                Assert(pHostCmd);
     2154                ClientStateMapIter It = mClientStateMap.find(m_idMasterClient);
     2155                if (It != mClientStateMap.end())
    21932156                {
    2194                     rc2 = pClient->Wakeup();
     2157                    ClientState *pClient = It->second;
     2158                    RTListAppend(&pClient->m_HostCmdList, &pHostCmd->m_ListEntry);
     2159                    pHostCmd = NULL;
     2160
     2161                    int rc2 = pClient->Wakeup();
    21952162                    LogFlowFunc(("Woke up client ID=%RU32 (master) -> rc=%Rrc\n", pClient->m_idClient, rc2));
    21962163                }
    21972164                else
    2198                     rc = rc2;
     2165                    rc = VERR_NOT_FOUND;
    21992166            }
    2200             else
    2201                 rc = VERR_NOT_FOUND;
    2202         }
    2203     }
    2204 
    2205     /* Drop our command reference. */
    2206     pHostCmd->SaneRelease();
     2167        }
     2168
     2169        /* Drop unset commands */
     2170        if (pHostCmd2)
     2171            pHostCmd2->Delete();
     2172    }
     2173    if (pHostCmd)
     2174        pHostCmd->Delete();
    22072175
    22082176    if (RT_FAILURE(rc))
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