Changeset 13971 in vbox
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/HostServices/GuestPropertySvc.h
r13928 r13971 431 431 * On success, VINF_SUCCESS will be returned and the buffer will contain 432 432 * details of a property notification. If no new notification is available, 433 * a timestamp of zero will be returned.433 * the call will block until one is. 434 434 * If the last notification could not be found by timestamp, VWRN_NOT_FOUND 435 435 * will be returned and the oldest available notification will be returned. 436 * if no timestamp is specified, the oldest available notification will be436 * If no timestamp is specified, the oldest available notification will be 437 437 * returned. 438 438 * If the buffer supplied was not large enough to hold the notification, 439 439 * VERR_BUFFER_OVERFLOW will be returned and the size parameter will contain 440 440 * the size of the buffer needed. 441 * 442 * The protocol for a guest to obtain notifications is to call 443 * GET_NOTIFICATION in a loop. On the first call, the ingoing timestamp 444 * parameter should be set to zero. On subsequent calls, it should be set to 445 * the outgoing timestamp from the previous call. 441 446 */ 442 447 typedef struct _GetNotification … … 452 457 * 453 458 * The timestamp of the change being notified of (OUT uint64_t) 454 * If this is zero then no new events are available. Undefined on 455 * failure. 459 * Undefined on failure. 456 460 */ 457 461 HGCMFunctionParameter timestamp; 458 462 459 463 /** 460 * The returned data . if anywill be placed here. (OUT pointer)464 * The returned data, if any, will be placed here. (OUT pointer) 461 465 * This call returns three null-terminated strings which will be placed 462 466 * one after another: name, value and flags. For a delete notification, -
trunk/src/VBox/HostServices/GuestProperties/service.cpp
r13922 r13971 60 60 #include <string> 61 61 #include <list> 62 #include <vector> 62 63 63 64 namespace guestProp { … … 104 105 /** The list of property changes for guest notifications */ 105 106 PropertyList mGuestNotifications; 107 /** Structure for holding an uncompleted guest call */ 108 struct GuestCall 109 { 110 /** The call handle */ 111 VBOXHGCMCALLHANDLE mHandle; 112 /** The function that was requested */ 113 uint32_t mFunction; 114 /** The number of parameters */ 115 uint32_t mcParms; 116 /** The parameters themselves */ 117 VBOXHGCMSVCPARM *mParms; 118 119 /** The standard constructor */ 120 GuestCall() : mFunction(0), mcParms(0) {} 121 /** The normal contructor */ 122 GuestCall(VBOXHGCMCALLHANDLE aHandle, uint32_t aFunction, 123 uint32_t acParms, VBOXHGCMSVCPARM aParms[]) 124 : mHandle(aHandle), mFunction(aFunction), mcParms(acParms), 125 mParms(aParms) {} 126 }; 127 typedef std::vector <GuestCall> CallVector; 128 /** The list of outstanding guest notification calls */ 129 CallVector mGuestWaiters; 106 130 /** @todo we should have classes for thread and request handler thread */ 107 131 /** Queue of outstanding property change notifications */ … … 213 237 int delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest); 214 238 int enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 215 int getNotification(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 239 int getNotification(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, 240 VBOXHGCMSVCPARM paParms[], bool canWait); 216 241 void doNotifications(const char *pszProperty, uint64_t u64Timestamp); 217 242 static DECLCALLBACK(int) reqNotify(PFNHGCMSVCEXT pfnCallback, … … 748 773 * @param cParms the number of HGCM parameters supplied 749 774 * @param paParms the array of HGCM parameters 775 * @param canWait can this request be enqueued 750 776 * @thread HGCM 751 */ 752 int Service::getNotification(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 777 * @throws can throw std::bad_alloc if canWait==true 778 */ 779 int Service::getNotification(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, 780 VBOXHGCMSVCPARM paParms[], bool canWait) 753 781 { 754 782 int rc = VINF_SUCCESS; … … 817 845 818 846 /* 819 * Write out the data. 820 */ 821 paParms[0].setUInt64(u64Timestamp); 822 paParms[2].setUInt32(buffer.size()); 823 if (RT_SUCCESS(rc) && buffer.size() <= cchBuf) 824 buffer.copy(pchBuf, cchBuf); 847 * Write out the data or add the caller to the notification list if there 848 * is no notification available. 849 */ 850 if (RT_SUCCESS(rc) && u64Timestamp != 0) 851 { 852 paParms[0].setUInt64(u64Timestamp); 853 paParms[2].setUInt32(buffer.size()); 854 if (RT_SUCCESS(rc) && buffer.size() <= cchBuf) 855 buffer.copy(pchBuf, cchBuf); 856 else if (RT_SUCCESS(rc)) 857 rc = VERR_BUFFER_OVERFLOW; 858 if (RT_SUCCESS(rc) && warn) 859 rc = VWRN_NOT_FOUND; 860 } 861 else if (RT_SUCCESS(rc) && canWait) 862 { 863 mGuestWaiters.push_back(GuestCall(callHandle, GET_NOTIFICATION, cParms, 864 paParms)); 865 rc = VINF_HGCM_ASYNC_EXECUTE; 866 } 825 867 else if (RT_SUCCESS(rc)) 826 rc = VERR_BUFFER_OVERFLOW; 827 if (RT_SUCCESS(rc) && warn) 828 rc = VWRN_NOT_FOUND; 868 { 869 AssertFailed(); 870 rc = VERR_INTERNAL_ERROR; 871 } 829 872 return rc; 830 873 } … … 847 890 848 891 AssertPtrReturnVoid(pszProperty); 892 /* Ensure that our timestamp is different to the last one. */ 893 if ( !mGuestNotifications.empty() 894 && u64Timestamp == mGuestNotifications.back().mTimestamp) 895 ++u64Timestamp; 896 897 /* 898 * Try to find the property. 899 */ 849 900 PropertyList::const_iterator it; 850 901 bool found = false; … … 856 907 break; 857 908 } 909 858 910 /* 859 911 * First case: if the property exists then send its current value … … 874 926 (PFNRT)Service::reqNotify, 7, mpfnHostCallback, 875 927 mpvHostData, pszName, pszValue, 876 (uint32_t) RT_HIDWORD( it->mTimestamp),877 (uint32_t) RT_LODWORD( it->mTimestamp), pszFlags);928 (uint32_t) RT_HIDWORD(u64Timestamp), 929 (uint32_t) RT_LODWORD(u64Timestamp), pszFlags); 878 930 #endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */ 879 931 } 880 932 if (found) 881 933 { 882 /* Add the change to the queue for guest notifications */ 934 /* Add the change to the queue for guest notifications and release 935 * waiters */ 883 936 if (RT_SUCCESS(rc)) 884 937 { … … 886 939 { 887 940 mGuestNotifications.push_back(*it); 941 while (mGuestWaiters.size() > 0) 942 { 943 GuestCall call = mGuestWaiters.back(); 944 int rc2 = getNotification(call.mHandle, call.mcParms, 945 call.mParms, false); 946 mpHelpers->pfnCallComplete (call.mHandle, rc2); 947 mGuestWaiters.pop_back(); 948 } 888 949 } 889 950 catch (std::bad_alloc) … … 980 1041 { 981 1042 int rc = VINF_SUCCESS; 982 bool fCallSync = true;983 984 1043 LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n", 985 1044 u32ClientID, eFunction, cParms, paParms)); … … 1022 1081 case GET_NOTIFICATION: 1023 1082 LogFlowFunc(("GET_NOTIFICATION\n")); 1024 rc = getNotification(c Parms, paParms);1083 rc = getNotification(callHandle, cParms, paParms, true); 1025 1084 break; 1026 1085 … … 1033 1092 rc = VERR_NO_MEMORY; 1034 1093 } 1035 if (fCallSync)1036 {1037 LogFlowFunc(("rc = %Rrc\n", rc));1094 LogFlowFunc(("rc = %Rrc\n", rc)); 1095 if (rc != VINF_HGCM_ASYNC_EXECUTE) 1096 { 1038 1097 mpHelpers->pfnCallComplete (callHandle, rc); 1039 1098 } … … 1176 1235 ptable->pfnCall = Service::svcCall; 1177 1236 ptable->pfnHostCall = Service::svcHostCall; 1178 ptable->pfnSaveState = NULL; /* The service is stateless by definition, so the*/1179 ptable->pfnLoadState = NULL; /* normalconstruction done before restoring suffices */1237 ptable->pfnSaveState = NULL; /* The service is stateless, so the normal */ 1238 ptable->pfnLoadState = NULL; /* construction done before restoring suffices */ 1180 1239 ptable->pfnRegisterExtension = Service::svcRegisterExtension; 1181 1240 -
trunk/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp
r13916 r13971 735 735 } 736 736 737 /* Test when no new events are available */738 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL,739 GET_NOTIFICATION, 3, paParms);740 if ( RT_FAILURE(callHandle.rc)741 || RT_FAILURE(paParms[0].getUInt64 (&u64Timestamp))742 || u64Timestamp != 0743 )744 {745 RTPrintf("Failed to signal properly that no new notifications are available.\n");746 rc = VERR_UNRESOLVED_ERROR;747 }748 749 737 /* Test a query with an unknown timestamp */ 750 738 paParms[0].setUInt64 (1); … … 775 763 * @note prints its own diagnostic information to stdout. 776 764 */ 777 int testNoNotifications(VBOXHGCMSVCFNTABLE *pTable) 765 int testNoNotifications(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMCALLHANDLE_TYPEDEF *callHandle, 766 VBOXHGCMSVCPARM *paParms, char *pchBuffer, size_t cchBuffer) 778 767 { 779 768 int rc = VINF_SUCCESS; 780 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS }; 781 char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN]; 782 783 RTPrintf("Testing the GET_NOTIFICATION call when no notifications are available.\n"); 769 770 RTPrintf("Testing the asynchronous GET_NOTIFICATION call with no notifications are available.\n"); 784 771 uint64_t u64Timestamp = 0; 785 772 uint32_t u32Size = 0; 786 VBOXHGCMSVCPARM paParms[3];787 773 788 774 paParms[0].setUInt64 (u64Timestamp); 789 paParms[1].setPointer ((void *) chBuffer, sizeof(chBuffer)); 790 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, 775 paParms[1].setPointer ((void *) pchBuffer, cchBuffer); 776 callHandle->rc = VINF_HGCM_ASYNC_EXECUTE; 777 pTable->pfnCall(pTable->pvService, callHandle, 0, NULL, 791 778 GET_NOTIFICATION, 3, paParms); 792 if ( RT_FAILURE(callHandle.rc) 793 || RT_FAILURE(paParms[0].getUInt64 (&u64Timestamp)) 794 || u64Timestamp != 0 795 ) 796 { 797 RTPrintf("Failed to signal properly that no new notifications are available.\n"); 779 if (callHandle->rc != VINF_HGCM_ASYNC_EXECUTE) 780 { 781 RTPrintf("GET_NOTIFICATION call completed when new notifications should be available.\n"); 798 782 rc = VERR_UNRESOLVED_ERROR; 799 783 } … … 805 789 VBOXHGCMSVCFNTABLE svcTable; 806 790 VBOXHGCMSVCHELPERS svcHelpers; 791 /* Paramters for the asynchronous guest notification call */ 792 VBOXHGCMSVCPARM aParm[3]; 793 char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN]; 794 VBOXHGCMCALLHANDLE_TYPEDEF callHandleStruct; 795 807 796 initTable(&svcTable, &svcHelpers); 808 797 RTR3Init(); … … 819 808 if (RT_FAILURE(testEnumPropsHost(&svcTable))) 820 809 return 1; 821 if (RT_FAILURE(testNoNotifications(&svcTable))) 810 /* Asynchronous notification call */ 811 if (RT_FAILURE(testNoNotifications(&svcTable, &callHandleStruct, aParm, 812 chBuffer, sizeof(chBuffer)))) 822 813 return 1; 823 814 if (RT_FAILURE(testSetProp(&svcTable))) 824 815 return 1; 816 RTPrintf("Checking the data returned by the asynchronous notification call.\n"); 817 /* Our previous notification call should have completed by now. */ 818 uint64_t u64Timestamp; 819 uint32_t u32Size; 820 if ( callHandleStruct.rc != VINF_SUCCESS 821 || RT_FAILURE(aParm[0].getUInt64 (&u64Timestamp)) 822 || RT_FAILURE(aParm[2].getUInt32 (&u32Size)) 823 || u32Size != getNotifications[0].cchBuffer 824 || memcmp(chBuffer, getNotifications[0].pchBuffer, u32Size) != 0 825 ) 826 { 827 RTPrintf("Asynchronous GET_NOTIFICATION call did not complete as expected, rc=%Rrc\n", 828 callHandleStruct.rc); 829 return 1; 830 } 825 831 if (RT_FAILURE(testDelProp(&svcTable))) 826 832 return 1;
Note:
See TracChangeset
for help on using the changeset viewer.