Changeset 22722 in vbox for trunk/src/VBox/Main/glue
- Timestamp:
- Sep 2, 2009 3:05:57 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/glue/EventQueue.cpp
r21878 r22722 24 24 25 25 #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 26 41 27 42 namespace com … … 246 261 } 247 262 248 } /* namespace com */ 249 263 264 #ifdef VBOX_WITH_XPCOM 265 266 /** Wrapper around nsIEventQueue::PendingEvents. */ 267 DECLINLINE(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. */ 275 DECLINLINE(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. */ 283 DECLINLINE(void) processPendingEvents(nsIEventQueue *pQueue) 284 { 285 pQueue->ProcessPendingEvents(); 286 } 287 288 #else 289 290 /** For automatic cleanup. */ 291 class MyThreadHandle 292 { 293 public: 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. */ 312 DECLINLINE(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. */ 320 DECLINLINE(bool) isEventQueueNative(MyThreadHandle const &Handle) 321 { 322 return false; 323 } 324 325 /** COM version of nsIEventQueue::ProcessPendingEvents. */ 326 static 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 369 EventQueue::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
Note:
See TracChangeset
for help on using the changeset viewer.