VirtualBox

Changeset 46649 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Jun 19, 2013 11:47:32 AM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
86538
Message:

Forward ported r85941 and required build fixes (Main: Implemented new event queue to separate system's native event queue and our own. Also, XPCOM is not needed for handling our own events. On Windows this also fixes the system's queue quota limitation).

Location:
trunk
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/VBox

  • trunk/src/VBox/Main/Makefile.kmk

    r46474 r46649  
    736736        glue/AutoLock.cpp \
    737737        glue/EventQueue.cpp \
     738        glue/NativeEventQueue.cpp \
    738739        glue/ErrorInfo.cpp \
    739740        glue/errorprint.cpp
  • trunk/src/VBox/Main/glue/EventQueue.cpp

    r43944 r46649  
    11/* $Id$ */
    22/** @file
    3  * MS COM / XPCOM Abstraction Layer:
    4  * Event and EventQueue class declaration
     3 * Event queue class declaration.
    54 */
    65
    76/*
    8  * Copyright (C) 2006-2012 Oracle Corporation
     7 * Copyright (C) 2013 Oracle Corporation
    98 *
    109 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1716 */
    1817
     18/** @todo Adapt / update documentation! */
     19
    1920#include "VBox/com/EventQueue.h"
    2021
    21 #ifdef RT_OS_DARWIN
    22 # include <CoreFoundation/CFRunLoop.h>
    23 #endif
    24 
    25 #if defined(VBOX_WITH_XPCOM) && !defined(RT_OS_DARWIN) && !defined(RT_OS_OS2)
    26 # define USE_XPCOM_QUEUE
    27 #endif
    28 
     22#include <iprt/asm.h>
    2923#include <new> /* For bad_alloc. */
    3024
    3125#include <iprt/err.h>
     26#include <iprt/semaphore.h>
    3227#include <iprt/time.h>
    3328#include <iprt/thread.h>
    3429#include <iprt/log.h>
    35 #ifdef USE_XPCOM_QUEUE
    36 # include <errno.h>
    37 #endif
    3830
    3931namespace com
     
    4335////////////////////////////////////////////////////////////////////////////////
    4436
    45 #ifndef VBOX_WITH_XPCOM
    46 
    47 # define CHECK_THREAD_RET(ret) \
    48     do { \
    49         AssertMsg(GetCurrentThreadId() == mThreadId, ("Must be on event queue thread!")); \
    50         if (GetCurrentThreadId() != mThreadId) \
    51             return ret; \
    52     } while (0)
    53 
    54 /** Magic LPARAM value for the WM_USER messages that we're posting.
    55  * @remarks This magic value is duplicated in
    56  *          vboxapi/PlatformMSCOM::interruptWaitEvents(). */
    57 #define EVENTQUEUE_WIN_LPARAM_MAGIC   UINT32_C(0xf241b819)
    58 
    59 
    60 #else // VBOX_WITH_XPCOM
    61 
    62 # define CHECK_THREAD_RET(ret) \
    63     do { \
    64         if (!mEventQ) \
    65             return ret; \
    66         BOOL isOnCurrentThread = FALSE; \
    67         mEventQ->IsOnCurrentThread(&isOnCurrentThread); \
    68         AssertMsg(isOnCurrentThread, ("Must be on event queue thread!")); \
    69         if (!isOnCurrentThread) \
    70             return ret; \
    71     } while (0)
    72 
    73 #endif // VBOX_WITH_XPCOM
    74 
    75 /** Pointer to the main event queue. */
    76 EventQueue *EventQueue::sMainQueue = NULL;
    77 
    78 
    79 #ifdef VBOX_WITH_XPCOM
    80 
    81 struct MyPLEvent : public PLEvent
    82 {
    83     MyPLEvent(Event *e) : event(e) {}
    84     Event *event;
    85 };
    86 
    87 /* static */
    88 void *PR_CALLBACK com::EventQueue::plEventHandler(PLEvent *self)
    89 {
    90     Event *ev = ((MyPLEvent *)self)->event;
    91     if (ev)
    92         ev->handler();
    93     else
    94     {
    95         EventQueue *eq = (EventQueue *)self->owner;
    96         Assert(eq);
    97         eq->mInterrupted = true;
    98     }
    99     return NULL;
    100 }
    101 
    102 /* static */
    103 void PR_CALLBACK com::EventQueue::plEventDestructor(PLEvent *self)
    104 {
    105     Event *ev = ((MyPLEvent *)self)->event;
    106     if (ev)
    107         delete ev;
    108     delete self;
    109 }
    110 
    111 #endif // VBOX_WITH_XPCOM
    112 
    113 /**
    114  *  Constructs an event queue for the current thread.
    115  *
    116  *  Currently, there can be only one event queue per thread, so if an event
    117  *  queue for the current thread already exists, this object is simply attached
    118  *  to the existing event queue.
    119  */
    120 EventQueue::EventQueue()
    121 {
    122     /** @todo r=andy This constructor does way too much. In case of failure
    123      *               it's up to the caller to verify all sorts of stuff. Why
    124      *               isn't this done in init() and moving the main queue
    125      *               creation/deletion stuff to a dedicated function? */
    126 #ifndef VBOX_WITH_XPCOM
    127 
    128     mThreadId = GetCurrentThreadId();
    129     // force the system to create the message queue for the current thread
    130     MSG msg;
    131     PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
    132 
    133     if (!DuplicateHandle(GetCurrentProcess(),
    134                          GetCurrentThread(),
    135                          GetCurrentProcess(),
    136                          &mhThread,
    137                          0 /*dwDesiredAccess*/,
    138                          FALSE /*bInheritHandle*/,
    139                          DUPLICATE_SAME_ACCESS))
    140       mhThread = INVALID_HANDLE_VALUE;
    141 
    142 #else // VBOX_WITH_XPCOM
    143 
    144     mEQCreated = false;
    145     mInterrupted = false;
    146 
    147     // Here we reference the global nsIEventQueueService instance and hold it
    148     // until we're destroyed. This is necessary to keep NS_ShutdownXPCOM() away
    149     // from calling StopAcceptingEvents() on all event queues upon destruction of
    150     // nsIEventQueueService, and makes sense when, for some reason, this happens
    151     // *before* we're able to send a NULL event to stop our event handler thread
    152     // when doing unexpected cleanup caused indirectly by NS_ShutdownXPCOM()
    153     // that is performing a global cleanup of everything. A good example of such
    154     // situation is when NS_ShutdownXPCOM() is called while the VirtualBox component
    155     // is still alive (because it is still referenced): eventually, it results in
    156     // a VirtualBox::uninit() call from where it is already not possible to post
    157     // NULL to the event thread (because it stopped accepting events).
    158 
    159     nsresult rc = NS_GetEventQueueService(getter_AddRefs(mEventQService));
    160 
    161     if (NS_SUCCEEDED(rc))
    162     {
    163         rc = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD,
    164                                                  getter_AddRefs(mEventQ));
    165         if (rc == NS_ERROR_NOT_AVAILABLE)
    166         {
    167             rc = mEventQService->CreateThreadEventQueue();
    168             if (NS_SUCCEEDED(rc))
    169             {
    170                 mEQCreated = true;
    171                 rc = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD,
    172                                                          getter_AddRefs(mEventQ));
    173             }
    174         }
    175     }
    176     AssertComRC(rc);
    177 
    178 #endif // VBOX_WITH_XPCOM
    179 }
    180 
    181 EventQueue::~EventQueue()
    182 {
    183 #ifndef VBOX_WITH_XPCOM
    184     if (mhThread != INVALID_HANDLE_VALUE)
    185     {
    186         CloseHandle(mhThread);
    187         mhThread = INVALID_HANDLE_VALUE;
    188     }
    189 #else // VBOX_WITH_XPCOM
    190     // process all pending events before destruction
    191     if (mEventQ)
    192     {
    193         if (mEQCreated)
    194         {
    195             mEventQ->StopAcceptingEvents();
    196             mEventQ->ProcessPendingEvents();
    197             mEventQService->DestroyThreadEventQueue();
    198         }
    199         mEventQ = nsnull;
    200         mEventQService = nsnull;
    201     }
    202 #endif // VBOX_WITH_XPCOM
    203 }
    204 
    205 /**
    206  *  Initializes the main event queue instance.
    207  *  @returns VBox status code.
    208  *
    209  *  @remarks If you're using the rest of the COM/XPCOM glue library,
    210  *           com::Initialize() will take care of initializing and uninitializing
    211  *           the EventQueue class.  If you don't call com::Initialize, you must
    212  *           make sure to call this method on the same thread that did the
    213  *           XPCOM initialization or we'll end up using the wrong main queue.
    214  */
    215 /* static */
    216 int EventQueue::init()
    217 {
    218     Assert(sMainQueue == NULL);
    219     Assert(RTThreadIsMain(RTThreadSelf()));
    220 
    221     try
    222     {
    223         sMainQueue = new EventQueue();
    224 
    225 #ifdef VBOX_WITH_XPCOM
    226         /* Check that it actually is the main event queue, i.e. that
    227            we're called on the right thread. */
    228         nsCOMPtr<nsIEventQueue> q;
    229         nsresult rv = NS_GetMainEventQ(getter_AddRefs(q));
    230         Assert(NS_SUCCEEDED(rv));
    231         Assert(q == sMainQueue->mEventQ);
    232 
    233         /* Check that it's a native queue. */
    234         PRBool fIsNative = PR_FALSE;
    235         rv = sMainQueue->mEventQ->IsQueueNative(&fIsNative);
    236         Assert(NS_SUCCEEDED(rv) && fIsNative);
    237 #endif // VBOX_WITH_XPCOM
    238     }
    239     catch (std::bad_alloc &)
    240     {
    241         return VERR_NO_MEMORY;
    242     }
    243 
    244     return VINF_SUCCESS;
    245 }
    246 
    247 /**
    248  *  Uninitialize the global resources (i.e. the main event queue instance).
    249  *  @returns VINF_SUCCESS
    250  */
    251 /* static */
    252 int EventQueue::uninit()
    253 {
    254     if (sMainQueue)
    255     {
    256         /* Must process all events to make sure that no NULL event is left
    257          * after this point. It would need to modify the state of sMainQueue. */
    258 #ifdef RT_OS_DARWIN /* Do not process the native runloop, the toolkit may not be ready for it. */
    259         sMainQueue->mEventQ->ProcessPendingEvents();
    260 #else
    261         sMainQueue->processEventQueue(0);
    262 #endif
    263         delete sMainQueue;
    264         sMainQueue = NULL;
    265     }
    266     return VINF_SUCCESS;
    267 }
    268 
    269 /**
    270  *  Get main event queue instance.
    271  *
    272  *  Depends on init() being called first.
    273  */
    274 /* static */
    275 EventQueue* EventQueue::getMainEventQueue()
    276 {
    277     return sMainQueue;
    278 }
    279 
    280 #ifdef VBOX_WITH_XPCOM
    281 # ifdef RT_OS_DARWIN
    282 /**
    283  * Wait for events and process them (Darwin).
    284  *
    285  * @retval  VINF_SUCCESS
    286  * @retval  VERR_TIMEOUT
    287  * @retval  VERR_INTERRUPTED
    288  *
    289  * @param   cMsTimeout      How long to wait, or RT_INDEFINITE_WAIT.
    290  */
    291 static int waitForEventsOnDarwin(RTMSINTERVAL cMsTimeout)
    292 {
    293     /*
    294      * Wait for the requested time, if we get a hit we do a poll to process
    295      * any other pending messages.
    296      *
    297      * Note! About 1.0e10: According to the sources anything above 3.1556952e+9
    298      *       means indefinite wait and 1.0e10 is what CFRunLoopRun() uses.
    299      */
    300     CFTimeInterval rdTimeout = cMsTimeout == RT_INDEFINITE_WAIT ? 1e10 : (double)cMsTimeout / 1000;
    301     OSStatus orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, rdTimeout, true /*returnAfterSourceHandled*/);
    302     if (orc == kCFRunLoopRunHandledSource)
    303     {
    304         OSStatus orc2 = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/);
    305         if (   orc2 == kCFRunLoopRunStopped
    306             || orc2 == kCFRunLoopRunFinished)
    307             orc = orc2;
    308     }
    309     if (   orc == 0 /*???*/
    310         || orc == kCFRunLoopRunHandledSource)
    311         return VINF_SUCCESS;
    312     if (   orc == kCFRunLoopRunStopped
    313         || orc == kCFRunLoopRunFinished)
    314         return VERR_INTERRUPTED;
    315     AssertMsg(orc == kCFRunLoopRunTimedOut, ("Unexpected status code from CFRunLoopRunInMode: %#x", orc));
    316     return VERR_TIMEOUT;
    317 }
    318 # else // !RT_OS_DARWIN
    319 
    320 /**
    321  * Wait for events (generic XPCOM).
    322  *
    323  * @retval  VINF_SUCCESS
    324  * @retval  VERR_TIMEOUT
    325  * @retval  VINF_INTERRUPTED
    326  * @retval  VERR_INTERNAL_ERROR_4
    327  *
    328  * @param   pQueue          The queue to wait on.
    329  * @param   cMsTimeout      How long to wait, or RT_INDEFINITE_WAIT.
    330  */
    331 static int waitForEventsOnXPCOM(nsIEventQueue *pQueue, RTMSINTERVAL cMsTimeout)
    332 {
    333     int     fd = pQueue->GetEventQueueSelectFD();
    334     fd_set  fdsetR;
    335     FD_ZERO(&fdsetR);
    336     FD_SET(fd, &fdsetR);
    337 
    338     fd_set  fdsetE = fdsetR;
    339 
    340     struct timeval  tv = {0,0};
    341     struct timeval *ptv;
    342     if (cMsTimeout == RT_INDEFINITE_WAIT)
    343         ptv = NULL;
    344     else
    345     {
    346         tv.tv_sec  = cMsTimeout / 1000;
    347         tv.tv_usec = (cMsTimeout % 1000) * 1000;
    348         ptv = &tv;
    349     }
    350 
    351     int rc = select(fd + 1, &fdsetR, NULL, &fdsetE, ptv);
    352     if (rc > 0)
    353         rc = VINF_SUCCESS;
    354     else if (rc == 0)
    355         rc = VERR_TIMEOUT;
    356     else if (errno == EINTR)
    357         rc = VINF_INTERRUPTED;
    358     else
    359     {
    360         static uint32_t s_ErrorCount = 0;
    361         if (s_ErrorCount < 500)
    362         {
    363             LogRel(("waitForEventsOnXPCOM rc=%d errno=%d\n", rc, errno));
    364             ++s_ErrorCount;
    365         }
    366 
    367         AssertMsgFailed(("rc=%d errno=%d\n", rc, errno));
    368         rc = VERR_INTERNAL_ERROR_4;
    369     }
    370     return rc;
    371 }
    372 
    373 # endif // !RT_OS_DARWIN
    374 #endif // VBOX_WITH_XPCOM
    375 
    376 #ifndef VBOX_WITH_XPCOM
    377 
    378 /**
    379  * Dispatch a message on Windows.
    380  *
    381  * This will pick out our events and handle them specially.
    382  *
    383  * @returns @a rc or VERR_INTERRUPTED (WM_QUIT or NULL msg).
    384  * @param   pMsg    The message to dispatch.
    385  * @param   rc      The current status code.
    386  */
    387 /*static*/
    388 int EventQueue::dispatchMessageOnWindows(MSG const *pMsg, int rc)
    389 {
    390     /*
    391      * Check for and dispatch our events.
    392      */
    393     if (   pMsg->hwnd    == NULL
    394         && pMsg->message == WM_USER)
    395     {
    396         if (pMsg->lParam == EVENTQUEUE_WIN_LPARAM_MAGIC)
    397         {
    398             Event *pEvent = (Event *)pMsg->wParam;
    399             if (pEvent)
    400             {
    401                 pEvent->handler();
    402                 delete pEvent;
    403             }
    404             else
    405                 rc = VERR_INTERRUPTED;
    406             return rc;
    407         }
    408         AssertMsgFailed(("lParam=%p wParam=%p\n", pMsg->lParam, pMsg->wParam));
    409     }
    410 
    411     /*
    412      * Check for the quit message and dispatch the message the normal way.
    413      */
    414     if (pMsg->message == WM_QUIT)
    415         rc = VERR_INTERRUPTED;
    416     TranslateMessage(pMsg);
    417     DispatchMessage(pMsg);
    418 
    419     return rc;
    420 }
    421 
    422 
    423 /**
    424  * Process pending events (Windows).
    425  *
    426  * @retval  VINF_SUCCESS
    427  * @retval  VERR_TIMEOUT
    428  * @retval  VERR_INTERRUPTED.
    429  */
    430 static int processPendingEvents(void)
    431 {
    432     int rc = VERR_TIMEOUT;
    433     MSG Msg;
    434     if (PeekMessage(&Msg, NULL /*hWnd*/, 0 /*wMsgFilterMin*/, 0 /*wMsgFilterMax*/, PM_REMOVE))
    435     {
    436         rc = VINF_SUCCESS;
    437         do
    438             rc = EventQueue::dispatchMessageOnWindows(&Msg, rc);
    439         while (PeekMessage(&Msg, NULL /*hWnd*/, 0 /*wMsgFilterMin*/, 0 /*wMsgFilterMax*/, PM_REMOVE));
    440     }
    441     return rc;
    442 }
    443 
    444 #else // VBOX_WITH_XPCOM
    445 
    446 /**
    447  * Process pending XPCOM events.
    448  * @param pQueue The queue to process events on.
    449  * @retval  VINF_SUCCESS
    450  * @retval  VERR_TIMEOUT
    451  * @retval  VERR_INTERRUPTED (darwin only)
    452  * @retval  VERR_INTERNAL_ERROR_2
    453  */
    454 static int processPendingEvents(nsIEventQueue *pQueue)
    455 {
    456     /* ProcessPendingEvents doesn't report back what it did, so check here. */
    457     PRBool fHasEvents = PR_FALSE;
    458     nsresult hr = pQueue->PendingEvents(&fHasEvents);
    459     if (NS_FAILED(hr))
    460         return VERR_INTERNAL_ERROR_2;
    461 
    462     /* Process pending events. */
    463     int rc = VINF_SUCCESS;
    464     if (fHasEvents)
    465         pQueue->ProcessPendingEvents();
    466     else
    467         rc = VERR_TIMEOUT;
    468 
    469 # ifdef RT_OS_DARWIN
    470     /* Process pending native events. */
    471     int rc2 = waitForEventsOnDarwin(0);
    472     if (rc == VERR_TIMEOUT || rc2 == VERR_INTERRUPTED)
    473         rc = rc2;
    474 # endif
    475 
    476     return rc;
    477 }
    478 
    479 #endif // VBOX_WITH_XPCOM
     37EventQueue::EventQueue(void)
     38    : mShutdown(false)
     39{
     40    int rc = RTCritSectInit(&mCritSect);
     41    AssertRC(rc);
     42
     43    rc = RTSemEventCreate(&mSemEvent);
     44    AssertRC(rc);
     45}
     46
     47EventQueue::~EventQueue(void)
     48{
     49    int rc = RTCritSectDelete(&mCritSect);
     50    AssertRC(rc);
     51
     52    rc = RTSemEventDestroy(mSemEvent);
     53    AssertRC(rc);
     54
     55    EventQueueListIterator it  = mEvents.begin();
     56    while (it != mEvents.end())
     57    {
     58        (*it)->Release();
     59        it = mEvents.erase(it);
     60            }
     61}
    48062
    48163/**
     
    50486int EventQueue::processEventQueue(RTMSINTERVAL cMsTimeout)
    50587{
    506     int rc;
    507     CHECK_THREAD_RET(VERR_INVALID_CONTEXT);
    508 
    509 #ifdef VBOX_WITH_XPCOM
    510     /*
    511      * Process pending events, if none are available and we're not in a
    512      * poll call, wait for some to appear.  (We have to be a little bit
    513      * careful after waiting for the events since Darwin will process
    514      * them as part of the wait, while the XPCOM case will not.)
    515      *
    516      * Note! Unfortunately, WaitForEvent isn't interruptible with Ctrl-C,
    517      *       while select() is.  So we cannot use it for indefinite waits.
    518      */
    519     rc = processPendingEvents(mEventQ);
    520     if (    rc == VERR_TIMEOUT
    521         &&  cMsTimeout > 0)
    522     {
    523 # ifdef RT_OS_DARWIN
    524         /** @todo check how Ctrl-C works on Darwin. */
    525         rc = waitForEventsOnDarwin(cMsTimeout);
    526         if (rc == VERR_TIMEOUT)
    527             rc = processPendingEvents(mEventQ);
    528 # else // !RT_OS_DARWIN
    529         rc = waitForEventsOnXPCOM(mEventQ, cMsTimeout);
    530         if (    RT_SUCCESS(rc)
    531             ||  rc == VERR_TIMEOUT)
    532             rc = processPendingEvents(mEventQ);
    533 # endif // !RT_OS_DARWIN
    534     }
    535 
    536     if (  (   RT_SUCCESS(rc)
    537            || rc == VERR_INTERRUPTED
    538            || rc == VERR_TIMEOUT)
    539         && mInterrupted)
    540     {
    541         mInterrupted = false;
    542         rc = VERR_INTERRUPTED;
    543     }
    544 
    545 #else // !VBOX_WITH_XPCOM
    546     if (cMsTimeout == RT_INDEFINITE_WAIT)
    547     {
    548         BOOL fRet;
    549         MSG  Msg;
    550         rc = VINF_SUCCESS;
    551         while (   rc != VERR_INTERRUPTED
    552                && (fRet = GetMessage(&Msg, NULL /*hWnd*/, WM_USER, WM_USER))
    553                && fRet != -1)
    554             rc = EventQueue::dispatchMessageOnWindows(&Msg, rc);
    555         if (fRet == 0)
    556             rc = VERR_INTERRUPTED;
    557         else if (fRet == -1)
    558             rc = RTErrConvertFromWin32(GetLastError());
     88    bool fWait;
     89    int rc = RTCritSectEnter(&mCritSect);
     90    if (RT_SUCCESS(rc))
     91    {
     92        fWait = mEvents.size() == 0;
     93        if (!fWait)
     94        {
     95            int rc2 = RTCritSectLeave(&mCritSect);
     96            AssertRC(rc2);
     97    }
     98    }
     99
     100    if (fWait)
     101    {
     102        int rc2 = RTCritSectLeave(&mCritSect);
     103        AssertRC(rc2);
     104
     105        rc = RTSemEventWaitNoResume(mSemEvent, cMsTimeout);
     106    }
     107
     108    if (RT_SUCCESS(rc))
     109    {
     110        if (ASMAtomicReadBool(&mShutdown))
     111            return VERR_INTERRUPTED;
     112
     113        if (fWait)
     114            rc = RTCritSectEnter(&mCritSect);
     115        if (RT_SUCCESS(rc))
     116        {
     117            EventQueueListIterator it = mEvents.begin();
     118            if (it != mEvents.end())
     119            {
     120                Event *pEvent = *it;
     121                AssertPtr(pEvent);
     122
     123                mEvents.erase(it);
     124
     125                int rc2 = RTCritSectLeave(&mCritSect);
     126                if (RT_SUCCESS(rc))
     127                    rc = rc2;
     128
     129                pEvent->handler();
     130                pEvent->Release();
    559131    }
    560132    else
    561133    {
    562         rc = processPendingEvents();
    563         if (   rc == VERR_TIMEOUT
    564             && cMsTimeout != 0)
    565         {
    566             DWORD rcW = MsgWaitForMultipleObjects(1,
    567                                                   &mhThread,
    568                                                   TRUE /*fWaitAll*/,
    569                                                   cMsTimeout,
    570                                                   QS_ALLINPUT);
    571             AssertMsgReturn(rcW == WAIT_TIMEOUT || rcW == WAIT_OBJECT_0,
    572                             ("%d\n", rcW),
    573                             VERR_INTERNAL_ERROR_4);
    574             rc = processPendingEvents();
    575         }
    576     }
    577 #endif // !VBOX_WITH_XPCOM
     134                int rc2 = RTCritSectLeave(&mCritSect);
     135                if (RT_SUCCESS(rc))
     136                    rc = rc2;
     137        }
     138    }
     139    }
    578140
    579141    Assert(rc != VERR_TIMEOUT || cMsTimeout != RT_INDEFINITE_WAIT);
     
    588150 * @returns VBox status code.
    589151 */
    590 int EventQueue::interruptEventQueueProcessing()
    591 {
    592     /* Send a NULL event. This event will be picked up and handled specially
    593      * both for XPCOM and Windows.  It is the responsibility of the caller to
    594      * take care of not running the loop again in a way which will hang. */
    595     postEvent(NULL);
    596     return VINF_SUCCESS;
     152int EventQueue::interruptEventQueueProcessing(void)
     153{
     154    ASMAtomicWriteBool(&mShutdown, true);
     155
     156    return RTSemEventSignal(mSemEvent);
    597157}
    598158
     
    605165BOOL EventQueue::postEvent(Event *pEvent)
    606166{
    607 #ifndef VBOX_WITH_XPCOM
    608     /* Note! The event == NULL case is duplicated in vboxapi/PlatformMSCOM::interruptWaitEvents(). */
    609     return PostThreadMessage(mThreadId, WM_USER, (WPARAM)pEvent, EVENTQUEUE_WIN_LPARAM_MAGIC);
    610 
    611 #else // VBOX_WITH_XPCOM
    612 
    613     if (!mEventQ)
    614         return FALSE;
    615 
    616     try
    617     {
    618         MyPLEvent *pMyEvent = new MyPLEvent(pEvent);
    619         mEventQ->InitEvent(pMyEvent, this, com::EventQueue::plEventHandler,
    620                            com::EventQueue::plEventDestructor);
    621         HRESULT rc = mEventQ->PostEvent(pMyEvent);
    622         return NS_SUCCEEDED(rc);
    623     }
    624     catch (std::bad_alloc &ba)
    625     {
    626         AssertMsgFailed(("Out of memory while allocating memory for event=%p: %s\n",
    627                          pEvent, ba.what()));
    628     }
    629 
    630     return FALSE;
    631 #endif // VBOX_WITH_XPCOM
    632 }
    633 
    634 
    635 /**
    636  *  Get select()'able selector for this event queue.
    637  *  This will return -1 on platforms and queue variants not supporting such
    638  *  functionality.
    639  */
    640 int EventQueue::getSelectFD()
    641 {
    642 #ifdef VBOX_WITH_XPCOM
    643     return mEventQ->GetEventQueueSelectFD();
    644 #else
    645     return -1;
    646 #endif
     167    int rc = RTCritSectEnter(&mCritSect);
     168    if (RT_SUCCESS(rc))
     169    {
     170       try
     171        {
     172            if (pEvent)
     173            {
     174                pEvent->AddRef();
     175                mEvents.push_back(pEvent);
     176            }
     177            else /* No locking, since we're already in our crit sect. */
     178                mShutdown = true;
     179
     180            size_t cEvents = mEvents.size();
     181            if (cEvents > _1K) /** @todo Make value configurable? */
     182            {
     183                static int s_cBitchedAboutLotEvents = 0;
     184                if (s_cBitchedAboutLotEvents < 10)
     185                    LogRel(("Warning: Event queue received lots of events (%zu), expect delayed event handling (%d/10)\n",
     186                            cEvents, ++s_cBitchedAboutLotEvents));
     187            }
     188
     189            /* Leave critical section before signalling event. */
     190            rc = RTCritSectLeave(&mCritSect);
     191            if (RT_SUCCESS(rc))
     192            {
     193                int rc2 = RTSemEventSignal(mSemEvent);
     194                AssertRC(rc2);
     195            }
     196        }
     197        catch (std::bad_alloc &ba)
     198        {
     199            NOREF(ba);
     200            rc = VERR_NO_MEMORY;
     201        }
     202
     203        if (RT_FAILURE(rc))
     204        {
     205            int rc2 = RTCritSectLeave(&mCritSect);
     206            AssertRC(rc2);
     207        }
     208    }
     209
     210    return RT_SUCCESS(rc) ? TRUE : FALSE;
    647211}
    648212
  • trunk/src/VBox/Main/glue/initterm.cpp

    r44528 r46649  
    66
    77/*
    8  * Copyright (C) 2006-2012 Oracle Corporation
     8 * Copyright (C) 2006-2013 Oracle Corporation
    99 *
    1010 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    4949#include "VBox/com/com.h"
    5050#include "VBox/com/assert.h"
    51 #include "VBox/com/EventQueue.h"
     51#include "VBox/com/NativeEventQueue.h"
    5252#include "VBox/com/AutoLock.h"
    5353
     
    499499     */
    500500    if (SUCCEEDED(rc))
    501         EventQueue::init();
     501        NativeEventQueue::init();
    502502
    503503    return rc;
     
    517517        if (-- gCOMMainInitCount == 0)
    518518        {
    519             EventQueue::uninit();
     519            NativeEventQueue::uninit();
    520520            ASMAtomicWriteHandle(&gCOMMainThread, NIL_RTTHREAD);
    521521        }
     
    556556            if (--gXPCOMInitCount == 0)
    557557            {
    558                 EventQueue::uninit();
     558                MainEventQueue::uninit();
    559559                rc = NS_ShutdownXPCOM(nsnull);
    560560
  • trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp

    r45356 r46649  
    53565356    AssertReturn(pvUser, VERR_INVALID_POINTER);
    53575357
    5358     com::Initialize();
    5359 
    5360     // create an event queue for the current thread
    5361     EventQueue *eventQ = new EventQueue();
    5362     AssertReturn(eventQ, VERR_NO_MEMORY);
    5363 
    5364     // return the queue to the one who created this thread
    5365     *(static_cast <EventQueue **>(pvUser)) = eventQ;
    5366     // signal that we're ready
    5367     RTThreadUserSignal(thread);
    5368 
    5369     /*
    5370      * In case of spurious wakeups causing VERR_TIMEOUTs and/or other return codes
    5371      * we must not stop processing events and delete the "eventQ" object. This must
    5372      * be done ONLY when we stop this loop via interruptEventQueueProcessing().
    5373      * See @bugref{5724}.
    5374      */
    5375     while (eventQ->processEventQueue(RT_INDEFINITE_WAIT) != VERR_INTERRUPTED)
    5376         /* nothing */ ;
    5377 
    5378     delete eventQ;
     5358    HRESULT hr = com::Initialize();
     5359    if (FAILED(hr))
     5360        return VERR_COM_UNEXPECTED;
     5361
     5362    int rc = VINF_SUCCESS;
     5363
     5364    try
     5365    {
     5366        /* Create an event queue for the current thread. */
     5367        EventQueue *pEventQueue = new EventQueue();
     5368        AssertPtr(pEventQueue);
     5369
     5370        /* Return the queue to the one who created this thread. */
     5371        *(static_cast <EventQueue **>(pvUser)) = pEventQueue;
     5372
     5373        /* signal that we're ready. */
     5374        RTThreadUserSignal(thread);
     5375
     5376        /*
     5377         * In case of spurious wakeups causing VERR_TIMEOUTs and/or other return codes
     5378         * we must not stop processing events and delete the pEventQueue object. This must
     5379         * be done ONLY when we stop this loop via interruptEventQueueProcessing().
     5380         * See @bugref{5724}.
     5381         */
     5382        while (pEventQueue->processEventQueue(RT_INDEFINITE_WAIT) != VERR_INTERRUPTED)
     5383            /* nothing */ ;
     5384
     5385        delete pEventQueue;
     5386    }
     5387    catch (std::bad_alloc &ba)
     5388    {
     5389        rc = VERR_NO_MEMORY;
     5390        NOREF(ba);
     5391    }
    53795392
    53805393    com::Shutdown();
    53815394
    5382 
    5383     LogFlowFuncLeave();
    5384 
    5385     return 0;
     5395    LogFlowFuncLeaveRC(rc);
     5396    return rc;
    53865397}
    53875398
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