Changeset 31579 in vbox for trunk/src/VBox/Main/glue
- Timestamp:
- Aug 11, 2010 5:21:27 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 64686
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/glue/EventQueue.cpp
r31371 r31579 8 8 9 9 /* 10 * Copyright (C) 2006-20 07Oracle Corporation10 * Copyright (C) 2006-2010 Oracle Corporation 11 11 * 12 12 * This file is part of VirtualBox Open Source Edition (OSE), as … … 42 42 //////////////////////////////////////////////////////////////////////////////// 43 43 44 #if defined (RT_OS_WINDOWS)44 #ifndef VBOX_WITH_XPCOM 45 45 46 46 #define CHECK_THREAD_RET(ret) \ 47 47 do { \ 48 AssertMsg 48 AssertMsg(GetCurrentThreadId() == mThreadId, ("Must be on event queue thread!")); \ 49 49 if (GetCurrentThreadId() != mThreadId) \ 50 50 return ret; \ 51 51 } while (0) 52 52 53 #else // !defined (RT_OS_WINDOWS)53 #else // VBOX_WITH_XPCOM 54 54 55 55 #define CHECK_THREAD_RET(ret) \ … … 58 58 return ret; \ 59 59 BOOL isOnCurrentThread = FALSE; \ 60 mEventQ->IsOnCurrentThread 61 AssertMsg 60 mEventQ->IsOnCurrentThread(&isOnCurrentThread); \ 61 AssertMsg(isOnCurrentThread, ("Must be on event queue thread!")); \ 62 62 if (!isOnCurrentThread) \ 63 63 return ret; \ 64 64 } while (0) 65 65 66 #endif // !defined (RT_OS_WINDOWS)66 #endif // VBOX_WITH_XPCOM 67 67 68 68 EventQueue *EventQueue::mMainQueue = NULL; 69 70 #ifdef VBOX_WITH_XPCOM 71 struct MyPLEvent : public PLEvent 72 { 73 MyPLEvent(Event *e) : event(e) {} 74 Event *event; 75 }; 76 77 /* static */ 78 void *PR_CALLBACK com::EventQueue::plEventHandler(PLEvent *self) 79 { 80 Event *ev = ((MyPLEvent *)self)->event; 81 if (ev) 82 ev->handler(); 83 else 84 { 85 EventQueue *eq = (EventQueue *)self->owner; 86 Assert(eq); 87 eq->mInterrupted = true; 88 } 89 return NULL; 90 } 91 92 /* static */ 93 void PR_CALLBACK com::EventQueue::plEventDestructor(PLEvent *self) 94 { 95 Event *ev = ((MyPLEvent *)self)->event; 96 if (ev) 97 delete ev; 98 delete self; 99 } 100 101 #endif // VBOX_WITH_XPCOM 69 102 70 103 /** … … 77 110 EventQueue::EventQueue() 78 111 { 79 #if defined (RT_OS_WINDOWS)112 #ifndef VBOX_WITH_XPCOM 80 113 81 114 mThreadId = GetCurrentThreadId(); 82 115 // force the system to create the message queue for the current thread 83 116 MSG msg; 84 PeekMessage 85 86 if (!DuplicateHandle 87 88 89 90 91 92 117 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); 118 119 if (!DuplicateHandle(GetCurrentProcess(), 120 GetCurrentThread(), 121 GetCurrentProcess(), 122 &mhThread, 123 0 /*dwDesiredAccess*/, 124 FALSE /*bInheritHandle*/, 125 DUPLICATE_SAME_ACCESS)) 93 126 mhThread = INVALID_HANDLE_VALUE; 94 127 95 #else 128 #else // VBOX_WITH_XPCOM 96 129 97 130 mEQCreated = FALSE; 98 99 mLastEvent = NULL; 100 mGotEvent = FALSE; 131 mInterrupted = FALSE; 101 132 102 133 // Here we reference the global nsIEventQueueService instance and hold it … … 112 143 // NULL to the event thread (because it stopped accepting events). 113 144 114 nsresult rc = NS_GetEventQueueService (getter_AddRefs(mEventQService));145 nsresult rc = NS_GetEventQueueService(getter_AddRefs(mEventQService)); 115 146 116 147 if (NS_SUCCEEDED(rc)) 117 148 { 118 rc = mEventQService->GetThreadEventQueue 119 getter_AddRefs(mEventQ));149 rc = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, 150 getter_AddRefs(mEventQ)); 120 151 if (rc == NS_ERROR_NOT_AVAILABLE) 121 152 { 122 rc = mEventQService->Create MonitoredThreadEventQueue();153 rc = mEventQService->CreateThreadEventQueue(); 123 154 if (NS_SUCCEEDED(rc)) 124 155 { 125 156 mEQCreated = TRUE; 126 rc = mEventQService->GetThreadEventQueue 127 getter_AddRefs(mEventQ));157 rc = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, 158 getter_AddRefs(mEventQ)); 128 159 } 129 160 } 130 161 } 131 AssertComRC 132 133 #endif 162 AssertComRC(rc); 163 164 #endif // VBOX_WITH_XPCOM 134 165 } 135 166 136 167 EventQueue::~EventQueue() 137 168 { 138 #if defined (RT_OS_WINDOWS)169 #ifndef VBOX_WITH_XPCOM 139 170 if (mhThread != INVALID_HANDLE_VALUE) 140 171 { 141 CloseHandle 172 CloseHandle(mhThread); 142 173 mhThread = INVALID_HANDLE_VALUE; 143 174 } 144 #else 175 #else // VBOX_WITH_XPCOM 145 176 // process all pending events before destruction 146 177 if (mEventQ) … … 155 186 mEventQService = nsnull; 156 187 } 157 #endif 188 #endif // VBOX_WITH_XPCOM 158 189 } 159 190 … … 175 206 mMainQueue = new EventQueue(); 176 207 177 #if defined (VBOX_WITH_XPCOM)208 #ifdef VBOX_WITH_XPCOM 178 209 /* Check that it actually is the main event queue, i.e. that 179 210 we're called on the right thread. */ … … 187 218 rv = mMainQueue->mEventQ->IsQueueNative(&fIsNative); 188 219 Assert(NS_SUCCEEDED(rv) && fIsNative); 189 #endif 220 #endif // VBOX_WITH_XPCOM 190 221 191 222 return VINF_SUCCESS; … … 200 231 { 201 232 Assert(mMainQueue); 233 /* Must process all events to make sure that no NULL event is left 234 * after this point. It would need to modify the state of mMainQueue. */ 235 mMainQueue->processEventQueue(0); 202 236 delete mMainQueue; 203 237 mMainQueue = NULL; … … 216 250 } 217 251 218 #ifdef RT_OS_DARWIN 252 #ifdef VBOX_WITH_XPCOM 253 # ifdef RT_OS_DARWIN 219 254 /** 220 255 * Wait for events and process them (Darwin). … … 249 284 return VERR_TIMEOUT; 250 285 } 251 # elif !defined(RT_OS_WINDOWS)252 253 /** 254 * Wait for events ( Unix).286 # else // !RT_OS_DARWIN 287 288 /** 289 * Wait for events (generic XPCOM). 255 290 * 256 291 * @returns VINF_SUCCESS or VERR_TIMEOUT. … … 260 295 */ 261 296 static 262 int waitForEventsOn Unix(nsIEventQueue *pQueue, unsigned cMsTimeout)297 int waitForEventsOnXPCOM(nsIEventQueue *pQueue, unsigned cMsTimeout) 263 298 { 264 299 int fd = pQueue->GetEventQueueSelectFD(); … … 295 330 } 296 331 297 #endif 298 299 #ifdef RT_OS_WINDOWS 332 # endif // !RT_OS_DARWIN 333 #endif // VBOX_WITH_XPCOM 334 335 #ifndef VBOX_WITH_XPCOM 300 336 /** 301 337 * Process pending events (Windows). … … 318 354 return rc; 319 355 } 320 #else /* !RT_OS_WINDOWS */356 #else // VBOX_WITH_XPCOM 321 357 /** 322 358 * Process pending XPCOM events. … … 335 371 return VERR_TIMEOUT; 336 372 337 /** @todo: rethink interruption events, current NULL event approach is bad */338 373 pQueue->ProcessPendingEvents(); 339 374 return VINF_SUCCESS; 340 375 } 341 #endif / * !RT_OS_WINDOWS */376 #endif // VBOX_WITH_XPCOM 342 377 343 378 … … 362 397 CHECK_THREAD_RET(VERR_INVALID_CONTEXT); 363 398 364 #if defined (VBOX_WITH_XPCOM)399 #ifdef VBOX_WITH_XPCOM 365 400 /* 366 401 * Process pending events, if none are available and we're not in a 367 402 * poll call, wait for some to appear. (We have to be a little bit 368 * careful after waiting for the events since darwin will process369 * them as part of the wait, while the unixcase will not.)403 * careful after waiting for the events since Darwin will process 404 * them as part of the wait, while the XPCOM case will not.) 370 405 * 371 406 * Note! Unfortunately, WaitForEvent isn't interruptible with Ctrl-C, … … 377 412 { 378 413 # ifdef RT_OS_DARWIN 379 /** @todo check how Ctrl-C works on darwin. */414 /** @todo check how Ctrl-C works on Darwin. */ 380 415 rc = waitForEventsOnDarwin(cMsTimeout); 381 416 if (rc == VERR_TIMEOUT) 382 417 rc = processPendingEvents(mEventQ); 383 # else 384 rc = waitForEventsOn Unix(mEventQ, cMsTimeout);418 # else // !RT_OS_DARWIN 419 rc = waitForEventsOnXPCOM(mEventQ, cMsTimeout); 385 420 if ( RT_SUCCESS(rc) 386 421 || rc == VERR_TIMEOUT) 387 422 rc = processPendingEvents(mEventQ); 388 # endif 389 } 390 391 #else /* !VBOX_WITH_XPCOM */ 423 # endif // !RT_OS_DARWIN 424 } 425 if (RT_SUCCESS(rc) && mInterrupted) 426 { 427 mInterrupted = false; 428 rc = VERR_INTERRUPTED; 429 } 430 431 #else // !VBOX_WITH_XPCOM 392 432 if (cMsTimeout == RT_INDEFINITE_WAIT) 393 433 { 394 Event *aEvent = NULL;395 396 BOOL fHasEvent = waitForEvent(&aEvent);397 if (fHasEvent)434 BOOL bRet; 435 MSG Msg; 436 int rc = VINF_SUCCESS; 437 while ((bRet = GetMessage(&Msg, NULL /*hWnd*/, WM_USER, WM_USER))) 398 438 { 399 handleEvent(aEvent); 400 rc = processPendingEvents(); 401 if (rc == VERR_TIMEOUT) 402 rc = VINF_SUCCESS; 439 if (bRet != -1) 440 DispatchMessage(&Msg); 403 441 } 404 else442 if (bRet == 0) 405 443 rc = VERR_INTERRUPTED; 406 444 } … … 422 460 } 423 461 } 424 #endif / * !VBOX_WITH_XPCOM */462 #endif // !VBOX_WITH_XPCOM 425 463 return rc; 426 464 } … … 433 471 int EventQueue::interruptEventQueueProcessing() 434 472 { 435 /** @todo: rethink me! */ 473 /* Send a NULL event. This gets us out of the event loop on XPCOM, and 474 * doesn't hurt on Windows. It is the responsibility of the caller to 475 * take care of not running the loop again in a way which will hang. */ 436 476 postEvent(NULL); 437 477 return VINF_SUCCESS; … … 446 486 BOOL EventQueue::postEvent(Event *event) 447 487 { 448 #if defined (RT_OS_WINDOWS)449 450 return PostThreadMessage (mThreadId, WM_USER, (WPARAM)event, NULL);451 452 #else 488 #ifndef VBOX_WITH_XPCOM 489 490 return PostThreadMessage(mThreadId, WM_USER, (WPARAM)event, NULL); 491 492 #else // VBOX_WITH_XPCOM 453 493 454 494 if (!mEventQ) 455 495 return FALSE; 456 496 457 MyPLEvent *ev = new MyPLEvent (event); 458 mEventQ->InitEvent (ev, this, plEventHandler, plEventDestructor); 459 HRESULT rc = mEventQ->PostEvent (ev); 497 MyPLEvent *ev = new MyPLEvent(event); 498 mEventQ->InitEvent(ev, this, com::EventQueue::plEventHandler, 499 com::EventQueue::plEventDestructor); 500 HRESULT rc = mEventQ->PostEvent(ev); 460 501 return NS_SUCCEEDED(rc); 461 502 462 #endif 463 } 464 465 /** 466 * Waits for a single event. 467 * This method must be called on the same thread where this event queue 468 * is created. 469 * 470 * After this method returns TRUE and non-NULL event, the caller should call 471 * #handleEvent() in order to process the returned event (otherwise the event 472 * is just removed from the queue, but not processed). 473 * 474 * There is a special case when the returned event is NULL (and the method 475 * returns TRUE), meaning that this event queue must finish its execution 476 * (i.e., quit the event loop), 477 * 478 * @param event next event removed from the queue 479 * @return TRUE if successful and false otherwise 480 */ 481 BOOL EventQueue::waitForEvent(Event **event) 482 { 483 Assert(event); 484 if (!event) 485 return FALSE; 486 487 *event = NULL; 488 489 CHECK_THREAD_RET (FALSE); 490 491 #if defined (RT_OS_WINDOWS) 492 493 MSG msg; 494 BOOL rc = GetMessage (&msg, NULL, WM_USER, WM_USER); 495 // check for error 496 if (rc == -1) 497 return FALSE; 498 // check for WM_QUIT 499 if (!rc) 500 return TRUE; 501 502 // retrieve our event 503 *event = (Event *) msg.wParam; 504 505 #else 506 507 PLEvent *ev = NULL; 508 HRESULT rc; 509 510 mGotEvent = FALSE; 511 512 do 513 { 514 rc = mEventQ->WaitForEvent (&ev); 515 // check for error 516 if (FAILED(rc)) 517 return FALSE; 518 // check for EINTR signal 519 if (!ev) 520 return TRUE; 521 522 // run PLEvent handler. This will just set mLastEvent if it is an 523 // MyPLEvent instance, and then delete ev. 524 mEventQ->HandleEvent (ev); 525 } 526 while (!mGotEvent); 527 528 // retrieve our event 529 *event = mLastEvent; 530 531 #endif 532 533 return TRUE; 534 } 535 536 /** 537 * Handles the given event and |delete|s it. 538 * This method must be called on the same thread where this event queue 539 * is created. 540 */ 541 BOOL EventQueue::handleEvent(Event *event) 542 { 543 Assert(event); 544 if (!event) 545 return FALSE; 546 547 CHECK_THREAD_RET (FALSE); 548 549 event->handler(); 550 delete event; 551 552 return TRUE; 553 } 503 #endif // VBOX_WITH_XPCOM 504 } 505 554 506 555 507 /** … … 566 518 #endif 567 519 } 520 568 521 } 569 522 /* namespace com */
Note:
See TracChangeset
for help on using the changeset viewer.