VirtualBox

Changeset 13971

Show
Ignore:
Timestamp:
11/07/08 17:07:57 (2 months ago)
Author:
vboxsync
Message:

HostServices/GuestProperties?: added blocking waits for notifications

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/include/VBox/HostServices/GuestPropertySvc.h

    r13928 r13971  
    431431 * On success, VINF_SUCCESS will be returned and the buffer will contain 
    432432 * 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
    434434 * If the last notification could not be found by timestamp, VWRN_NOT_FOUND 
    435435 * will be returned and the oldest available notification will be returned. 
    436  * if no timestamp is specified, the oldest available notification will be 
     436 * If no timestamp is specified, the oldest available notification will be 
    437437 * returned. 
    438438 * If the buffer supplied was not large enough to hold the notification, 
    439439 * VERR_BUFFER_OVERFLOW will be returned and the size parameter will contain 
    440440 * 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.  
    441446 */ 
    442447typedef struct _GetNotification 
     
    452457     * 
    453458     * 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. 
    456460     */ 
    457461    HGCMFunctionParameter timestamp; 
    458462 
    459463    /** 
    460      * The returned data. if any will be placed here.  (OUT pointer) 
     464     * The returned data, if any, will be placed here.  (OUT pointer) 
    461465     * This call returns three null-terminated strings which will be placed 
    462466     * one after another: name, value and flags.  For a delete notification, 
  • trunk/src/VBox/HostServices/GuestProperties/service.cpp

    r13922 r13971  
    6060#include <string> 
    6161#include <list> 
     62#include <vector> 
    6263 
    6364namespace guestProp { 
     
    104105    /** The list of property changes for guest notifications */ 
    105106    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; 
    106130    /** @todo we should have classes for thread and request handler thread */ 
    107131    /** Queue of outstanding property change notifications */ 
     
    213237    int delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest); 
    214238    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); 
    216241    void doNotifications(const char *pszProperty, uint64_t u64Timestamp); 
    217242    static DECLCALLBACK(int) reqNotify(PFNHGCMSVCEXT pfnCallback, 
     
    748773 * @param   cParms  the number of HGCM parameters supplied 
    749774 * @param   paParms the array of HGCM parameters 
     775 * @param   canWait can this request be enqueued 
    750776 * @thread  HGCM 
    751  */ 
    752 int Service::getNotification(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 
     777 * @throws  can throw std::bad_alloc if canWait==true 
     778 */ 
     779int Service::getNotification(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, 
     780                             VBOXHGCMSVCPARM paParms[], bool canWait) 
    753781{ 
    754782    int rc = VINF_SUCCESS; 
     
    817845 
    818846    /* 
    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    } 
    825867    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    } 
    829872    return rc; 
    830873} 
     
    847890 
    848891    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     */ 
    849900    PropertyList::const_iterator it; 
    850901    bool found = false; 
     
    856907                break; 
    857908            } 
     909 
    858910    /* 
    859911     * First case: if the property exists then send its current value 
     
    874926                             (PFNRT)Service::reqNotify, 7, mpfnHostCallback, 
    875927                             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); 
    878930#endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */ 
    879931    } 
    880932    if (found) 
    881933    { 
    882         /* Add the change to the queue for guest notifications */ 
     934        /* Add the change to the queue for guest notifications and release 
     935         * waiters */ 
    883936        if (RT_SUCCESS(rc)) 
    884937        { 
     
    886939            { 
    887940                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                } 
    888949            } 
    889950            catch (std::bad_alloc) 
     
    9801041{ 
    9811042    int rc = VINF_SUCCESS; 
    982     bool fCallSync = true; 
    983  
    9841043    LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n", 
    9851044                 u32ClientID, eFunction, cParms, paParms)); 
     
    10221081            case GET_NOTIFICATION: 
    10231082                LogFlowFunc(("GET_NOTIFICATION\n")); 
    1024                 rc = getNotification(cParms, paParms); 
     1083                rc = getNotification(callHandle, cParms, paParms, true); 
    10251084                break; 
    10261085 
     
    10331092        rc = VERR_NO_MEMORY; 
    10341093    } 
    1035     if (fCallSync) 
    1036     { 
    1037         LogFlowFunc(("rc = %Rrc\n", rc)); 
     1094    LogFlowFunc(("rc = %Rrc\n", rc)); 
     1095    if (rc != VINF_HGCM_ASYNC_EXECUTE) 
     1096    { 
    10381097        mpHelpers->pfnCallComplete (callHandle, rc); 
    10391098    } 
     
    11761235                ptable->pfnCall               = Service::svcCall; 
    11771236                ptable->pfnHostCall           = Service::svcHostCall; 
    1178                 ptable->pfnSaveState          = NULL;  /* The service is stateless by definition, so the */ 
    1179                 ptable->pfnLoadState          = NULL;  /* normal construction done before restoring suffices */ 
     1237                ptable->pfnSaveState          = NULL;  /* The service is stateless, so the normal */ 
     1238                ptable->pfnLoadState          = NULL;  /* construction done before restoring suffices */ 
    11801239                ptable->pfnRegisterExtension  = Service::svcRegisterExtension; 
    11811240 
  • trunk/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp

    r13916 r13971  
    735735    } 
    736736 
    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 != 0 
    743        ) 
    744     { 
    745         RTPrintf("Failed to signal properly that no new notifications are available.\n"); 
    746         rc = VERR_UNRESOLVED_ERROR; 
    747     } 
    748  
    749737    /* Test a query with an unknown timestamp */ 
    750738    paParms[0].setUInt64 (1); 
     
    775763 * @note    prints its own diagnostic information to stdout. 
    776764 */ 
    777 int testNoNotifications(VBOXHGCMSVCFNTABLE *pTable) 
     765int testNoNotifications(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMCALLHANDLE_TYPEDEF *callHandle, 
     766                        VBOXHGCMSVCPARM *paParms, char *pchBuffer, size_t cchBuffer) 
    778767{ 
    779768    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"); 
    784771    uint64_t u64Timestamp = 0; 
    785772    uint32_t u32Size = 0; 
    786     VBOXHGCMSVCPARM paParms[3]; 
    787773 
    788774    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, 
    791778                    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"); 
    798782        rc = VERR_UNRESOLVED_ERROR; 
    799783    } 
     
    805789    VBOXHGCMSVCFNTABLE svcTable; 
    806790    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 
    807796    initTable(&svcTable, &svcHelpers); 
    808797    RTR3Init(); 
     
    819808    if (RT_FAILURE(testEnumPropsHost(&svcTable))) 
    820809        return 1; 
    821     if (RT_FAILURE(testNoNotifications(&svcTable))) 
     810    /* Asynchronous notification call */ 
     811    if (RT_FAILURE(testNoNotifications(&svcTable, &callHandleStruct, aParm, 
     812                   chBuffer, sizeof(chBuffer)))) 
    822813        return 1; 
    823814    if (RT_FAILURE(testSetProp(&svcTable))) 
    824815        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    } 
    825831    if (RT_FAILURE(testDelProp(&svcTable))) 
    826832        return 1; 

© 2008 Sun Microsystems, Inc.
ContactPrivacy policy