Changeset 75872 in vbox for trunk/src/VBox/HostServices/GuestControl/service.cpp
- Timestamp:
- Dec 2, 2018 4:30:13 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostServices/GuestControl/service.cpp
r75871 r75872 111 111 typedef struct HostCommand 112 112 { 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; 117 115 union 118 116 { 119 117 /** The top two twomost bits are exploited for message destination. 120 118 * See VBOX_GUESTCTRL_DST_XXX. */ 121 uint64_t m_idContextAndDst;119 uint64_t m_idContextAndDst; 122 120 /** The context ID this command belongs to (extracted from the first parameter). */ 123 uint32_t m_idContext;121 uint32_t m_idContext; 124 122 }; 125 123 /** Dynamic structure for holding the HGCM parms */ … … 131 129 132 130 HostCommand() 133 : m_cRefs(1) 134 , m_idContextAndDst(0) 131 : m_idContextAndDst(0) 135 132 , mMsgType(UINT32_MAX) 136 133 , mParmCount(0) … … 140 137 } 141 138 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 155 139 /** 156 140 * Releases the host command, properly deleting it if no further references. 157 141 */ 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; 183 159 } 184 160 … … 201 177 Assert(mpParms == NULL); 202 178 Assert(mParmCount == 0); 203 Assert( m_cRefs == 1);179 Assert(RTListIsEmpty(&m_ListEntry)); 204 180 205 181 /* … … 482 458 { 483 459 PVBOXHGCMSVCHELPERS m_pSvcHelpers; 460 /** Host command list to process (HostCommand). */ 461 RTLISTANCHOR m_HostCmdList; 484 462 /** The HGCM client ID. */ 485 463 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; 488 471 /** Pending client call (GUEST_MSG_PEEK_WAIT or GUEST_MSG_WAIT), zero if none pending. 489 472 * … … 491 474 * from the waiting call until a new host command is available. */ 492 475 guestControl::eGuestFn m_enmIsPending; 493 /** The client's pending connection. */476 /** Pending peek/wait request details. */ 494 477 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;501 478 502 479 … … 504 481 : m_pSvcHelpers(NULL) 505 482 , m_idClient(0) 483 , m_idSession(UINT32_MAX) 484 , m_fIsMaster(false) 485 , m_fPendingCancel(false) 506 486 , m_enmIsPending((guestControl::eGuestFn)0) 507 , m_fPendingCancel(false)508 , m_fIsMaster(false)509 , m_idSession(UINT32_MAX)510 487 , mHostCmdRc(VINF_SUCCESS) 511 488 , mHostCmdTries(0) 512 489 , mPeekCount(0) 513 { } 490 { 491 RTListInit(&m_HostCmdList); 492 } 514 493 515 494 ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers, uint32_t idClient) 516 495 : m_pSvcHelpers(pSvcHelpers) 517 496 , m_idClient(idClient) 497 , m_idSession(UINT32_MAX) 498 , m_fIsMaster(false) 499 , m_fPendingCancel(false) 518 500 , m_enmIsPending((guestControl::eGuestFn)0) 519 , m_fPendingCancel(false)520 , m_fIsMaster(false)521 , m_idSession(UINT32_MAX)522 501 , mHostCmdRc(VINF_SUCCESS) 523 502 , mHostCmdTries(0) 524 503 , mPeekCount(0) 525 { } 504 { 505 RTListInit(&m_HostCmdList); 506 } 526 507 527 508 /** 528 509 * Used by for Service::hostProcessCommand(). 529 510 */ 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); 545 515 } 546 516 … … 560 530 rc = VINF_SUCCESS; 561 531 562 HostC mdList::iterator ItFirstCmd = mHostCmdList.begin();563 if ( ItFirstCmd != mHostCmdList.end())532 HostCommand *pFirstCmd = RTListGetFirstCpp(&m_HostCmdList, HostCommand, m_ListEntry); 533 if (pFirstCmd) 564 534 { 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)); 570 537 571 538 if (m_enmIsPending == GUEST_MSG_PEEK_WAIT) … … 577 544 m_PendingReq.mParms = NULL; 578 545 m_PendingReq.mNumParms = 0; 579 m_enmIsPending 546 m_enmIsPending = (guestControl::eGuestFn)0; 580 547 } 581 548 else if (m_enmIsPending == GUEST_MSG_WAIT) … … 676 643 void OldDitchFirstHostCmd() 677 644 { 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); 683 648 684 649 /* Reset state else. */ … … 697 662 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 698 663 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 699 Assert( *mHostCmdList.begin() == pHostCmd);664 Assert(RTListNodeIsFirst(&m_HostCmdList, &pHostCmd->m_ListEntry)); 700 665 701 666 LogFlowFunc(("[Client %RU32] pConnection=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32, mPeekCount=%RU32\n", … … 744 709 if (fRemove) 745 710 { 746 Assert( *mHostCmdList.begin() == pHostCmd);711 Assert(RTListNodeIsFirst(&m_HostCmdList, &pHostCmd->m_ListEntry)); 747 712 OldDitchFirstHostCmd(); 748 713 } … … 762 727 * If the host command list is empty, the request must wait for one to be posted. 763 728 */ 764 if (mHostCmdList.empty()) 729 HostCommand *pFirstCmd = RTListGetFirstCpp(&m_HostCmdList, HostCommand, m_ListEntry); 730 if (!pFirstCmd) 765 731 { 766 732 if (!m_fPendingCancel) … … 786 752 * Return first host command. 787 753 */ 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); 794 755 } 795 756 … … 899 860 /** User data pointer to be supplied to the host callback function. */ 900 861 void *mpvHostData; 901 /** List containing all buffered host commands. */902 RTLISTANCHOR mHostCmdList;903 862 /** Map containing all connected clients, key is HGCM client ID. */ 904 863 ClientStateMap mClientStateMap; /**< @todo Use VBOXHGCMSVCFNTABLE::cbClient for this! */ … … 921 880 , m_cPreparedSessions(0) 922 881 { 923 RTListInit(&mHostCmdList);924 882 RTListInit(&m_PreparedSessions); 925 883 } … … 1057 1015 * Cancel all pending host commands, replying with GUEST_DISCONNECTED if final recipient. 1058 1016 */ 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(); 1075 1030 } 1076 1031 … … 1099 1054 if (pThis->mClientStateMap.empty()) 1100 1055 pThis->m_fLegacyMode = true; 1101 1102 /*1103 * Host command sanity check.1104 */1105 Assert(RTListIsEmpty(&pThis->mHostCmdList) || !pThis->mClientStateMap.empty());1106 1056 1107 1057 return VINF_SUCCESS; … … 1240 1190 * Return information about the first command if one is pending in the list. 1241 1191 */ 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 { 1246 1195 pFirstCmd->setPeekReturn(paParms, cParms); 1247 1196 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_XXXX -> VINF_SUCCESS (idMsg=%u (%s), cParms=%u)\n", … … 1303 1252 1304 1253 /* 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 { 1311 1259 1312 1260 ASSERT_GUEST_MSG_RETURN(pFirstCmd->mMsgType == idMsgExpected || idMsgExpected == UINT32_MAX, … … 1374 1322 if (rc != VERR_CANCELLED) 1375 1323 { 1376 pClient->mHostCmdList.erase(itFirstCmd);1377 pFirstCmd-> SaneRelease();1324 RTListNodeRemove(&pFirstCmd->m_ListEntry); 1325 pFirstCmd->Delete(); 1378 1326 } 1379 1327 else … … 1456 1404 * Do the job. 1457 1405 */ 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 { 1461 1409 if ( pFirstCmd->mMsgType == idMsg 1462 1410 || idMsg == UINT32_MAX) … … 1468 1416 * Remove the command from the queue. 1469 1417 */ 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); 1472 1420 1473 1421 /* … … 1556 1504 * Free the command. 1557 1505 */ 1558 pFirstCmd-> SaneRelease();1506 pFirstCmd->Delete(); 1559 1507 } 1560 1508 else … … 1898 1846 * Execute the request. 1899 1847 */ 1900 if (! pClient->mHostCmdList.empty())1848 if (!RTListIsEmpty(&pClient->m_HostCmdList)) 1901 1849 pClient->OldDitchFirstHostCmd(); 1902 1850 … … 2133 2081 /* 2134 2082 * 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 host2083 * and immediately return an error to the host. This avoids the host 2136 2084 * waiting for a response from the guest side in case VBoxService on 2137 2085 * the guest is not running/system is messed up somehow. … … 2143 2091 } 2144 2092 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 */ 2145 2098 HostCommand *pHostCmd = new (std::nothrow) HostCommand(); 2146 2099 AssertReturn(pHostCmd, VERR_NO_MEMORY); 2147 2148 2100 int rc = pHostCmd->Init(idFunction, cParms, paParms); 2149 2101 if (RT_SUCCESS(rc)) 2150 2102 { 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) 2167 2128 { 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) 2170 2132 { 2171 rc = pClient->EnqueueCommand(pHostCmd);2172 if ( RT_SUCCESS(rc))2133 ClientState *pClient = It->second; 2134 if (pClient->m_idSession == idSession) 2173 2135 { 2136 RTListAppend(&pClient->m_HostCmdList, &pHostCmd->m_ListEntry); 2137 pHostCmd = pHostCmd2; 2138 pHostCmd2 = NULL; 2139 2174 2140 int rc2 = pClient->Wakeup(); 2175 2141 LogFlowFunc(("Woke up client ID=%RU32 -> rc=%Rrc\n", pClient->m_idClient, rc2)); 2176 2142 RT_NOREF(rc2); 2143 rc = VINF_SUCCESS; 2144 break; 2177 2145 } 2178 break;2179 2146 } 2180 2147 } 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)) 2189 2152 { 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()) 2193 2156 { 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(); 2195 2162 LogFlowFunc(("Woke up client ID=%RU32 (master) -> rc=%Rrc\n", pClient->m_idClient, rc2)); 2196 2163 } 2197 2164 else 2198 rc = rc2;2165 rc = VERR_NOT_FOUND; 2199 2166 } 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(); 2207 2175 2208 2176 if (RT_FAILURE(rc))
Note:
See TracChangeset
for help on using the changeset viewer.