Changeset 27781 in vbox
- Timestamp:
- Mar 29, 2010 11:52:20 AM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 59430
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/HostServices/GuestPropertySvc.h
r25647 r27781 251 251 * Takes one 32-bit unsigned integer parameter for the flags. 252 252 */ 253 SET_GLOBAL_FLAGS_HOST = 7, 254 255 /** 256 * Flush notifications. 257 * Takes one 32-bit unsigned integer parameter that gives the number of 258 * milliseconds to wait for the worker thread to get the work done. 259 */ 260 FLUSH_NOTIFICATIONS_HOST 253 SET_GLOBAL_FLAGS_HOST = 7 261 254 }; 262 255 -
trunk/src/VBox/HostServices/GuestProperties/service.cpp
r26749 r27781 163 163 CallList mGuestWaiters; 164 164 /** @todo we should have classes for thread and request handler thread */ 165 /** Queue of outstanding property change notifications */166 RTREQQUEUE *mReqQueue;167 /** Request that we've left pending in a call to flushNotifications. */168 PRTREQ mPendingDummyReq;169 /** Thread for processing the request queue */170 RTTHREAD mReqThread;171 /** Tell the thread that it should exit */172 bool volatile mfExitThread;173 165 /** Callback function supplied by the host for notification of updates 174 166 * to properties */ … … 249 241 : mpHelpers(pHelpers) 250 242 , meGlobalFlags(NILFLAG) 251 , mPendingDummyReq(NULL)252 , mfExitThread(false)253 243 , mpfnHostCallback(NULL) 254 244 , mpvHostData(NULL) 255 { 256 int rc = RTReqCreateQueue(&mReqQueue); 257 #ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 258 if (RT_SUCCESS(rc)) 259 rc = RTThreadCreate(&mReqThread, reqThreadFn, this, 0, 260 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE, 261 "GuestPropReq"); 262 #endif 263 if (RT_FAILURE(rc)) 264 throw rc; 265 } 245 { } 266 246 267 247 /** … … 350 330 int delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest); 351 331 int enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 352 int flushNotifications(uint32_t cMsTimeout);353 332 int getNotification(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, 354 333 VBOXHGCMSVCPARM paParms[]); … … 357 336 int getNotificationWriteOut(VBOXHGCMSVCPARM paParms[], Property prop); 358 337 void doNotifications(const char *pszProperty, uint64_t u64Timestamp); 359 static DECLCALLBACK(int) reqNotify(PFNHGCMSVCEXT pfnCallback, 360 void *pvData, char *pszName, 361 char *pszValue, uint32_t u32TimeHigh, 362 uint32_t u32TimeLow, char *pszFlags); 363 /** 364 * Empty request function for terminating the request thread. 365 * @returns VINF_EOF to cause the request processing function to return 366 * @todo return something more appropriate 367 */ 368 static DECLCALLBACK(int) reqVoid() { return VINF_EOF; } 338 int notifyHost(const char *pszName, const char *pszValue, 339 uint64_t u64Timestamp, const char *pszFlags); 369 340 370 341 void call (VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, … … 374 345 int uninit (); 375 346 }; 376 377 378 /**379 * Thread function for processing the request queue380 * @copydoc FNRTTHREAD381 */382 /* static */383 DECLCALLBACK(int) Service::reqThreadFn(RTTHREAD ThreadSelf, void *pvUser)384 {385 SELF *pSelf = reinterpret_cast<SELF *>(pvUser);386 while (!pSelf->mfExitThread)387 RTReqProcess(pSelf->mReqQueue, RT_INDEFINITE_WAIT);388 return VINF_SUCCESS;389 }390 347 391 348 … … 849 806 } 850 807 851 /**852 * Flushes the notifications.853 *854 * @returns iprt status value855 * @param cMsTimeout The timeout in milliseconds.856 * @thread HGCM857 */858 int Service::flushNotifications(uint32_t cMsTimeout)859 {860 LogFlowThisFunc(("cMsTimeout=%RU32\n", cMsTimeout));861 int rc;862 863 #ifndef VBOX_GUEST_PROP_TEST_NOTHREAD864 /*865 * Wait for the thread to finish processing all current requests.866 */867 if (!mPendingDummyReq && !RTReqIsBusy(mReqQueue))868 rc = VINF_SUCCESS;869 else870 {871 if (!mPendingDummyReq)872 rc = RTReqCallEx(mReqQueue, &mPendingDummyReq, 0 /*cMillies*/, RTREQFLAGS_VOID, (PFNRT)reqVoid, 0);873 else874 rc = VERR_TIMEOUT;875 if (rc == VERR_TIMEOUT)876 rc = RTReqWait(mPendingDummyReq, cMsTimeout);877 if (RT_SUCCESS(rc))878 {879 RTReqFree(mPendingDummyReq);880 mPendingDummyReq = NULL;881 }882 }883 #else884 NOREF(cMsTimeout);885 rc = VINF_SUCCESS;886 #endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */887 888 return rc;889 }890 808 891 809 /** Helper query used by getOldNotification */ … … 919 837 } 920 838 839 921 840 /** Helper query used by getNotification */ 922 841 int Service::getNotificationWriteOut(VBOXHGCMSVCPARM paParms[], Property prop) … … 957 876 } 958 877 878 959 879 /** 960 880 * Get the next guest notification. … … 1015 935 } 1016 936 937 1017 938 /** 1018 939 * Notify the service owner and the guest that a property has been … … 1020 941 * @param pszProperty the name of the property which has changed 1021 942 * @param u64Timestamp the time at which the change took place 1022 * @note this call allocates memory which the reqNotify request is expected to1023 * free again, using RTStrFree().1024 943 * 1025 944 * @thread HGCM service … … 1091 1010 mGuestNotifications.pop_front(); 1092 1011 1093 #ifndef VBOX_GUEST_PROP_TEST_NOTHREAD1094 1012 /* 1095 1013 * Host notifications - first case: if the property exists then send its 1096 1014 * current value 1097 1015 */ 1098 char *pszName = NULL, *pszValue = NULL, *pszFlags = NULL;1099 1100 1016 if (found && mpfnHostCallback != NULL) 1101 1017 { 1102 1018 char szFlags[MAX_FLAGS_LEN]; 1103 1019 /* Send out a host notification */ 1104 rc = writeFlags(prop.mFlags, szFlags);1020 const char *pszValue = prop.mValue.c_str(); 1105 1021 if (RT_SUCCESS(rc)) 1106 rc = RTStrDupEx(&pszName, pszProperty);1022 rc = writeFlags(prop.mFlags, szFlags); 1107 1023 if (RT_SUCCESS(rc)) 1108 rc = RTStrDupEx(&pszValue, prop.mValue.c_str()); 1109 if (RT_SUCCESS(rc)) 1110 rc = RTStrDupEx(&pszFlags, szFlags); 1111 if (RT_SUCCESS(rc)) 1112 { 1113 LogFlowThisFunc (("pszName=%p (%s)\n", pszName, pszName)); 1114 LogFlowThisFunc (("pszValue=%p (%s)\n", pszValue, pszValue)); 1115 LogFlowThisFunc (("pszFlags=%p (%s)\n", pszFlags, pszFlags)); 1116 rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT, 1117 (PFNRT)Service::reqNotify, 7, mpfnHostCallback, 1118 mpvHostData, pszName, pszValue, 1119 (uint32_t) RT_HIDWORD(u64Timestamp), 1120 (uint32_t) RT_LODWORD(u64Timestamp), pszFlags); 1121 } 1024 rc = notifyHost(pszProperty, pszValue, u64Timestamp, szFlags); 1122 1025 } 1123 1026 … … 1129 1032 { 1130 1033 /* Send out a host notification */ 1131 rc = RTStrDupEx(&pszName, pszProperty);1132 1034 if (RT_SUCCESS(rc)) 1133 { 1134 LogFlowThisFunc (("pszName=%p (%s)\n", pszName, pszName)); 1135 rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT, 1136 (PFNRT)Service::reqNotify, 7, mpfnHostCallback, 1137 mpvHostData, pszName, (uintptr_t) NULL, 1138 (uint32_t) RT_HIDWORD(u64Timestamp), 1139 (uint32_t) RT_LODWORD(u64Timestamp), 1140 (uintptr_t) NULL); 1141 } 1142 } 1143 if (RT_FAILURE(rc)) /* clean up if we failed somewhere */ 1144 { 1145 LogThisFunc (("Failed, freeing allocated strings.\n")); 1146 RTStrFree(pszName); 1147 RTStrFree(pszValue); 1148 RTStrFree(pszFlags); 1035 rc = notifyHost(pszProperty, NULL, u64Timestamp, NULL); 1149 1036 } 1150 1037 LogFlowThisFunc (("returning\n")); 1151 #endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */1152 1038 } 1153 1039 1154 1040 /** 1155 1041 * Notify the service owner that a property has been added/deleted/changed. 1156 * asynchronous part. 1157 * @param pszProperty the name of the property which has changed 1158 * @note this call allocates memory which the reqNotify request is expected to 1159 * free again, using RTStrFree(). 1160 * 1161 * @thread request thread 1162 */ 1163 /* static */ 1164 DECLCALLBACK(int) Service::reqNotify(PFNHGCMSVCEXT pfnCallback, void *pvData, 1165 char *pszName, char *pszValue, uint32_t u32TimeHigh, 1166 uint32_t u32TimeLow, char *pszFlags) 1167 { 1168 LogFlowFunc (("pfnCallback=%p, pvData=%p, pszName=%p, pszValue=%p, u32TimeHigh=%u, u32TimeLow=%u, pszFlags=%p\n", pfnCallback, pvData, pszName, pszValue, u32TimeHigh, u32TimeLow, pszFlags)); 1169 LogFlowFunc (("pszName=%s\n", pszName)); 1170 LogFlowFunc (("pszValue=%s\n", pszValue)); 1171 LogFlowFunc (("pszFlags=%s\n", pszFlags)); 1172 /* LogFlowFunc (("pfnCallback=%p, pvData=%p, pszName=%s, pszValue=%s, u32TimeHigh=%u, u32TimeLow=%u, pszFlags=%s\n", pfnCallback, pvData, pszName, pszValue, u32TimeHigh, u32TimeLow, pszFlags)); */ 1042 * @returns IPRT status value 1043 * @param pszName the property name 1044 * @param pszValue the new value, or NULL if the property was deleted 1045 * @param u64Timestamp the time of the change 1046 * @param pszFlags the new flags string 1047 */ 1048 int Service::notifyHost(const char *pszName, const char *pszValue, 1049 uint64_t u64Timestamp, const char *pszFlags) 1050 { 1051 LogFlowFunc (("pszName=%s, pszValue=%s, u64Timestamp=%llu, pszFlags=%s\n", 1052 pszName, pszValue, u64Timestamp, pszFlags)); 1173 1053 HOSTCALLBACKDATA HostCallbackData; 1174 1054 HostCallbackData.u32Magic = HOSTCALLBACKMAGIC; 1175 1055 HostCallbackData.pcszName = pszName; 1176 1056 HostCallbackData.pcszValue = pszValue; 1177 HostCallbackData.u64Timestamp = RT_MAKE_U64(u32TimeLow, u32TimeHigh);1057 HostCallbackData.u64Timestamp = u64Timestamp; 1178 1058 HostCallbackData.pcszFlags = pszFlags; 1179 int rc = pfnCallback(pvData, 0 /*u32Function*/, (void *)(&HostCallbackData), 1180 sizeof(HostCallbackData)); 1181 AssertRC(rc); 1182 LogFlowFunc (("Freeing strings\n")); 1183 RTStrFree(pszName); 1184 RTStrFree(pszValue); 1185 RTStrFree(pszFlags); 1186 LogFlowFunc (("returning success\n")); 1187 return VINF_SUCCESS; 1059 int rc = mpfnHostCallback (mpvHostData, 0 /*u32Function*/, 1060 (void *)(&HostCallbackData), 1061 sizeof(HostCallbackData)); 1062 LogFlowFunc (("returning %Rrc\n", rc)); 1063 return rc; 1188 1064 } 1189 1065 … … 1328 1204 break; 1329 1205 1330 /* The host wishes to flush all pending notification */1331 case FLUSH_NOTIFICATIONS_HOST:1332 LogFlowFunc(("FLUSH_NOTIFICATIONS_HOST\n"));1333 if (cParms == 1)1334 {1335 uint32_t cMsTimeout;1336 rc = paParms[0].getUInt32(&cMsTimeout);1337 if (RT_SUCCESS(rc))1338 rc = flushNotifications(cMsTimeout);1339 }1340 else1341 rc = VERR_INVALID_PARAMETER;1342 break;1343 1344 1206 default: 1345 1207 rc = VERR_NOT_SUPPORTED; … … 1358 1220 int Service::uninit() 1359 1221 { 1360 int rc = VINF_SUCCESS; 1361 1362 ASMAtomicWriteBool(&mfExitThread, true); 1363 1364 #ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 1365 /* 1366 * Send a dummy request to the thread so it is forced out of the loop and 1367 * notice that the exit flag is set. Give up waiting after 5 mins. 1368 * We call flushNotifications first to try clean up any pending request. 1369 */ 1370 flushNotifications(120*1000); 1371 1372 rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT, (PFNRT)reqVoid, 0); 1373 if (RT_SUCCESS(rc)) 1374 { 1375 unsigned count = 0; 1376 do 1377 { 1378 rc = RTThreadWait(mReqThread, 1000, NULL); 1379 ++count; 1380 Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5))); 1381 } while ((VERR_TIMEOUT == rc) && (count < 300)); 1382 } 1383 #endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */ 1384 if (RT_SUCCESS(rc)) 1385 RTReqDestroyQueue(mReqQueue); 1386 return rc; 1222 return VINF_SUCCESS; 1387 1223 } 1388 1224
Note:
See TracChangeset
for help on using the changeset viewer.