- Timestamp:
- Nov 16, 2009 3:50:47 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/HostServices/GuestPropertySvc.h
r24666 r24703 245 245 * The parameter format matches that of ENUM_PROPS. 246 246 */ 247 ENUM_PROPS_HOST = 6 247 ENUM_PROPS_HOST = 6, 248 249 /** 250 * Flush notifications. 251 * Takes one 32-bit unsigned integer parameter that gives the number of 252 * milliseconds to wait for the worker thread to get the work done. 253 */ 254 FLUSH_NOTIFICATIONS_HOST 248 255 }; 249 256 -
trunk/src/VBox/HostServices/GuestProperties/service.cpp
r24665 r24703 21 21 */ 22 22 23 /** 23 /** @page pg_svc_guest_properties Guest Property HGCM Service 24 * 24 25 * This HGCM service allows the guest to set and query values in a property 25 26 * store on the host. The service proxies the guest requests to the service … … 39 40 */ 40 41 41 #define LOG_GROUP LOG_GROUP_HGCM42 43 42 /******************************************************************************* 44 43 * Header Files * 45 44 *******************************************************************************/ 45 #define LOG_GROUP LOG_GROUP_HGCM 46 46 #include <VBox/HostServices/GuestPropertySvc.h> 47 47 48 48 #include <VBox/log.h> 49 #include <iprt/asm.h> 50 #include <iprt/assert.h> 51 #include <iprt/autores.h> 52 #include <iprt/cpputils.h> 49 53 #include <iprt/err.h> 50 #include <iprt/assert.h> 54 #include <iprt/mem.h> 55 #include <iprt/req.h> 51 56 #include <iprt/string.h> 52 #include <iprt/mem.h> 53 #include <iprt/autores.h> 57 #include <iprt/thread.h> 54 58 #include <iprt/time.h> 55 #include <iprt/cpputils.h>56 #include <iprt/req.h>57 #include <iprt/thread.h>58 59 59 60 #include <memory> /* for auto_ptr */ … … 163 164 /** Queue of outstanding property change notifications */ 164 165 RTREQQUEUE *mReqQueue; 166 /** Request that we've left pending in a call to flushNotifications. */ 167 PRTREQ mPendingDummyReq; 165 168 /** Thread for processing the request queue */ 166 169 RTTHREAD mReqThread; 167 170 /** Tell the thread that it should exit */ 168 bool mfExitThread;171 bool volatile mfExitThread; 169 172 /** Callback function supplied by the host for notification of updates 170 173 * to properties */ … … 222 225 public: 223 226 explicit Service(PVBOXHGCMSVCHELPERS pHelpers) 224 : mpHelpers(pHelpers), mfExitThread(false), mpfnHostCallback(NULL), 225 mpvHostData(NULL) 227 : mpHelpers(pHelpers) 228 , mPendingDummyReq(NULL) 229 , mfExitThread(false) 230 , mpfnHostCallback(NULL) 231 , mpvHostData(NULL) 226 232 { 227 233 int rc = RTReqCreateQueue(&mReqQueue); … … 321 327 int delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest); 322 328 int enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 329 int flushNotifications(uint32_t cMsTimeout); 323 330 int getNotification(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, 324 331 VBOXHGCMSVCPARM paParms[]); … … 350 357 * @copydoc FNRTTHREAD 351 358 */ 359 /* static */ 352 360 DECLCALLBACK(int) Service::reqThreadFn(RTTHREAD ThreadSelf, void *pvUser) 353 361 { … … 819 827 rc = VERR_BUFFER_OVERFLOW; 820 828 } 829 return rc; 830 } 831 832 /** 833 * Flushes the notifications. 834 * 835 * @returns iprt status value 836 * @param cMsTimeout The timeout in milliseconds. 837 * @thread HGCM 838 */ 839 int Service::flushNotifications(uint32_t cMsTimeout) 840 { 841 LogFlowThisFunc(("cMsTimeout=%RU32\n", cMsTimeout)); 842 int rc; 843 844 #ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 845 /* 846 * Wait for the thread to finish processing all current requests. 847 */ 848 if (!mPendingDummyReq && !RTReqIsBusy(mReqQueue)) 849 rc = VINF_SUCCESS; 850 else 851 { 852 if (!mPendingDummyReq) 853 rc = RTReqCallEx(mReqQueue, &mPendingDummyReq, 0 /*cMillies*/, RTREQFLAGS_VOID, (PFNRT)reqVoid, 0); 854 else 855 rc = VERR_TIMEOUT; 856 if (rc == VERR_TIMEOUT) 857 rc = RTReqWait(mPendingDummyReq, cMsTimeout); 858 if (RT_SUCCESS(rc)) 859 { 860 RTReqFree(mPendingDummyReq); 861 mPendingDummyReq = NULL; 862 } 863 } 864 #else 865 NOREF(cMsTimeout); 866 rc = VINF_SUCCESS; 867 #endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */ 868 821 869 return rc; 822 870 } … … 1095 1143 */ 1096 1144 /* static */ 1097 intService::reqNotify(PFNHGCMSVCEXT pfnCallback, void *pvData,1098 char *pszName, char *pszValue, uint32_t u32TimeHigh,1099 uint32_t u32TimeLow, char *pszFlags)1145 DECLCALLBACK(int) Service::reqNotify(PFNHGCMSVCEXT pfnCallback, void *pvData, 1146 char *pszName, char *pszValue, uint32_t u32TimeHigh, 1147 uint32_t u32TimeLow, char *pszFlags) 1100 1148 { 1101 1149 LogFlowFunc (("pfnCallback=%p, pvData=%p, pszName=%p, pszValue=%p, u32TimeHigh=%u, u32TimeLow=%u, pszFlags=%p\n", pfnCallback, pvData, pszName, pszValue, u32TimeHigh, u32TimeLow, pszFlags)); … … 1247 1295 break; 1248 1296 1297 /* The host wishes to flush all pending notification */ 1298 case FLUSH_NOTIFICATIONS_HOST: 1299 LogFlowFunc(("FLUSH_NOTIFICATIONS_HOST\n")); 1300 if (cParms == 1) 1301 { 1302 uint32_t cMsTimeout; 1303 rc = paParms[0].getUInt32(&cMsTimeout); 1304 if (RT_SUCCESS(rc)) 1305 rc = flushNotifications(cMsTimeout); 1306 } 1307 else 1308 rc = VERR_INVALID_PARAMETER; 1309 break; 1310 1249 1311 default: 1250 1312 rc = VERR_NOT_SUPPORTED; … … 1264 1326 { 1265 1327 int rc = VINF_SUCCESS; 1266 unsigned count = 0; 1267 1268 mfExitThread = true; 1328 1329 ASMAtomicWriteBool(&mfExitThread, true); 1330 1269 1331 #ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 1332 /* 1333 * Send a dummy request to the thread so it is forced out of the loop and 1334 * notice that the exit flag is set. Give up waiting after 5 mins. 1335 * We call flushNotifications first to try clean up any pending request. 1336 */ 1337 flushNotifications(120*1000); 1338 1270 1339 rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT, (PFNRT)reqVoid, 0); 1271 1340 if (RT_SUCCESS(rc)) 1341 { 1342 unsigned count = 0; 1272 1343 do 1273 1344 { … … 1276 1347 Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5))); 1277 1348 } while ((VERR_TIMEOUT == rc) && (count < 300)); 1349 } 1278 1350 #endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */ 1279 1351 if (RT_SUCCESS(rc)) -
trunk/src/VBox/Main/ConsoleImpl.cpp
r24664 r24703 105 105 #include <memory> // for auto_ptr 106 106 #include <vector> 107 #include <typeinfo> 107 108 108 109 … … 1309 1310 } 1310 1311 1312 /** 1313 * Helper that is used by powerDown to move the guest properties to VBoxSVC. 1314 * 1315 * @param fSaving Whether we're saving a machine state and should 1316 * therefore save transient properties as well. 1317 * 1318 * @returns COM status code. 1319 * 1320 * @remarks This is called without holding the console lock. 1321 */ 1322 HRESULT Console::doMoveGuestPropertiesOnPowerOff(bool fSaving) 1323 { 1324 /* 1325 * First, flush any pending notifications. 1326 */ 1327 VBOXHGCMSVCPARM parm[1]; 1328 parm[0].setUInt32(20*1000/*ms*/); 1329 int vrc = mVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::FLUSH_NOTIFICATIONS_HOST, 1, &parm[0]); 1330 if (RT_FAILURE(vrc)) 1331 LogRelFunc(("Flushing notifications failed with rc=%Rrc\n", vrc)); 1332 1333 /* 1334 * Enumerate the properties and 1335 */ 1336 HRESULT hrc; 1337 com::SafeArray<BSTR> namesOut; 1338 com::SafeArray<BSTR> valuesOut; 1339 com::SafeArray<ULONG64> timestampsOut; 1340 com::SafeArray<BSTR> flagsOut; 1341 try 1342 { 1343 Bstr pattern(""); 1344 hrc = doEnumerateGuestProperties(pattern, ComSafeArrayAsOutParam(namesOut), 1345 ComSafeArrayAsOutParam(valuesOut), 1346 ComSafeArrayAsOutParam(timestampsOut), 1347 ComSafeArrayAsOutParam(flagsOut)); 1348 if (SUCCEEDED(hrc)) 1349 { 1350 std::vector <BSTR> names; 1351 std::vector <BSTR> values; 1352 std::vector <ULONG64> timestamps; 1353 std::vector <BSTR> flags; 1354 for (size_t i = 0; i < namesOut.size(); ++i) 1355 { 1356 uint32_t fFlags = guestProp::NILFLAG; 1357 vrc = guestProp::validateFlags(Utf8Str(flagsOut[i]).raw(), &fFlags); AssertRC(vrc); 1358 if ( fSaving 1359 || !(fFlags & guestProp::TRANSIENT)) 1360 { 1361 names.push_back(namesOut[i]); 1362 values.push_back(valuesOut[i]); 1363 timestamps.push_back(timestampsOut[i]); 1364 flags.push_back(flagsOut[i]); 1365 } 1366 } 1367 com::SafeArray<BSTR> namesIn(names); 1368 com::SafeArray<BSTR> valuesIn(values); 1369 com::SafeArray<ULONG64> timestampsIn(timestamps); 1370 com::SafeArray<BSTR> flagsIn(flags); 1371 if ( namesIn.isNull() 1372 || valuesIn.isNull() 1373 || timestampsIn.isNull() 1374 || flagsIn.isNull() 1375 ) 1376 throw std::bad_alloc(); 1377 /* PushGuestProperties() calls DiscardSettings(), which calls us back */ 1378 mControl->PushGuestProperties(ComSafeArrayAsInParam(namesIn), 1379 ComSafeArrayAsInParam(valuesIn), 1380 ComSafeArrayAsInParam(timestampsIn), 1381 ComSafeArrayAsInParam(flagsIn)); 1382 } 1383 } 1384 catch (...) 1385 { 1386 hrc = Console::handleUnexpectedExceptions(RT_SRC_POS); 1387 } 1388 if (FAILED(hrc)) 1389 LogRelFunc(("Failed with hrc=%Rhrc\n", hrc)); 1390 return hrc; 1391 } 1392 1393 1394 1311 1395 #endif /* VBOX_WITH_GUEST_PROPS */ 1312 1396 … … 2704 2788 ///////////////////////////////////////////////////////////////////////////// 2705 2789 2790 /** 2791 * @copydoc VirtualBox::handleUnexpectedExceptions 2792 */ 2793 /* static */ 2794 HRESULT Console::handleUnexpectedExceptions(RT_SRC_POS_DECL) 2795 { 2796 try 2797 { 2798 /* re-throw the current exception */ 2799 throw; 2800 } 2801 catch (const std::exception &err) 2802 { 2803 return setError(E_FAIL, tr("Unexpected exception: %s [%s]\n%s[%d] (%s)"), 2804 err.what(), typeid(err).name(), 2805 pszFile, iLine, pszFunction); 2806 } 2807 catch (...) 2808 { 2809 return setError(E_FAIL, tr("Unknown exception\n%s[%d] (%s)"), 2810 pszFile, iLine, pszFunction); 2811 } 2812 2813 /* should not get here */ 2814 AssertFailed(); 2815 return E_FAIL; 2816 } 2706 2817 2707 2818 /* static */ … … 2750 2861 } 2751 2862 } 2863 2864 // private methods 2865 ///////////////////////////////////////////////////////////////////////////// 2752 2866 2753 2867 /** … … 4876 4990 || mMachineState == MachineState_Restoring 4877 4991 || mMachineState == MachineState_TeleportingPausedVM 4878 || mMachineState == MachineState_TeleportingIn /** @todo Teleportation ???*/4992 || mMachineState == MachineState_TeleportingIn 4879 4993 , ("Invalid machine state: %s\n", Global::stringifyMachineState(mMachineState))); 4880 4994 … … 4894 5008 mVMPoweredOff = true; 4895 5009 4896 /* go to Stopping state if not already there. Note that we don't go from 4897 * Saving/Restoring to Stopping because vmstateChangeCallback() needs it to 4898 * set the state to Saved on VMSTATE_TERMINATED. In terms of protecting from 4899 * inappropriate operations while leaving the lock below, Saving or 4900 * Restoring should be fine too. Ditto for Teleporting* -> Teleported. */ 5010 /* 5011 * Go to Stopping state if not already there. 5012 * 5013 * Note that we don't go from Saving/Restoring to Stopping because 5014 * vmstateChangeCallback() needs it to set the state to Saved on 5015 * VMSTATE_TERMINATED. In terms of protecting from inappropriate operations 5016 * while leaving the lock below, Saving or Restoring should be fine too. 5017 * Ditto for TeleportingPausedVM -> Teleported. 5018 */ 4901 5019 if ( mMachineState != MachineState_Saving 4902 5020 && mMachineState != MachineState_Restoring … … 4931 5049 aProgress->SetCurrentOperationProgress(99 * (++ step) / StepCount ); 4932 5050 4933 #ifdef VBOX_WITH_HGCM4934 4935 # ifdef VBOX_WITH_GUEST_PROPS /** @todo r=bird: This may be premature, the VM may still be running at this point! */4936 4937 /* Save all guest property store entries to the machine XML file */4938 com::SafeArray<BSTR> namesOut;4939 com::SafeArray<BSTR> valuesOut;4940 com::SafeArray<ULONG64> timestampsOut;4941 com::SafeArray<BSTR> flagsOut;4942 Bstr pattern("");4943 if (pattern.isNull()) /** @todo r=bird: What is pattern actually used for? And, again, what's is the out-of-memory policy in main? */4944 rc = E_OUTOFMEMORY;4945 else4946 rc = doEnumerateGuestProperties(Bstr(""), ComSafeArrayAsOutParam(namesOut),4947 ComSafeArrayAsOutParam(valuesOut),4948 ComSafeArrayAsOutParam(timestampsOut),4949 ComSafeArrayAsOutParam(flagsOut));4950 if (SUCCEEDED(rc))4951 {4952 try4953 {4954 std::vector <BSTR> names;4955 std::vector <BSTR> values;4956 std::vector <ULONG64> timestamps;4957 std::vector <BSTR> flags;4958 for (unsigned i = 0; i < namesOut.size(); ++i)4959 {4960 uint32_t fFlags;4961 guestProp::validateFlags(Utf8Str(flagsOut[i]).raw(), &fFlags);4962 if ( !(fFlags & guestProp::TRANSIENT)4963 || mMachineState == MachineState_Saving4964 || mMachineState == MachineState_LiveSnapshotting4965 )4966 {4967 names.push_back(namesOut[i]);4968 values.push_back(valuesOut[i]);4969 timestamps.push_back(timestampsOut[i]);4970 flags.push_back(flagsOut[i]);4971 }4972 }4973 com::SafeArray<BSTR> namesIn(names);4974 com::SafeArray<BSTR> valuesIn(values);4975 com::SafeArray<ULONG64> timestampsIn(timestamps);4976 com::SafeArray<BSTR> flagsIn(flags);4977 if ( namesIn.isNull()4978 || valuesIn.isNull()4979 || timestampsIn.isNull()4980 || flagsIn.isNull()4981 )4982 throw std::bad_alloc();4983 /* PushGuestProperties() calls DiscardSettings(), which calls us back */4984 alock.leave();4985 mControl->PushGuestProperties(ComSafeArrayAsInParam(namesIn),4986 ComSafeArrayAsInParam(valuesIn),4987 ComSafeArrayAsInParam(timestampsIn),4988 ComSafeArrayAsInParam(flagsIn));4989 alock.enter();4990 }4991 catch (std::bad_alloc)4992 {4993 rc = E_OUTOFMEMORY;4994 }4995 }4996 4997 /* advance percent count */4998 if (aProgress)4999 aProgress->SetCurrentOperationProgress(99 * (++ step) / StepCount );5000 5001 # endif /* VBOX_WITH_GUEST_PROPS defined */5002 5003 /* Shutdown HGCM services before stopping the guest, because they might5004 * need a cleanup. */5005 if (mVMMDev)5006 {5007 LogFlowThisFunc(("Shutdown HGCM...\n"));5008 5009 /* Leave the lock since EMT will call us back as addVMCaller() */5010 alock.leave();5011 5012 mVMMDev->hgcmShutdown();5013 5014 alock.enter();5015 }5016 5017 /* advance percent count */5018 if (aProgress)5019 aProgress->SetCurrentOperationProgress(99 * (++ step) / StepCount );5020 5021 #endif /* VBOX_WITH_HGCM */5022 5051 5023 5052 /* ---------------------------------------------------------------------- … … 5052 5081 vrc = VINF_SUCCESS; 5053 5082 5054 /* Power off the VM if not already done that */ 5083 /* 5084 * Power off the VM if not already done that. 5085 * Leave the lock since EMT will call vmstateChangeCallback. 5086 * 5087 * Note that VMR3PowerOff() may fail here (invalid VMSTATE) if the 5088 * VM-(guest-)initiated power off happened in parallel a ms before this 5089 * call. So far, we let this error pop up on the user's side. 5090 */ 5055 5091 if (!mVMPoweredOff) 5056 5092 { 5057 5093 LogFlowThisFunc(("Powering off the VM...\n")); 5058 5059 /* Leave the lock since EMT will call us back on VMR3PowerOff() */5060 5094 alock.leave(); 5061 5062 5095 vrc = VMR3PowerOff(mpVM); 5063 5064 /* Note that VMR3PowerOff() may fail here (invalid VMSTATE) if the5065 * VM-(guest-)initiated power off happened in parallel a ms before this5066 * call. So far, we let this error pop up on the user's side. */5067 5068 5096 alock.enter(); 5069 5070 5097 } 5071 5098 else 5072 5099 { 5073 /* reset the flag for further re-use */ 5100 /** @todo r=bird: Doesn't make sense. Please remove after 3.1 has been branched 5101 * off. */ 5102 /* reset the flag for future re-use */ 5074 5103 mVMPoweredOff = false; 5075 5104 } … … 5079 5108 aProgress->SetCurrentOperationProgress(99 * (++ step) / StepCount ); 5080 5109 5110 #ifdef VBOX_WITH_HGCM 5111 # ifdef VBOX_WITH_GUEST_PROPS 5112 /* 5113 * Save all guest property store entries to the machine XML file 5114 * and hand controll over to VBoxSVC. Ignoring failure for now. 5115 */ 5116 LogFlowThisFunc(("Moving Guest Properties to XML/VBoxSVC...\n")); 5117 bool fIsSaving = mMachineState == MachineState_Saving 5118 || mMachineState == MachineState_LiveSnapshotting; 5119 alock.leave(); 5120 doMoveGuestPropertiesOnPowerOff(fIsSaving); 5121 alock.enter(); 5122 5123 /* advance percent count */ 5124 if (aProgress) 5125 aProgress->SetCurrentOperationProgress(99 * (++ step) / StepCount ); 5126 5127 # endif /* VBOX_WITH_GUEST_PROPS defined */ 5128 5129 /* Shutdown HGCM services before destroying the VM. */ 5130 if (mVMMDev) 5131 { 5132 LogFlowThisFunc(("Shutdown HGCM...\n")); 5133 5134 /* Leave the lock since EMT will call us back as addVMCaller() */ 5135 alock.leave(); 5136 5137 mVMMDev->hgcmShutdown(); 5138 5139 alock.enter(); 5140 } 5141 5142 /* advance percent count */ 5143 if (aProgress) 5144 aProgress->SetCurrentOperationProgress(99 * (++ step) / StepCount ); 5145 5146 #endif /* VBOX_WITH_HGCM */ 5147 5081 5148 LogFlowThisFunc(("Ready for VM destruction.\n")); 5082 5149 … … 5085 5152 if (RT_SUCCESS(vrc) || autoCaller.state() == InUninit) 5086 5153 { 5087 /* If the machine has an USB co mtroller, release all USB devices5154 /* If the machine has an USB controller, release all USB devices 5088 5155 * (symmetric to the code in captureUSBDevices()) */ 5089 5156 bool fHasUSBController = false; -
trunk/src/VBox/Main/include/ConsoleImpl.h
r24579 r24703 223 223 } 224 224 225 static HRESULT handleUnexpectedExceptions(RT_SRC_POS_DECL); 226 225 227 static const char *convertControllerTypeToDev(StorageControllerType_T enmCtrlType); 226 228 static HRESULT convertBusPortDeviceToLun(StorageBus_T enmBus, LONG port, LONG device, unsigned &uLun); … … 505 507 506 508 #ifdef VBOX_WITH_GUEST_PROPS 507 static DECLCALLBACK(int) doGuestPropNotification (void *pvExtension, uint32_t,508 void *pvParms, uint32_t cbParms);509 HRESULT doEnumerateGuestProperties(CBSTR aPatterns,510 ComSafeArrayOut(BSTR, aNames),511 ComSafeArrayOut(BSTR, aValues),512 ComSafeArrayOut(ULONG64, aTimestamps),513 ComSafeArrayOut(BSTR, aFlags));509 static DECLCALLBACK(int) doGuestPropNotification(void *pvExtension, uint32_t, void *pvParms, uint32_t cbParms); 510 HRESULT doMoveGuestPropertiesOnPowerOff(bool fSaving); 511 HRESULT doEnumerateGuestProperties(CBSTR aPatterns, 512 ComSafeArrayOut(BSTR, aNames), 513 ComSafeArrayOut(BSTR, aValues), 514 ComSafeArrayOut(ULONG64, aTimestamps), 515 ComSafeArrayOut(BSTR, aFlags)); 514 516 515 517 bool enabledGuestPropertiesVRDP (void);
Note:
See TracChangeset
for help on using the changeset viewer.