VirtualBox

Changeset 22847 in vbox for trunk/src/libs/xpcom18a4/python


Ignore:
Timestamp:
Sep 8, 2009 8:37:54 PM (15 years ago)
Author:
vboxsync
Message:

Python, COM glue: event processing API

File:
1 edited

Legend:

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

    r22829 r22847  
    493493
    494494#ifdef VBOX
    495 //#define USE_EVENTQUEUE  1
    496 
    497 # ifdef USE_EVENTQUEUE
     495
    498496#  include <VBox/com/EventQueue.h>
    499497#  include <iprt/err.h>
    500 # else
    501 #  include <iprt/cdefs.h>
    502 # endif
    503 
    504 static nsIEventQueue* g_mainEventQ = nsnull;
    505 
    506 # ifndef USE_EVENTQUEUE /** @todo Make USE_EVENTQUEUE default. */
    507 // Wrapper that checks if the queue has pending events.
    508 DECLINLINE(bool)
    509 hasEventQueuePendingEvents(nsIEventQueue *pQueue)
    510 {
    511         PRBool fHasEvents = PR_FALSE;
    512         nsresult rc = pQueue->PendingEvents(&fHasEvents);
    513         return NS_SUCCEEDED(rc) && fHasEvents ? true : false;
    514 }
    515 
    516 // Wrapper that checks if the queue is native or not.
    517 DECLINLINE(bool)
    518 isEventQueueNative(nsIEventQueue *pQueue)
    519 {
    520         PRBool fIsNative = PR_FALSE;
    521         nsresult rc = pQueue->IsQueueNative(&fIsNative);
    522         return NS_SUCCEEDED(rc) && fIsNative ? true : false;
    523 }
    524 
    525 # ifdef RT_OS_DARWIN
    526 #  include <iprt/time.h>
    527 #  include <iprt/thread.h>
    528 #  include <iprt/err.h>
    529 #  include <CoreFoundation/CFRunLoop.h>
    530 #  if MAC_OS_X_VERSION_MAX_ALLOWED == 1040 /* ASSUMES this means we're using the 10.4 SDK. */
    531 #   include <CarbonEvents.h>
    532 #  endif
    533 
    534 // Common fallback for waiting (and maybe processing) events. Caller process
    535 // any pending events when 0 is returned.
    536 static nsresult
    537 waitForEventsCommonFallback(nsIEventQueue *pQueue, PRInt32 cMsTimeout)
    538 {
    539         if (cMsTimeout < 0) {
    540                 // WaitForEvent probably does the trick here.
    541                 PLEvent *pEvent = NULL;
    542                 nsresult rc = -1;
    543                 Py_BEGIN_ALLOW_THREADS;
    544                 rc = pQueue->WaitForEvent(&pEvent);
    545                 Py_END_ALLOW_THREADS;
    546                 if (NS_SUCCEEDED(rc)) {
    547                         pQueue->HandleEvent(pEvent);
    548                         return 0;
    549                 }
    550         } else {
    551                 // Poll until time out or event is encountered. We have
    552                 // no other choice here.
    553                 uint64_t const StartMillTS = RTTimeMilliTS();
    554                 for (;;)
    555                 {
    556                         // Any pending events?
    557                         if (hasEventQueuePendingEvents(pQueue))
    558                                 return 0;
    559 
    560                         // Work any native per-thread event loops for good measure.
    561 #  ifdef RT_OS_DARWIN
    562                         CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/);
    563 #  endif
    564 
    565                         // Any pending events?
    566                         if (hasEventQueuePendingEvents(pQueue))
    567                                 return 0;
    568 
    569                         // Timed out?
    570                         uint64_t cMsElapsed = RTTimeMilliTS() - StartMillTS;
    571                         if (cMsElapsed > (uint32_t)cMsTimeout)
    572                                 break;
    573 
    574                         // Sleep a bit; return 0 if interrupt (see the select code edition).
    575                         uint32_t cMsLeft = (uint32_t)cMsTimeout - (uint32_t)cMsElapsed;
    576                         int rc = RTThreadSleep(RT_MIN(cMsLeft, 250));
    577                         if (rc == VERR_INTERRUPTED)
    578                                 return 0;
    579                 }
    580         }
    581 
    582         return 1;
    583 }
    584 
    585 
    586 // Takes care of the waiting on darwin. Caller process any pending events when
    587 // 0 is returned.
    588 static nsresult
    589 waitForEventsOnDarwin(nsIEventQueue *pQueue, PRInt32 cMsTimeout)
    590 {
    591         // This deals with the common case where the caller is the main
    592         // application thread and the queue is a native one.
    593         if (    isEventQueueNative(pQueue)
    594 #  if MAC_OS_X_VERSION_MAX_ALLOWED == 1040 /* ASSUMES this means we're using the 10.4 SDK. */
    595             &&  GetCurrentEventLoop() == GetMainEventLoop()
    596 #  else
    597             &&  CFRunLoopGetMain() == CFRunLoopGetCurrent()
    598 #  endif
    599         ) {
    600                 OSStatus       orc       = -1;
    601                 CFTimeInterval rdTimeout = cMsTimeout < 0
    602                                          ? 1.0e10
    603                                          : (double)cMsTimeout / 1000;
    604                 Py_BEGIN_ALLOW_THREADS;
    605                 orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, rdTimeout, true /*returnAfterSourceHandled*/);
    606                 if (orc == kCFRunLoopRunHandledSource)
    607                     orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/);
    608                 Py_END_ALLOW_THREADS;
    609                 if (!orc || orc == kCFRunLoopRunHandledSource)
    610                         return 0;
    611 
    612                 if (orc != kCFRunLoopRunTimedOut) {
    613                         NS_WARNING("Unexpected status code from CFRunLoopRunInMode");
    614                         RTThreadSleep(1); // throttle
    615                 }
    616 
    617                 return hasEventQueuePendingEvents(pQueue) ? 0 : 1;
    618         }
    619 
    620         // All native queus are driven by the main application loop... Use the
    621         // fallback for now.
    622         return waitForEventsCommonFallback(pQueue, cMsTimeout);
    623 }
    624 
    625 # endif /* RT_OS_DARWIN */
    626 # endif /* !USE_EVENTQUEUE */
    627498
    628499static PyObject*
     
    634505    return NULL; /** @todo throw exception */
    635506
    636   nsIEventQueue* q = g_mainEventQ;
    637   if (q == nsnull)
    638     return NULL; /** @todo throw exception */
    639 
    640 # ifdef USE_EVENTQUEUE
    641507  int rc;
    642  
    643   Py_BEGIN_ALLOW_THREADS;
    644   rc = com::EventQueue::processThreadEventQueue(aTimeout < 0 ? RT_INDEFINITE_WAIT : (uint32_t)aTimeout);
    645   Py_END_ALLOW_THREADS;
    646  
     508  com::EventQueue* aEventQ = com::EventQueue::getMainEventQueue();
     509  NS_WARN_IF_FALSE(aEventQ != nsnull, "Null main event queue");
     510  if (!aEventQ)
     511      return NULL;
     512
     513  Py_BEGIN_ALLOW_THREADS
     514  rc = aEventQ->processEventQueue(aTimeout < 0 ? RT_INDEFINITE_WAIT : (uint32_t)aTimeout);
     515  Py_END_ALLOW_THREADS
    647516  if (RT_SUCCESS(rc))
    648517      return PyInt_FromLong(0);
     518
    649519  if (   rc == VERR_TIMEOUT
    650520      || rc == VERR_INTERRUPTED)
    651521      return PyInt_FromLong(1);
    652   return NULL; /** @todo throw exception */
    653 
    654 # else  /* !USE_EVENTQUEUE */
    655   NS_WARN_IF_FALSE(isEventQueueNative(q), "The event queue must be native!");
    656 
    657   PRInt32 result = 0;
    658 #  ifdef RT_OS_DARWIN
    659   if (aTimeout != 0 && !hasEventQueuePendingEvents(q))
    660     result = waitForEventsOnDarwin(q, aTimeout);
    661   if (result == 0)
    662     q->ProcessPendingEvents();
    663 
    664 #  else  /* !RT_OS_DARWIN */
    665 
    666   PRBool hasEvents = PR_FALSE;
    667   nsresult rc;
    668   PRInt32 fd;
    669 
    670   if (aTimeout == 0)
    671     goto ok;
    672 
    673   rc = q->PendingEvents(&hasEvents);
    674   if (NS_FAILED (rc))
    675     return NULL;
    676 
    677   if (hasEvents)
    678     goto ok;
    679 
    680   fd = q->GetEventQueueSelectFD();
    681   if (fd < 0 && aTimeout < 0)
    682   {
    683     /* fallback */
    684     PLEvent *pEvent = NULL;
    685     Py_BEGIN_ALLOW_THREADS
    686     rc = q->WaitForEvent(&pEvent);
    687     Py_END_ALLOW_THREADS
    688     if (NS_SUCCEEDED(rc))
    689       q->HandleEvent(pEvent);
    690     goto ok;
    691   }
    692 
    693   /* Cannot perform timed wait otherwise */
    694   if (fd < 0)
    695       return NULL;
    696 
    697   {
    698     fd_set fdsetR, fdsetE;
    699     struct timeval tv;
    700 
    701     FD_ZERO(&fdsetR);
    702     FD_SET(fd, &fdsetR);
    703 
    704     fdsetE = fdsetR;
    705     if (aTimeout > 0)
    706       {
    707         tv.tv_sec = (PRInt64)aTimeout / 1000;
    708         tv.tv_usec = ((PRInt64)aTimeout % 1000) * 1000;
    709       }
    710 
    711     /** @todo: What to do for XPCOM platforms w/o select() ? */
    712     Py_BEGIN_ALLOW_THREADS;
    713     int n = select(fd + 1, &fdsetR, NULL, &fdsetE, aTimeout < 0 ? NULL : &tv);
    714     result = (n == 0) ?  1 :  0;
    715     Py_END_ALLOW_THREADS;
    716   }
    717  ok:
    718   q->ProcessPendingEvents();
    719 #  endif /* !RT_OS_DARWIN */
    720   return PyInt_FromLong(result);
    721 # endif /* !USE_EVENTQUEUE */
    722 }
    723 
    724 PR_STATIC_CALLBACK(void *) PyHandleEvent(PLEvent *ev)
    725 {
    726   return nsnull;
    727 }
    728 
    729 PR_STATIC_CALLBACK(void) PyDestroyEvent(PLEvent *ev)
    730 {
    731   delete ev;
     522
     523  return NULL; /** @todo throw correct exception */
    732524}
    733525
     
    735527PyXPCOMMethod_InterruptWait(PyObject *self, PyObject *args)
    736528{
    737   nsIEventQueue* q = g_mainEventQ;
    738   PRInt32 result = 0;
    739   nsresult rc;
    740 
    741   PLEvent *ev = new PLEvent();
    742   if (!ev)
    743   {
    744     result = 1;
    745     goto done;
    746   }
    747   q->InitEvent (ev, NULL, PyHandleEvent, PyDestroyEvent);
    748   rc = q->PostEvent (ev);
    749   if (NS_FAILED(rc))
    750   {
    751     result = 2;
    752     goto done;
    753   }
    754 
    755  done:
    756   return PyInt_FromLong(result);
     529  com::EventQueue* aEventQ = com::EventQueue::getMainEventQueue();
     530  NS_WARN_IF_FALSE(aEventQ != nsnull, "Null main event queue");
     531  if (!aEventQ)
     532      return NULL;
     533
     534  aEventQ->interruptEventQueueProcessing();
     535
     536  return PyInt_FromLong(0);
    757537}
    758538
     
    1004784    rc = com::Initialize();
    1005785
    1006     if (NS_SUCCEEDED(rc))
    1007     {
    1008       NS_GetMainEventQ (&g_mainEventQ);
    1009     }
    1010 
    1011786    init_xpcom();
    1012787  }
     
    1016791void deinitVBoxPython()
    1017792{
    1018 
    1019   if (g_mainEventQ)
    1020     NS_RELEASE(g_mainEventQ);
    1021 
    1022793  com::Shutdown();
    1023794}
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