Changeset 22911 in vbox for trunk/src/VBox/Main/glue
- Timestamp:
- Sep 10, 2009 12:02:36 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 52173
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/glue/EventQueue.cpp
r22849 r22911 179 179 timedWaitForEventsOnDarwin(nsIEventQueue *pQueue, PRInt32 cMsTimeout) 180 180 { 181 // This deals with the common case where the caller is the main182 // application thread and the queue is a native one.183 181 OSStatus orc = -1; 184 182 CFTimeInterval rdTimeout = (double)cMsTimeout / 1000; … … 200 198 #ifdef RT_OS_WINDOWS 201 199 static int 202 processPendingEvents OnWindows()200 processPendingEvents() 203 201 { 204 202 MSG Msg; … … 211 209 if (rc == VERR_INTERRUPTED) 212 210 break; 213 rc = VINF_SUCCESS; 211 rc = VINF_SUCCESS; 214 212 } 215 213 return rc; … … 239 237 } 240 238 }; 241 #endif 242 #include <stdio.h> 239 #else 240 static int 241 processPendingEvents(nsIEventQueue* pQueue) 242 { 243 /** @todo: rethink interruption events, current NULL event approach is bad */ 244 pQueue->ProcessPendingEvents(); 245 return VINF_SUCCESS; 246 } 247 #endif 243 248 int EventQueue::processEventQueue(uint32_t cMsTimeout) 244 249 { 245 250 int rc = VINF_SUCCESS; 251 /** @todo: check that current thread == one we were created on */ 246 252 #if defined (VBOX_WITH_XPCOM) 247 253 do { … … 249 255 nsresult rc; 250 256 251 rc = mEventQ->PendingEvents(&fHasEvents); 257 rc = mEventQ->PendingEvents(&fHasEvents); 252 258 if (NS_FAILED (rc)) 253 259 return VERR_INTERNAL_ERROR_3; … … 305 311 } while (0); 306 312 307 mEventQ->ProcessPendingEvents();313 rc = processPendingEvents(mEventQ); 308 314 #else /* Windows */ 309 315 do { … … 342 348 } while (0); 343 349 344 processPendingEventsOnWindows();350 rc = processPendingEvents(); 345 351 #endif 346 352 return rc; 347 348 353 } 349 354 350 355 int EventQueue::interruptEventQueueProcessing() 351 356 { 357 /** @todo: rethink me! */ 352 358 postEvent(NULL); 353 359 return VINF_SUCCESS; … … 469 475 } 470 476 471 477 int EventQueue::getSelectFD() 478 { 472 479 #ifdef VBOX_WITH_XPCOM 473 474 /** Wrapper around nsIEventQueue::PendingEvents. */ 475 DECLINLINE(bool) hasEventQueuePendingEvents(nsIEventQueue *pQueue) 476 { 477 PRBool fHasEvents = PR_FALSE; 478 nsresult rc = pQueue->PendingEvents(&fHasEvents); 479 return NS_SUCCEEDED(rc) && fHasEvents ? true : false; 480 } 481 482 /** Wrapper around nsIEventQueue::IsQueueNative. */ 483 DECLINLINE(bool) isEventQueueNative(nsIEventQueue *pQueue) 484 { 485 PRBool fIsNative = PR_FALSE; 486 nsresult rc = pQueue->IsQueueNative(&fIsNative); 487 return NS_SUCCEEDED(rc) && fIsNative ? true : false; 488 } 489 490 /** Wrapper around nsIEventQueue::ProcessPendingEvents. */ 491 DECLINLINE(void) processPendingEvents(nsIEventQueue *pQueue) 492 { 493 pQueue->ProcessPendingEvents(); 494 } 495 496 #else 497 498 /** COM version of nsIEventQueue::PendingEvents. */ 499 DECLINLINE(bool) hasEventQueuePendingEvents(MyThreadHandle &Handle) 500 { 501 DWORD rc = MsgWaitForMultipleObjects(1, &Handle.mh, TRUE /*fWaitAll*/, 0 /*ms*/, QS_ALLINPUT); 502 return rc == WAIT_OBJECT_0; 503 } 504 505 /** COM version of nsIEventQueue::IsQueueNative, the question doesn't make 506 * sense and we have to return false for the code below to work. */ 507 DECLINLINE(bool) isEventQueueNative(MyThreadHandle const &Handle) 508 { 509 return false; 510 } 511 512 /** COM version of nsIEventQueue::ProcessPendingEvents. */ 513 static void processPendingEvents(MyThreadHandle const &Handle) 514 { 515 /* 516 * Process pending thead messages. 517 */ 518 MSG Msg; 519 while (PeekMessage(&Msg, NULL /*hWnd*/, 0 /*wMsgFilterMin*/, 0 /*wMsgFilterMax*/, PM_REMOVE)) 520 { 521 if (Msg.message == WM_QUIT) 522 return /*VERR_INTERRUPTED*/; 523 DispatchMessage(&Msg); 524 } 525 } 526 527 #endif /* VBOX_WITH_XPCOM */ 528 529 /** 530 * Processes events for the current thread. 531 * 532 * @param cMsTimeout The timeout in milliseconds or RT_INDEFINITE_WAIT. 533 * @param pfnExitCheck Optional callback for checking for some exit condition 534 * while looping. Note that this may be called 535 * @param pvUser User argument for pfnExitCheck. 536 * @param cMsPollInterval The interval cMsTimeout should be called at. 0 means 537 * never default. 538 * @param fReturnOnEvent If true, return immediately after some events has 539 * been processed. If false, process events until we 540 * time out, pfnExitCheck returns true, interrupted or 541 * the queue receives some kind of quit message. 542 * 543 * @returns VBox status code. 544 * @retval VINF_SUCCESS if events were processed. 545 * @retval VERR_TIMEOUT if no events before cMsTimeout elapsed. 546 * @retval VERR_INTERRUPTED if the wait was interrupted by a signal or other 547 * async event. 548 * @retval VERR_NOT_FOUND if the thread has no event queue. 549 * @retval VERR_CALLBACK_RETURN if the callback indicates return. 550 * 551 * @todo This is just a quick approximation of what we need. Feel free to 552 * improve the interface and make it fit better in with the EventQueue 553 * class. 554 */ 555 /*static*/ int 556 EventQueue::processThreadEventQueue(uint32_t cMsTimeout, bool (*pfnExitCheck)(void *pvUser) /*= 0*/, 557 void *pvUser /*= 0*/, uint32_t cMsPollInterval /*= 1000*/, 558 bool fReturnOnEvent /*= true*/) 559 { 560 uint64_t const StartMsTS = RTTimeMilliTS(); 561 562 /* set default. */ 563 if (cMsPollInterval == 0) 564 cMsPollInterval = 1000; 565 566 /* 567 * Get the event queue / thread. 568 */ 569 #ifdef VBOX_WITH_XPCOM 570 nsCOMPtr<nsIEventQueue> q; 571 nsresult rv = NS_GetCurrentEventQ(getter_AddRefs(q)); 572 if (NS_FAILED(rv)) 573 return VERR_NOT_FOUND; 574 #else 575 MyThreadHandle q; 576 #endif 577 578 /* 579 * Check for pending before setting up the wait. 580 */ 581 if ( !hasEventQueuePendingEvents(q) 582 || !fReturnOnEvent) 583 { 584 bool fIsNative = isEventQueueNative(q); 585 if ( fIsNative 586 || cMsTimeout != RT_INDEFINITE_WAIT 587 || pfnExitCheck 588 || !fReturnOnEvent /** @todo !fReturnOnEvent and cMsTimeout RT_INDEFINITE_WAIT can be handled in else */) 589 { 590 #ifdef USE_XPCOM_QUEUE 591 int const fdQueue = fIsNative ? q->GetEventQueueSelectFD() : -1; 592 if (fIsNative && fdQueue == -1) 593 return VERR_INTERNAL_ERROR_4; 594 #endif 595 for (;;) 596 { 597 /* 598 * Check for events. 599 */ 600 if (hasEventQueuePendingEvents(q)) 601 { 602 if (fReturnOnEvent) 603 break; 604 processPendingEvents(q); 605 } 606 607 /* 608 * Check the user exit. 609 */ 610 if ( pfnExitCheck 611 && pfnExitCheck(pvUser)) 612 return VERR_CALLBACK_RETURN; 613 614 /* 615 * Figure out how much we have left to wait and if we've timed out already. 616 */ 617 uint32_t cMsLeft; 618 if (cMsTimeout == RT_INDEFINITE_WAIT) 619 cMsLeft = RT_INDEFINITE_WAIT; 620 else 621 { 622 uint64_t cMsElapsed = RTTimeMilliTS() - StartMsTS; 623 if (cMsElapsed >= cMsTimeout) 624 break; /* timeout */ 625 cMsLeft = cMsTimeout - (uint32_t)cMsElapsed; 626 } 627 628 /* 629 * Wait in a queue & platform specific manner. 630 */ 631 #ifdef VBOX_WITH_XPCOM 632 if (!fIsNative) 633 RTThreadSleep(250 /*ms*/); 634 else 635 { 636 # ifdef USE_XPCOM_QUEUE 637 fd_set fdset; 638 FD_ZERO(&fdset); 639 FD_SET(fdQueue, &fdset); 640 struct timeval tv; 641 if ( cMsLeft == RT_INDEFINITE_WAIT 642 || cMsLeft >= cMsPollInterval) 643 { 644 tv.tv_sec = cMsPollInterval / 1000; 645 tv.tv_usec = (cMsPollInterval % 1000) * 1000; 646 } 647 else 648 { 649 tv.tv_sec = cMsLeft / 1000; 650 tv.tv_usec = (cMsLeft % 1000) * 1000; 651 } 652 int prc = select(fdQueue + 1, &fdset, NULL, NULL, &tv); 653 if (prc == -1) 654 return RTErrConvertFromErrno(errno); 655 656 # elif defined(RT_OS_DARWIN) 657 CFTimeInterval rdTimeout = (double)RT_MIN(cMsLeft, cMsPollInterval) / 1000; 658 OSStatus orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, rdTimeout, true /*returnAfterSourceHandled*/); 659 if (orc == kCFRunLoopRunHandledSource) 660 orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/); 661 if ( orc != 0 662 && orc != kCFRunLoopRunHandledSource 663 && orc != kCFRunLoopRunTimedOut) 664 return orc == kCFRunLoopRunStopped || orc == kCFRunLoopRunFinished 665 ? VERR_INTERRUPTED 666 : RTErrConvertFromDarwin(orc); 667 # else 668 # warning "PORTME:" 669 RTThreadSleep(250); 670 # endif 671 } 672 673 #else /* !VBOX_WITH_XPCOM */ 674 DWORD rc = MsgWaitForMultipleObjects(1, &q.mh, TRUE /*fWaitAll*/, RT_MIN(cMsLeft, cMsPollInterval), QS_ALLINPUT); 675 if (rc == WAIT_OBJECT_0) 676 { 677 if (fReturnOnEvent) 678 break; 679 processPendingEvents(q); 680 } 681 else if (rc == WAIT_FAILED) 682 return RTErrConvertFromWin32(GetLastError()); 683 else if (rc != WAIT_TIMEOUT) 684 return VERR_INTERNAL_ERROR_4; 685 #endif /* !VBOX_WITH_XPCOM */ 686 } /* for (;;) */ 687 } 688 else 689 { 690 /* 691 * Indefinite wait without any complications. 692 */ 693 #ifdef VBOX_WITH_XPCOM 694 PLEvent *pEvent = NULL; 695 rv = q->WaitForEvent(&pEvent); 696 if (NS_FAILED(rv)) 697 return VERR_INTERRUPTED; 698 q->HandleEvent(pEvent); 699 #else 700 DWORD rc = MsgWaitForMultipleObjects(1, &q.mh, TRUE /*fWaitAll*/, INFINITE, QS_ALLINPUT); 701 if (rc != WAIT_OBJECT_0) 702 { 703 if (rc == WAIT_FAILED) 704 return RTErrConvertFromWin32(GetLastError()); 705 return VERR_INTERNAL_ERROR_3; 706 } 707 #endif 708 } 709 } 710 711 /* 712 * We have/had events in the queue. Process pending events and 713 * return successfully. 714 */ 715 processPendingEvents(q); 716 717 return VINF_SUCCESS; 480 return mEventQ->GetEventQueueSelectFD(); 481 #else 482 return -1; 483 #endif 718 484 } 719 485 }
Note:
See TracChangeset
for help on using the changeset viewer.