VirtualBox

Changeset 22722 in vbox


Ignore:
Timestamp:
Sep 2, 2009 3:05:57 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
51848
Message:

VBoxCOM,VBoxManage,WebService: Event queue fun.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/com/EventQueue.h

    r8155 r22722  
    9090    BOOL waitForEvent (Event **event);
    9191    BOOL handleEvent (Event *event);
     92    static int processThreadEventQueue(uint32_t cMsTimeout, bool (*pfnExitCheck)(void *pvUser) = 0,
     93                                       void *pvUser = 0, uint32_t cMsPollInterval = 1000,
     94                                       bool fReturnOnEvent = true);
    9295
    9396private:
  • trunk/include/iprt/err.h

    r22492 r22722  
    599599/** Invalid Base64 encoding. */
    600600#define VERR_INVALID_BASE64_ENCODING        (-87)
     601/** Return instigated by a callback or similar. */
     602#define VERR_CALLBACK_RETURN                (-88)
     603/** Return instigated by a callback or similar. */
     604#define VINF_CALLBACK_RETURN                88
    601605/** @} */
    602606
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp

    r22693 r22722  
    419419
    420420/**
     421 * Callback for processThreadEventQueue.
     422 *
     423 * @param   pvUser  Pointer to the callback object.
     424 *
     425 * @returns true if it should return or false if it should continue waiting for
     426 *          events.
     427 */
     428static bool eventExitCheck(void *pvUser)
     429{
     430    GuestPropertyCallback const *pCallbacks = (GuestPropertyCallback const *)pvUser;
     431    return pCallbacks->Signalled();
     432}
     433
     434/**
    421435 * Enumerates the properties in the guest property store.
    422436 *
     
    469483     * Set up the callback and wait.
    470484     *
     485     *
    471486     * The waiting is done is 1 sec at the time since there there are races
    472487     * between the callback and us going to sleep.  This also guards against
     
    485500    a->virtualBox->RegisterCallback(callback);
    486501
    487 #ifdef USE_XPCOM_QUEUE
    488     int const       fdQueue   = a->eventQ->GetEventQueueSelectFD();
    489 #endif
    490     uint64_t const  StartMsTS = RTTimeMilliTS();
    491     for (;;)
    492     {
    493 #ifdef VBOX_WITH_XPCOM
    494         /* Process pending XPCOM events. */
    495         a->eventQ->ProcessPendingEvents();
    496 #endif
    497 
    498         /* Signalled? */
    499         if (cbImpl->Signalled())
    500             break;
    501 
    502         /* Figure out how much we have left to wait and if we've timed out already. */
    503         uint32_t cMsLeft;
    504         if (cMsTimeout == RT_INDEFINITE_WAIT)
    505             cMsLeft = RT_INDEFINITE_WAIT;
    506         else
    507         {
    508             uint64_t cMsElapsed = RTTimeMilliTS() - StartMsTS;
    509             if (cMsElapsed >= cMsTimeout)
    510                 break; /* timeout */
    511             cMsLeft = cMsTimeout - (uint32_t)cMsElapsed;
    512         }
    513 
    514         /* Wait in a platform specific manner. */
    515 #define POLL_MS_INTERVAL    1000
    516 #ifdef USE_XPCOM_QUEUE
    517         fd_set fdset;
    518         FD_ZERO(&fdset);
    519         FD_SET(fdQueue, &fdset);
    520         struct timeval tv;
    521         if (    cMsLeft == RT_INDEFINITE_WAIT
    522             ||  cMsLeft >= POLL_MS_INTERVAL)
    523         {
    524             tv.tv_sec = POLL_MS_INTERVAL / 1000;
    525             tv.tv_usec = 0;
    526         }
    527         else
    528         {
    529             tv.tv_sec = 0;
    530             tv.tv_usec = cMsLeft * 1000;
    531         }
    532         int prc = select(fdQueue + 1, &fdset, NULL, NULL, &tv);
    533         if (prc == -1)
    534         {
    535             RTPrintf("Error waiting for event: %s (%d)\n", strerror(errno), errno);
    536             break;
    537         }
    538 
    539 #elif defined(RT_OS_DARWIN)
    540         CFTimeInterval rdTimeout = (double)RT_MIN(cMsLeft, POLL_MS_INTERVAL) / 1000;
    541         OSStatus orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, rdTimeout, true /*returnAfterSourceHandled*/);
    542         if (orc == kCFRunLoopRunHandledSource)
    543             orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/);
    544         if (   orc != 0
    545             && orc != kCFRunLoopRunHandledSource
    546             && orc != kCFRunLoopRunTimedOut)
    547         {
    548             RTPrintf("Error waiting for event: %d\n", orc);
    549             break;
    550         }
    551 
    552 #else  /* !USE_XPCOM_QUEUE */
    553         int vrc = cbImpl->wait(RT_MIN(cMsLeft, POLL_MS_INTERVAL));
    554         if (    vrc != VERR_TIMEOUT
    555             &&  RT_FAILURE(vrc))
    556         {
    557             RTPrintf("Error waiting for event: %Rrc\n", vrc);
    558             break;
    559         }
    560 #endif /* !USE_XPCOM_QUEUE */
    561     } /* for (;;) */
    562 
    563     /*
    564      * Clean up the callback and report timeout.
    565      */
     502    int vrc = com::EventQueue::processThreadEventQueue(cMsTimeout, eventExitCheck, (void *)cbImpl,
     503                                                       1000 /*cMsPollInterval*/, false /*fReturnOnEvent*/);
     504    if (   RT_FAILURE(vrc)
     505        && vrc != VERR_CALLBACK_RETURN
     506        && vrc != VERR_TIMEOUT)
     507    {
     508        RTPrintf("Error waiting for event: %Rrc\n", vrc);
     509        return 1;
     510    }
     511
    566512    a->virtualBox->UnregisterCallback(callback);
    567513
  • trunk/src/VBox/Main/glue/EventQueue.cpp

    r21878 r22722  
    2424
    2525#include "VBox/com/EventQueue.h"
     26
     27#ifdef RT_OS_DARWIN
     28# include <CoreFoundation/CFRunLoop.h>
     29#endif
     30
     31#if defined(VBOX_WITH_XPCOM) && !defined(RT_OS_DARWIN) && !defined(RT_OS_OS2)
     32# define USE_XPCOM_QUEUE
     33#endif
     34
     35#include <iprt/err.h>
     36#include <iprt/time.h>
     37#include <iprt/thread.h>
     38#ifdef USE_XPCOM_QUEUE
     39# include <errno.h>
     40#endif
    2641
    2742namespace com
     
    246261}
    247262
    248 } /* namespace com */
    249 
     263
     264#ifdef VBOX_WITH_XPCOM
     265
     266/** Wrapper around nsIEventQueue::PendingEvents. */
     267DECLINLINE(bool) hasEventQueuePendingEvents(nsIEventQueue *pQueue)
     268{
     269    PRBool fHasEvents = PR_FALSE;
     270    nsresult rc = pQueue->PendingEvents(&fHasEvents);
     271    return NS_SUCCEEDED(rc) && fHasEvents ? true : false;
     272}
     273
     274/** Wrapper around nsIEventQueue::IsQueueNative. */
     275DECLINLINE(bool) isEventQueueNative(nsIEventQueue *pQueue)
     276{
     277    PRBool fIsNative = PR_FALSE;
     278    nsresult rc = pQueue->IsQueueNative(&fIsNative);
     279    return NS_SUCCEEDED(rc) && fIsNative ? true : false;
     280}
     281
     282/** Wrapper around nsIEventQueue::ProcessPendingEvents. */
     283DECLINLINE(void) processPendingEvents(nsIEventQueue *pQueue)
     284{
     285    pQueue->ProcessPendingEvents();
     286}
     287
     288#else
     289
     290/** For automatic cleanup.  */
     291class MyThreadHandle
     292{
     293public:
     294    HANDLE mh;
     295
     296    MyThreadHandle(HANDLE hThread)
     297    {
     298        if (!DuplicateHandle(GetCurrentProcess(), hThread, GetCurrentProcess(),
     299                             &mh, 0 /*dwDesiredAccess*/, FALSE /*bInheritHandle*/,
     300                             DUPLICATE_SAME_ACCESS))
     301            mh = INVALID_HANDLE_VALUE;
     302    }
     303
     304    ~MyThreadHandle()
     305    {
     306        CloseHandle(mh);
     307        mh = INVALID_HANDLE_VALUE;
     308    }
     309};
     310
     311/** COM version of nsIEventQueue::PendingEvents. */
     312DECLINLINE(bool) hasEventQueuePendingEvents(MyThreadHandle &Handle)
     313{
     314    DWORD rc = MsgWaitForMultipleObjects(1, &Handle.mh, TRUE /*fWaitAll*/, 0 /*ms*/, QS_ALLINPUT);
     315    return rc == WAIT_OBJECT_0;
     316}
     317
     318/** COM version of nsIEventQueue::IsQueueNative, the question doesn't make
     319 *  sense and we have to return false for the code below to work. */
     320DECLINLINE(bool) isEventQueueNative(MyThreadHandle const &Handle)
     321{
     322    return false;
     323}
     324
     325/** COM version of nsIEventQueue::ProcessPendingEvents. */
     326static void processPendingEvents(MyThreadHandle const &Handle)
     327{
     328    /*
     329     * Process pending thead messages.
     330     */
     331    MSG Msg;
     332    while (PeekMessage(&Msg, NULL /*hWnd*/, 0 /*wMsgFilterMin*/, 0 /*wMsgFilterMax*/, PM_REMOVE))
     333    {
     334        if (Msg.message == WM_QUIT)
     335            return /*VERR_INTERRUPTED*/;
     336        DispatchMessage(&Msg);
     337    }
     338}
     339
     340#endif /* VBOX_WITH_XPCOM */
     341
     342/**
     343 *  Processes events for the current thread.
     344 *
     345 *  @param cMsTimeout       The timeout in milliseconds or RT_INDEFINITE_WAIT.
     346 *  @param pfnExitCheck     Optional callback for checking for some exit condition
     347 *                          while looping.  Note that this may be called
     348 *  @param pvUser           User argument for pfnExitCheck.
     349 *  @param cMsPollInterval  The interval cMsTimeout should be called at. 0 means
     350 *                          never default.
     351 *  @param fReturnOnEvent   If true, return immediately after some events has
     352 *                          been processed. If false, process events until we
     353 *                          time out, pfnExitCheck returns true, interrupted or
     354 *                          the queue receives some kind of quit message.
     355 *
     356 *  @returns VBox status code.
     357 *  @retval VINF_SUCCESS if events were processed.
     358 *  @retval VERR_TIMEOUT if no events before cMsTimeout elapsed.
     359 *  @retval VERR_INTERRUPTED if the wait was interrupted by a signal or other
     360 *          async event.
     361 *  @retval VERR_NOT_FOUND if the thread has no event queue.
     362 *  @retval VERR_CALLBACK_RETURN if the callback indicates return.
     363 *
     364 *  @todo This is just a quick approximation of what we need. Feel free to
     365 *        improve the interface and make it fit better in with the EventQueue
     366 *        class.
     367 */
     368/*static*/ int
     369EventQueue::processThreadEventQueue(uint32_t cMsTimeout, bool (*pfnExitCheck)(void *pvUser) /*= 0*/,
     370                                    void *pvUser /*= 0*/, uint32_t cMsPollInterval /*= 1000*/,
     371                                    bool fReturnOnEvent /*= true*/)
     372{
     373    uint64_t const StartMsTS = RTTimeMilliTS();
     374
     375    /* set default. */
     376    if (cMsPollInterval == 0)
     377        cMsPollInterval = 1000;
     378
     379    /*
     380     * Get the event queue / thread.
     381     */
     382#ifdef VBOX_WITH_XPCOM
     383    nsCOMPtr<nsIEventQueue> q;
     384    nsresult rv = NS_GetCurrentEventQ(getter_AddRefs(q));
     385    if (NS_FAILED(rv))
     386        return VERR_NOT_FOUND;
     387#else
     388    MyThreadHandle q(GetCurrentThread());
     389#endif
     390
     391    /*
     392     * Check for pending before setting up the wait.
     393     */
     394    if (    !hasEventQueuePendingEvents(q)
     395        ||  !fReturnOnEvent)
     396    {
     397        bool fIsNative = isEventQueueNative(q);
     398        if (    fIsNative
     399            ||  cMsTimeout != RT_INDEFINITE_WAIT
     400            ||  pfnExitCheck
     401            ||  !fReturnOnEvent /** @todo !fReturnOnEvent and cMsTimeout RT_INDEFINITE_WAIT can be handled in else */)
     402        {
     403#ifdef USE_XPCOM_QUEUE
     404            int const fdQueue = fIsNative ? q->GetEventQueueSelectFD() : -1;
     405            if (fIsNative && fdQueue == -1)
     406                return VERR_INTERNAL_ERROR_4;
     407#endif
     408            for (;;)
     409            {
     410                /*
     411                 * Check for events.
     412                 */
     413                if (hasEventQueuePendingEvents(q))
     414                {
     415                    if (fReturnOnEvent)
     416                        break;
     417                    processPendingEvents(q);
     418                }
     419
     420                /*
     421                 * Check the user exit.
     422                 */
     423                if (   pfnExitCheck
     424                    && pfnExitCheck(pvUser))
     425                    return VERR_CALLBACK_RETURN;
     426
     427                /*
     428                 * Figure out how much we have left to wait and if we've timed out already.
     429                 */
     430                uint32_t cMsLeft;
     431                if (cMsTimeout == RT_INDEFINITE_WAIT)
     432                    cMsLeft = RT_INDEFINITE_WAIT;
     433                else
     434                {
     435                    uint64_t cMsElapsed = RTTimeMilliTS() - StartMsTS;
     436                    if (cMsElapsed >= cMsTimeout)
     437                        break; /* timeout */
     438                    cMsLeft = cMsTimeout - (uint32_t)cMsElapsed;
     439                }
     440
     441                /*
     442                 * Wait in a queue & platform specific manner.
     443                 */
     444#ifdef VBOX_WITH_XPCOM
     445                if (!fIsNative)
     446                    RTThreadSleep(250 /*ms*/);
     447                else
     448                {
     449# ifdef USE_XPCOM_QUEUE
     450                    fd_set fdset;
     451                    FD_ZERO(&fdset);
     452                    FD_SET(fdQueue, &fdset);
     453                    struct timeval tv;
     454                    if (    cMsLeft == RT_INDEFINITE_WAIT
     455                        ||  cMsLeft >= cMsPollInterval)
     456                    {
     457                        tv.tv_sec = cMsPollInterval / 1000;
     458                        tv.tv_usec = (cMsPollInterval % 1000) * 1000;
     459                    }
     460                    else
     461                    {
     462                        tv.tv_sec = cMsLeft / 1000;
     463                        tv.tv_usec = (cMsLeft % 1000) * 1000;
     464                    }
     465                    int prc = select(fdQueue + 1, &fdset, NULL, NULL, &tv);
     466                    if (prc == -1)
     467                        return RTErrConvertFromErrno(errno);
     468
     469# elif defined(RT_OS_DARWIN)
     470                    CFTimeInterval rdTimeout = (double)RT_MIN(cMsLeft, cMsPollInterval) / 1000;
     471                    OSStatus orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, rdTimeout, true /*returnAfterSourceHandled*/);
     472                    if (orc == kCFRunLoopRunHandledSource)
     473                        orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/);
     474                    if (   orc != 0
     475                        && orc != kCFRunLoopRunHandledSource
     476                        && orc != kCFRunLoopRunTimedOut)
     477                        return orc == kCFRunLoopRunStopped || orc == kCFRunLoopRunFinished
     478                             ? VERR_INTERRUPTED
     479                             : RTErrConvertFromDarwin(orc);
     480# else
     481#  warning "PORTME:"
     482                    RTThreadSleep(250);
     483# endif
     484                }
     485
     486#else  /* !VBOX_WITH_XPCOM */
     487                DWORD rc = MsgWaitForMultipleObjects(1, &q.mh, TRUE /*fWaitAll*/, RT_MIN(cMsLeft, cMsPollInterval), QS_ALLINPUT);
     488                if (rc == WAIT_OBJECT_0)
     489                {
     490                    if (fReturnOnEvent)
     491                        break;
     492                    processPendingEvents(q);
     493                }
     494                else if (rc == WAIT_FAILED)
     495                    return RTErrConvertFromWin32(GetLastError());
     496                else if (rc != WAIT_TIMEOUT)
     497                    return VERR_INTERNAL_ERROR_4;
     498#endif /* !VBOX_WITH_XPCOM */
     499            } /* for (;;) */
     500        }
     501        else
     502        {
     503            /*
     504             * Indefinite wait without any complications.
     505             */
     506#ifdef VBOX_WITH_XPCOM
     507            PLEvent *pEvent = NULL;
     508            rv = q->WaitForEvent(&pEvent);
     509            if (NS_FAILED(rv))
     510                return VERR_INTERRUPTED;
     511            q->HandleEvent(pEvent);
     512#else
     513            DWORD rc = MsgWaitForMultipleObjects(1, &q.mh, TRUE /*fWaitAll*/, INFINITE, QS_ALLINPUT);
     514            if (rc != WAIT_OBJECT_0)
     515            {
     516                if (rc == WAIT_FAILED)
     517                    return RTErrConvertFromWin32(GetLastError());
     518                return VERR_INTERNAL_ERROR_3;
     519            }
     520#endif
     521        }
     522    }
     523
     524    /*
     525     * We have/had events in the queue. Process pending events and
     526     * return successfully.
     527     */
     528    processPendingEvents(q);
     529
     530    return VINF_SUCCESS;
     531}
     532
     533}
     534/* namespace com */
     535
  • trunk/src/VBox/Main/webservice/vboxweb.cpp

    r22708 r22722  
    462462            WebLog("Request served\n");
    463463
     464#if 0 /* Ulrich, try enable this and see if the leak goes away. */
     465{
     466 int vrc = com::EventQueue::processThreadEventQueue(0);
     467 WebLog("processThreadEventQueue -> %Rrc\n", vrc);
     468}
     469#endif
     470
    464471            soap_destroy(&soap); // clean up class instances
    465472            soap_end(&soap); // clean up everything and close socket
Note: See TracChangeset for help on using the changeset viewer.

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