VirtualBox

Changeset 13971 in vbox


Ignore:
Timestamp:
Nov 7, 2008 4:07:57 PM (16 years ago)
Author:
vboxsync
Message:

HostServices/GuestProperties: added blocking waits for notifications

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • 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;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette