VirtualBox

Changeset 22687 in vbox for trunk/src/libs


Ignore:
Timestamp:
Sep 2, 2009 12:25:29 AM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
51800
Message:

VBoxPython/darwin: Re-implemented PyXPCOMMethod_WaitForEvents for darwin.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/libs/xpcom18a4/python/src/module/_xpcom.cpp

    r22394 r22687  
    496496static nsIEventQueue* g_mainEventQ = nsnull;
    497497
    498 static PyObject*
     498# ifdef RT_OS_DARWIN
     499#  include <iprt/time.h>
     500#  include <iprt/thread.h>
     501#  include <iprt/err.h>
     502#  include <CarbonEvents.h>
     503
     504// Wrapper that checks if the queue has pending events.
     505DECLINLINE(bool)
     506hasEventQueuePendingEvents(nsIEventQueue *pQueue)
     507{
     508        PRBool fHasEvents = PR_FALSE;
     509        nsresult rc = pQueue->PendingEvents(&fHasEvents);
     510        return NS_SUCCEEDED(rc) && fHasEvents ? true : false;
     511}
     512
     513// Wrapper that checks if the queue has pending events.
     514DECLINLINE(bool)
     515isEventQueueNative(nsIEventQueue *pQueue)
     516{
     517        PRBool fIsNative = PR_FALSE;
     518        nsresult rc = pQueue->IsQueueNative(&fIsNative);
     519        return NS_SUCCEEDED(rc) && fIsNative ? true : false;
     520}
     521
     522
     523// Common fallback for waiting (and maybe processing) events. Caller process
     524// any pending events when 0 is returned.
     525static nsresult
     526waitForEventsCommonFallback(nsIEventQueue *pQueue, PRInt32 cMsTimeout)
     527{
     528        if (cMsTimeout < 0) {
     529                // WaitForEvent probably does the trick here.
     530                PLEvent *pEvent = NULL;
     531                nsresult rc = -1;
     532                Py_BEGIN_ALLOW_THREADS;
     533                rc = pQueue->WaitForEvent(&pEvent);
     534                Py_END_ALLOW_THREADS;
     535                if (NS_SUCCEEDED(rc)) {
     536                        pQueue->HandleEvent(pEvent);
     537                        return 0;
     538                }
     539        } else {
     540                // Poll until time out or event is encountered. We have
     541                // no other choice here.
     542                uint64_t const StartMillTS = RTTimeMilliTS();
     543                for (;;)
     544                {
     545                        // Any pending events?
     546                        if (hasEventQueuePendingEvents(pQueue))
     547                                return 0;
     548
     549                        // Work any native per-thread event loops for good measure.
     550#  ifdef RT_OS_DARWIN
     551                        RunCurrentEventLoop(0.0005 /*sec*/);
     552#  endif
     553
     554                        // Any pending events?
     555                        if (hasEventQueuePendingEvents(pQueue))
     556                                return 0;
     557
     558                        // Timed out?
     559                        uint64_t cMsElapsed = RTTimeMilliTS() - StartMillTS;
     560                        if (cMsElapsed > (uint32_t)cMsTimeout)
     561                                break;
     562
     563                        // Sleep a bit; return 0 if interrupt (see the select code edition).
     564                        uint32_t cMsLeft = (uint32_t)cMsTimeout - (uint32_t)cMsElapsed;
     565                        int rc = RTThreadSleep(RT_MIN(cMsLeft, 250));
     566                        if (rc == VERR_INTERRUPTED)
     567                                return 0;
     568                }
     569        }
     570
     571        return 1;
     572}
     573
     574
     575// Takes care of the waiting on darwin. Caller process any pending events when
     576// 0 is returned.
     577static nsresult
     578waitForEventsOnDarwin(nsIEventQueue *pQueue, PRInt32 cMsTimeout)
     579{
     580        // This deals with the common case where the caller is the main
     581        // application thread and the queue is a native one.
     582        if (    isEventQueueNative(pQueue)
     583            &&  GetCurrentEventLoop() == GetMainEventLoop()
     584        ) {
     585                OSStatus     orc       = -1;
     586                EventTimeout rdTimeout = cMsTimeout < 0
     587                                       ? kEventDurationForever
     588                                       : (double)cMsTimeout / 1000;
     589                Py_BEGIN_ALLOW_THREADS;
     590                orc = RunCurrentEventLoop(rdTimeout);
     591                Py_END_ALLOW_THREADS;
     592                if (!orc || orc == eventLoopQuitErr)
     593                        return 0;
     594
     595                if (orc != eventLoopTimedOutErr) {
     596                        NS_WARNING("Unexpected status code from RunCurrentEventLoop");
     597                        RTThreadSleep(1); // throttle
     598                }
     599
     600                return hasEventQueuePendingEvents(pQueue) ? 0 : 1;
     601        }
     602
     603        // All native queus are driven by the main application loop... Use the
     604        // fallback for now.
     605        return waitForEventsCommonFallback(pQueue, cMsTimeout);
     606}
     607
     608# endif /* RT_OS_DARWIN */
     609
     610static PyObject*
    499611PyXPCOMMethod_WaitForEvents(PyObject *self, PyObject *args)
    500612{
     
    505617
    506618  nsIEventQueue* q = g_mainEventQ;
     619  if (q == nsnull)
     620    return NULL;
     621
     622  NS_WARN_IF_FALSE(isEventQueueNative(q), "The event queue must be native!");
     623
     624  PRInt32 result = 0;
     625# ifdef RT_OS_DARWIN
     626  if (aTimeout != 0 && !hasEventQueuePendingEvents(q))
     627    result = waitForEventsOnDarwin(q, aTimeout);
     628  if (result == 0)
     629    q->ProcessPendingEvents();
     630
     631# else  /* !RT_OS_DARWIN */
     632
    507633  PRBool hasEvents = PR_FALSE;
    508634  nsresult rc;
    509   PRInt32 fd, result = 0;
    510 
    511   if (q == nsnull)
    512     return NULL;
     635  PRInt32 fd;
    513636
    514637  if (aTimeout == 0)
     
    521644  if (hasEvents)
    522645    goto ok;
    523  
     646
    524647  fd = q->GetEventQueueSelectFD();
    525648  if (fd < 0 && aTimeout < 0)
     
    537660  /* Cannot perform timed wait otherwise */
    538661  if (fd < 0)
    539 #ifdef RT_OS_DARWIN
    540       /**
    541        * @todo: maybe need some way to implement timed wait on Darwin,
    542        *        just return immediately instead
    543        */
    544       goto ok;
    545 #else
    546662      return NULL;
    547 #endif
    548  
     663
    549664  {
    550665    fd_set fdsetR, fdsetE;
    551666    struct timeval tv;
    552    
     667
    553668    FD_ZERO(&fdsetR);
    554669    FD_SET(fd, &fdsetR);
     
    560675        tv.tv_usec = ((PRInt64)aTimeout % 1000) * 1000;
    561676      }
    562    
     677
    563678    /** @todo: What to do for XPCOM platforms w/o select() ? */
    564679    Py_BEGIN_ALLOW_THREADS;
     
    569684 ok:
    570685  q->ProcessPendingEvents();
     686# endif /* !RT_OS_DARWIN */
    571687
    572688  return PyInt_FromLong(result);
     
    583699}
    584700
    585 static PyObject* 
     701static PyObject*
    586702PyXPCOMMethod_InterruptWait(PyObject *self, PyObject *args)
    587703{
     
    610726static void deinitVBoxPython();
    611727
    612 static PyObject* 
     728static PyObject*
    613729PyXPCOMMethod_DeinitCOM(PyObject *self, PyObject *args)
    614730{
     
    621737static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
    622738
    623 static PyObject* 
     739static PyObject*
    624740PyXPCOMMethod_AttachThread(PyObject *self, PyObject *args)
    625741{
     
    653769}
    654770
    655 static PyObject* 
     771static PyObject*
    656772PyXPCOMMethod_DetachThread(PyObject *self, PyObject *args)
    657773{
     
    684800    return PyInt_FromLong(result);
    685801}
    686 #endif
     802
     803#endif /* VBOX */
    687804
    688805extern PYXPCOM_EXPORT PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args);
     
    863980}
    864981
    865 static 
     982static
    866983void deinitVBoxPython()
    867984{
    868985
    869986  if (g_mainEventQ)
    870     NS_RELEASE(g_mainEventQ); 
    871  
     987    NS_RELEASE(g_mainEventQ);
     988
    872989  com::Shutdown();
    873990}
    874 #endif
     991
     992#endif /* VBOX_PYXPCOM */
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