Changeset 29867 in vbox
- Timestamp:
- May 28, 2010 3:09:23 PM (15 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostServices/GuestControl/service.cpp
r29797 r29867 28 28 * new host commands to perform. There can be multiple clients connected 29 29 * to a service. A client is represented by its HGCM client ID. 30 * - Context ID: A (almost) unique ID automatically generated on the host (Main API) 30 * - Context ID: A (almost) unique ID automatically generated on the host (Main API) 31 31 * to not only distinguish clients but individual requests. Because 32 32 * the host does not know anything about connected clients it needs 33 33 * an indicator which it can refer to later. This context ID gets 34 * internally bound by the service to a client which actually processes 34 * internally bound by the service to a client which actually processes 35 35 * the command in order to have a relationship between client<->context ID(s). 36 36 * 37 37 * The host can trigger commands which get buffered by the service (with full HGCM 38 * parameter info). As soon as a client connects (or is ready to do some new work) 39 * it gets a buffered host command to process it. This command then will be immediately 38 * parameter info). As soon as a client connects (or is ready to do some new work) 39 * it gets a buffered host command to process it. This command then will be immediately 40 40 * removed from the command list. If there are ready clients but no new commands to be 41 41 * processed, these clients will be set into a deferred state (that is being blocked 42 42 * to return until a new command is available). 43 43 * 44 * If a client needs to inform the host that something happend, it can send a 44 * If a client needs to inform the host that something happend, it can send a 45 45 * message to a low level HGCM callback registered in Main. This callback contains 46 * the actual data as well as the context ID to let the host do the next necessary 46 * the actual data as well as the context ID to let the host do the next necessary 47 47 * steps for this context. This context ID makes it possible to wait for an event 48 48 * inside the host's Main API function (like starting a process on the guest and 49 49 * wait for getting its PID returned by the client) as well as cancelling blocking 50 * host calls in order the client terminated/crashed (HGCM detects disconnected 50 * host calls in order the client terminated/crashed (HGCM detects disconnected 51 51 * clients and reports it to this service's callback). 52 52 */ … … 80 80 /** 81 81 * Structure for holding all clients with their 82 * generated host contexts. This is necessary for 82 * generated host contexts. This is necessary for 83 83 * mainting the relationship between a client and its context IDs. 84 84 */ … … 135 135 GuestCall() : mClientID(0), mHandle(0), mParms(NULL), mNumParms(0) {} 136 136 /** The normal contructor. */ 137 GuestCall(uint32_t aClientID, VBOXHGCMCALLHANDLE aHandle, 137 GuestCall(uint32_t aClientID, VBOXHGCMCALLHANDLE aHandle, 138 138 VBOXHGCMSVCPARM aParms[], uint32_t cParms) 139 139 : mClientID(aClientID), mHandle(aHandle), mParms(aParms), mNumParms(cParms) {} … … 475 475 AssertPtr(pCmd); 476 476 int rc; 477 477 478 478 /* Sufficient parameter space? */ 479 479 if (pCmd->mParmBuf.uParmCount > cParms) … … 481 481 paParms[0].setUInt32(pCmd->mParmBuf.uMsg); /* Message ID */ 482 482 paParms[1].setUInt32(pCmd->mParmBuf.uParmCount); /* Required parameters for message */ 483 483 484 484 /* 485 485 * So this call apparently failed because the guest wanted to peek … … 500 500 * defer the guest call until we have something from the host. 501 501 */ 502 int Service::retrieveNextHostCmd(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, 502 int Service::retrieveNextHostCmd(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, 503 503 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 504 504 { 505 505 int rc = VINF_SUCCESS; 506 506 507 /* 507 /* 508 508 * Lookup client in our list so that we can assign the context ID of 509 509 * a command to that client. … … 547 547 * later reference & cleanup). */ 548 548 Assert(curCmd.mContextID > 0); 549 /// @todo r=bird: check if already in the list. 549 550 it->mContextList.push_back(curCmd.mContextID); 550 551 … … 568 569 { 569 570 if (it->mClientID == u32ClientID) 570 { 571 { 571 572 if (it->mNumParms >= 2) 572 573 { 573 574 it->mParms[0].setUInt32(GETHOSTMSG_EXEC_HOST_CANCEL_WAIT); /* Message ID. */ 574 575 it->mParms[1].setUInt32(0); /* Required parameters for message. */ 575 } 576 } 576 577 if (mpHelpers) 577 mpHelpers->pfnCallComplete(it->mHandle, rc); 578 mpHelpers->pfnCallComplete(it->mHandle, rc); 578 579 it = mClientList.erase(it); 579 580 } … … 636 637 && newCmd.mParmBuf.uParmCount > 0) 637 638 { 638 /* 639 /* 639 640 * Assume that the context ID *always* is the first parameter, 640 641 * assign the context ID to the command. … … 651 652 { 652 653 GuestCall guest = mClientList.front(); 653 rc = sendHostCmdToGuest(&newCmd, 654 rc = sendHostCmdToGuest(&newCmd, 654 655 guest.mHandle, guest.mNumParms, guest.mParms); 655 656 … … 657 658 AssertPtr(mpHelpers); 658 659 mpHelpers->pfnCallComplete(guest.mHandle, rc); 659 mClientList.pop_front(); 660 660 mClientList.pop_front(); 661 661 662 /* If we got VERR_TOO_MUCH_DATA we buffer the host command in the next block 662 * and return success to the host. */ 663 * and return success to the host. */ 663 664 if (rc == VERR_TOO_MUCH_DATA) 664 665 { … … 675 676 if (!fProcessed) 676 677 { 677 mHostCmds.push_back(newCmd); 678 mHostCmds.push_back(newCmd); 678 679 #if 0 679 680 /* Limit list size by deleting oldest element. */ -
trunk/src/VBox/Main/GuestImpl.cpp
r29807 r29867 599 599 /* Not found, add to list. */ 600 600 GuestProcess p; 601 p.mPID = pCBData->u32PID; 601 p.mPID = pCBData->u32PID; 602 602 p.mStatus = pCBData->u32Status; 603 603 p.mExitCode = pCBData->u32Flags; /* Contains exit code. */ 604 604 p.mFlags = 0; 605 605 606 606 mGuestProcessList.push_back(p); 607 607 } … … 747 747 if (SUCCEEDED(it->pProgress->COMGETTER(Canceled)(&fCancelled)) && !fCancelled) 748 748 it->pProgress->Cancel(); 749 /* 750 * Do *not NULL pProgress here, because waiting function like executeProcess() 751 * will still rely on this object for checking whether they have to give up! 749 /* 750 * Do *not NULL pProgress here, because waiting function like executeProcess() 751 * will still rely on this object for checking whether they have to give up! 752 752 */ 753 753 } … … 777 777 { 778 778 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 779 /// @todo r=bird: check if already in the list and find another one. 779 780 mCallbackList.push_back(context); 780 781 nCallbacks = mCallbackList.size(); 781 } 782 } 782 783 783 784 #if 0 … … 803 804 ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress) 804 805 { 806 /** @todo r=bird: Eventually we should clean up all the timeout parameters 807 * in the API and have the same way of specifying infinite waits! */ 805 808 #ifndef VBOX_WITH_GUEST_CONTROL 806 809 ReturnComNotImplemented(); … … 860 863 for (unsigned i = 0; RT_SUCCESS(vrc) && i < uNumArgs; i++) 861 864 { 865 /// @todo r=bird: RTUtf16ToUtf8(). 862 866 int cbLen = RTStrAPrintf(&papszArgv[i], "%s", Utf8Str(args[i]).raw()); 863 867 if (cbLen < 0) … … 901 905 PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS)); 902 906 AssertReturn(pData, VBOX_E_IPRT_ERROR); 903 uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START, 907 uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START, 904 908 pData, sizeof(CALLBACKDATAEXECSTATUS), progress); 905 909 Assert(uContextID > 0); … … 921 925 VMMDev *vmmDev; 922 926 { 923 /* Make sure mParent is valid, so set the read lock while using. 927 /* Make sure mParent is valid, so set the read lock while using. 924 928 * Do not keep this lock while doing the actual call, because in the meanwhile 925 929 * another thread could request a write lock which would be a bad idea ... */ 926 930 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 927 931 928 932 /* Forward the information to the VMM device. */ 929 933 AssertPtr(mParent); … … 973 977 /* Check for manual stop. */ 974 978 if (!it->pProgress.isNull()) 975 { 979 { 976 980 rc = it->pProgress->COMGETTER(Canceled)(&fCanceled); 977 981 if (FAILED(rc)) throw rc; 978 982 if (fCanceled) 979 break; /* Client wants to abort. */ 983 break; /* HGCM/guest wants to abort because of status change. */ 984 980 985 } 986 /// @todo r=bird: two operation progress object and wait first operation. 987 /// IProgress::WaitForOperationCompletion. 981 988 RTThreadSleep(cMsWait); 982 989 } … … 986 993 if (!fCanceled) 987 994 { 988 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 995 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 989 996 990 997 PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)it->pvData; … … 1001 1008 *aPID = pData->u32PID; 1002 1009 break; 1003 1010 1004 1011 /* In any other case the process either already 1005 1012 * terminated or something else went wrong, so no PID ... */ … … 1010 1017 case PROC_STS_TOA: 1011 1018 case PROC_STS_DWN: 1012 /* 1019 /* 1013 1020 * Process (already) ended, but we want to get the 1014 * PID anyway to retrieve the output in a later call. 1021 * PID anyway to retrieve the output in a later call. 1015 1022 */ 1016 1023 *aPID = pData->u32PID; 1017 1024 break; 1018 1025 1019 1026 case PROC_STS_ERROR: 1020 1027 vrc = pData->u32Flags; /* u32Flags member contains IPRT error code. */ 1021 1028 break; 1022 1029 1023 1030 default: 1024 1031 vrc = VERR_INVALID_PARAMETER; /* Unknown status, should never happen! */ … … 1073 1080 rc = setError(E_UNEXPECTED, 1074 1081 tr("The service call failed with error %Rrc"), vrc); 1075 } 1082 } 1076 1083 } 1077 1084 else /* Execution went fine. */ … … 1121 1128 STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ULONG64 aSize, ComSafeArrayOut(BYTE, aData)) 1122 1129 { 1130 /** @todo r=bird: Eventually we should clean up all the timeout parameters 1131 * in the API and have the same way of specifying infinite waits! */ 1123 1132 #ifndef VBOX_WITH_GUEST_CONTROL 1124 1133 ReturnComNotImplemented(); … … 1132 1141 1133 1142 AutoCaller autoCaller(this); 1134 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1143 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1135 1144 1136 1145 HRESULT rc = S_OK; … … 1163 1172 pData, sizeof(CALLBACKDATAEXECOUT), progress); 1164 1173 Assert(uContextID > 0); 1165 1174 1166 1175 size_t cbData = (size_t)RT_MIN(aSize, _64K); 1167 1176 com::SafeArray<BYTE> outputData(cbData); 1168 1177 1169 1178 VBOXHGCMSVCPARM paParms[5]; 1170 1179 int i = 0; … … 1172 1181 paParms[i++].setUInt32(aPID); 1173 1182 paParms[i++].setUInt32(aFlags); /** @todo Should represent stdout and/or stderr. */ 1174 1183 1175 1184 int vrc = VINF_SUCCESS; 1176 1185 1177 1186 { 1178 1187 VMMDev *vmmDev; 1179 1188 { 1180 /* Make sure mParent is valid, so set the read lock while using. 1189 /* Make sure mParent is valid, so set the read lock while using. 1181 1190 * Do not keep this lock while doing the actual call, because in the meanwhile 1182 1191 * another thread could request a write lock which would be a bad idea ... */ 1183 1192 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1184 1193 1185 1194 /* Forward the information to the VMM device. */ 1186 1195 AssertPtr(mParent); … … 1195 1204 } 1196 1205 } 1197 1206 1198 1207 if (RT_SUCCESS(vrc)) 1199 1208 { 1200 1209 LogFlowFunc(("Waiting for HGCM callback (timeout=%ldms) ...\n", aTimeoutMS)); 1201 1210 1202 1211 /* 1203 1212 * Wait for the HGCM low level callback until the process … … 1233 1242 } 1234 1243 RTThreadSleep(cMsWait); 1235 } 1236 1244 } 1245 1237 1246 /* Was the whole thing canceled? */ 1238 1247 if (!fCanceled) … … 1241 1250 { 1242 1251 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1243 1252 1244 1253 /* Did we get some output? */ 1245 1254 pData = (PCALLBACKDATAEXECOUT)it->pvData; 1246 1255 Assert(it->cbData == sizeof(CALLBACKDATAEXECOUT)); 1247 1256 AssertPtr(pData); 1248 1257 1249 1258 if (pData->cbData) 1250 1259 { … … 1252 1261 if (pData->cbData > cbData) 1253 1262 outputData.resize(pData->cbData); 1254 1263 1255 1264 /* Fill output in supplied out buffer. */ 1256 1265 memcpy(outputData.raw(), pData->pvData, pData->cbData); … … 1296 1305 else /* PID lookup failed. */ 1297 1306 rc = setError(VBOX_E_IPRT_ERROR, 1298 tr("Process (PID %u) not found!"), aPID); 1307 tr("Process (PID %u) not found!"), aPID); 1299 1308 } 1300 1309 else /* HGCM operation failed. */ 1301 1310 rc = setError(E_UNEXPECTED, 1302 1311 tr("The HGCM call failed with error %Rrc"), vrc); 1303 1312 1304 1313 /* Cleanup. */ 1305 1314 progress->uninit(); … … 1328 1337 1329 1338 AutoCaller autoCaller(this); 1330 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1339 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1331 1340 1332 1341 HRESULT rc = S_OK; … … 1335 1344 { 1336 1345 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1337 1346 1338 1347 GuestProcessIterConst it; 1339 1348 for (it = mGuestProcessList.begin(); it != mGuestProcessList.end(); it++) … … 1342 1351 break; 1343 1352 } 1344 1353 1345 1354 if (it != mGuestProcessList.end()) 1346 1355 {
Note:
See TracChangeset
for help on using the changeset viewer.