- Timestamp:
- Jun 21, 2010 1:43:55 PM (14 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/EventImpl.cpp
r30311 r30331 16 16 */ 17 17 18 #include <list> 19 #include <map> 20 #include <deque> 21 18 22 #include "EventImpl.h" 23 #include "AutoCaller.h" 24 #include "Logging.h" 25 26 #include <iprt/semaphore.h> 27 #include <iprt/critsect.h> 28 #include <VBox/com/array.h> 19 29 20 30 struct VBoxEvent::Data 21 31 { 22 32 Data() 23 : 33 : 24 34 mType(VBoxEventType_Invalid), 25 mWaitable(FALSE) 35 mWaitEvent(NIL_RTSEMEVENT), 36 mWaitable(FALSE), 37 mProcessed(FALSE) 26 38 {} 27 VBoxEventType_T mType; 28 BOOL mWaitable; 39 ComPtr<IEventSource> mSource; 40 VBoxEventType_T mType; 41 RTSEMEVENT mWaitEvent; 42 BOOL mWaitable; 43 BOOL mProcessed; 29 44 }; 30 45 … … 46 61 HRESULT rc = S_OK; 47 62 63 m->mSource = aSource; 48 64 m->mType = aType; 49 65 m->mWaitable = aWaitable; 66 m->mProcessed = !aWaitable; 67 68 do { 69 if (aWaitable) 70 { 71 int vrc = ::RTSemEventCreate (&m->mWaitEvent); 72 73 if (RT_FAILURE(vrc)) 74 { 75 AssertFailed (); 76 rc = setError(E_FAIL, 77 tr("Internal error (%Rrc)"), vrc); 78 break; 79 } 80 } 81 } while (0); 50 82 51 83 return rc; … … 54 86 void VBoxEvent::uninit() 55 87 { 88 m->mProcessed = TRUE; 56 89 m->mType = VBoxEventType_Invalid; 90 m->mSource.setNull(); 91 92 if (m->mWaitEvent != NIL_RTSEMEVENT) 93 { 94 ::RTSemEventDestroy(m->mWaitEvent); 95 } 57 96 } 58 97 59 98 STDMETHODIMP VBoxEvent::COMGETTER(Type)(VBoxEventType_T *aType) 60 99 { 100 CheckComArgNotNull(aType); 101 102 AutoCaller autoCaller(this); 103 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 104 61 105 // never changes till event alive, no locking? 62 106 *aType = m->mType; … … 66 110 STDMETHODIMP VBoxEvent::COMGETTER(Source)(IEventSource* *aSource) 67 111 { 68 return E_NOTIMPL; 112 CheckComArgOutPointerValid(aSource); 113 114 AutoCaller autoCaller(this); 115 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 116 117 m->mSource.queryInterfaceTo(aSource); 118 return S_OK; 69 119 } 70 120 71 121 STDMETHODIMP VBoxEvent::COMGETTER(Waitable)(BOOL *aWaitable) 72 122 { 123 CheckComArgNotNull(aWaitable); 124 125 AutoCaller autoCaller(this); 126 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 127 73 128 // never changes till event alive, no locking? 74 129 *aWaitable = m->mWaitable; … … 79 134 STDMETHODIMP VBoxEvent::SetProcessed() 80 135 { 81 return E_NOTIMPL; 136 AutoCaller autoCaller(this); 137 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 138 139 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 140 141 if (m->mProcessed) 142 return S_OK; 143 144 m->mProcessed = TRUE; 145 146 // notify waiters 147 ::RTSemEventSignal(m->mWaitEvent); 148 149 return S_OK; 82 150 } 83 151 84 152 STDMETHODIMP VBoxEvent::WaitProcessed(LONG aTimeout, BOOL *aResult) 85 153 { 86 return E_NOTIMPL; 87 } 88 154 CheckComArgNotNull(aResult); 155 156 AutoCaller autoCaller(this); 157 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 158 159 { 160 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 161 162 if (m->mProcessed) 163 return S_OK; 164 } 165 166 int vrc = ::RTSemEventWait(m->mWaitEvent, aTimeout); 167 AssertMsg(RT_SUCCESS(vrc) || vrc == VERR_TIMEOUT || vrc == VERR_INTERRUPTED, 168 ("RTSemEventWait returned %Rrc\n", vrc)); 169 170 171 if (RT_SUCCESS(vrc)) 172 { 173 AssertMsg(m->mProcessed, 174 ("mProcessed must be set here\n")); 175 *aResult = m->mProcessed; 176 } 177 else 178 { 179 *aResult = FALSE; 180 } 181 182 return S_OK; 183 } 184 185 static const int FirstEvent = (int)VBoxEventType_LastWildcard + 1; 186 static const int LastEvent = (int)VBoxEventType_Last; 187 static const int NumEvents = LastEvent - FirstEvent; 188 189 struct ListenerRecord; 190 typedef std::list<ListenerRecord*> EventMap[NumEvents]; 191 typedef std::map<IEvent*, int32_t> PendingEventsMap; 192 typedef std::deque<ComPtr<IEvent> > PassiveQueue; 193 194 struct ListenerRecord 195 { 196 ComPtr<IEventListener> mListener; 197 BOOL mActive; 198 EventSource* mOwner; 199 200 RTSEMEVENT mQEvent; 201 RTCRITSECT mcsQLock; 202 PassiveQueue mQueue; 203 204 ListenerRecord(IEventListener* aListener, 205 com::SafeArray<VBoxEventType_T>& aInterested, 206 BOOL aActive, 207 EventSource* aOwner); 208 ~ListenerRecord(); 209 210 HRESULT process(IEvent* aEvent, BOOL aWaitable, PendingEventsMap::iterator& pit); 211 HRESULT enqueue(IEvent* aEvent); 212 HRESULT dequeue(IEvent* *aEvent, LONG aTimeout); 213 HRESULT eventProcessed(IEvent * aEvent, PendingEventsMap::iterator& pit); 214 }; 215 216 typedef std::map<IEventListener*, ListenerRecord> Listeners; 89 217 90 218 struct EventSource::Data 91 219 { 92 Data() 93 : 94 mBogus(0) 95 {} 96 int32_t mBogus; 220 Data() {} 221 Listeners mListeners; 222 EventMap mEvMap; 223 PendingEventsMap mPendingMap; 97 224 }; 225 226 static BOOL implies(VBoxEventType_T who, VBoxEventType_T what) 227 { 228 switch (who) 229 { 230 case VBoxEventType_Any: 231 return TRUE; 232 case VBoxEventType_MachineEvent: 233 return (what == VBoxEventType_OnMachineStateChange) || (what == VBoxEventType_OnMachineDataChange); 234 case VBoxEventType_Invalid: 235 return FALSE; 236 } 237 return who == what; 238 } 239 240 ListenerRecord::ListenerRecord(IEventListener* aListener, 241 com::SafeArray<VBoxEventType_T>& aInterested, 242 BOOL aActive, 243 EventSource* aOwner) 244 : 245 mActive(aActive), 246 mOwner(aOwner) 247 { 248 mListener = aListener; 249 EventMap* aEvMap = &aOwner->m->mEvMap; 250 251 for (size_t i = 0; i < aInterested.size(); ++i) 252 { 253 VBoxEventType_T interested = aInterested[i]; 254 for (int j = FirstEvent; j < LastEvent; j++) 255 { 256 VBoxEventType_T candidate = (VBoxEventType_T)j; 257 if (implies(interested, candidate)) 258 { 259 (*aEvMap)[j - FirstEvent].push_back(this); 260 } 261 } 262 } 263 264 ::RTCritSectInitEx(&mcsQLock, 0, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL); 265 ::RTSemEventCreate (&mQEvent); 266 } 267 268 ListenerRecord::~ListenerRecord() 269 { 270 /* Remove references to us from the event map */ 271 EventMap* aEvMap = &mOwner->m->mEvMap; 272 for (int j = FirstEvent; j < LastEvent; j++) 273 { 274 (*aEvMap)[j - FirstEvent].remove(this); 275 } 276 277 ::RTCritSectDelete(&mcsQLock); 278 ::RTSemEventDestroy(mQEvent); 279 } 280 281 HRESULT ListenerRecord::process(IEvent* aEvent, BOOL aWaitable, PendingEventsMap::iterator& pit) 282 { 283 if (mActive) 284 { 285 HRESULT rc = mListener->HandleEvent(aEvent); 286 if (aWaitable) 287 eventProcessed(aEvent, pit); 288 return rc; 289 } 290 else 291 return enqueue(aEvent); 292 } 293 294 295 HRESULT ListenerRecord::enqueue (IEvent* aEvent) 296 { 297 AssertMsg(!mActive, ("must be passive\n")); 298 ::RTCritSectEnter(&mcsQLock); 299 300 mQueue.push_back(aEvent); 301 // notify waiters 302 ::RTSemEventSignal(mQEvent); 303 304 ::RTCritSectLeave(&mcsQLock); 305 306 return S_OK; 307 } 308 309 HRESULT ListenerRecord::dequeue (IEvent* *aEvent, LONG aTimeout) 310 { 311 AssertMsg(!mActive, ("must be passive\n")); 312 313 ::RTCritSectEnter(&mcsQLock); 314 if (mQueue.empty()) 315 { 316 ::RTCritSectLeave(&mcsQLock); 317 ::RTSemEventWait(mQEvent, aTimeout); 318 ::RTCritSectEnter(&mcsQLock); 319 } 320 if (mQueue.empty()) 321 { 322 *aEvent = NULL; 323 } 324 else 325 { 326 mQueue.front().queryInterfaceTo(aEvent); 327 mQueue.pop_front(); 328 } 329 ::RTCritSectLeave(&mcsQLock); 330 return S_OK; 331 } 332 333 HRESULT ListenerRecord::eventProcessed (IEvent* aEvent, PendingEventsMap::iterator& pit) 334 { 335 if (--pit->second == 0) 336 { 337 aEvent->SetProcessed(); 338 mOwner->m->mPendingMap.erase(pit); 339 } 340 341 Assert(pit->second >= 0); 342 return S_OK; 343 } 98 344 99 345 HRESULT EventSource::FinalConstruct() … … 118 364 void EventSource::uninit() 119 365 { 120 } 121 122 STDMETHODIMP EventSource::RegisterListener(IEventListener * aListener, 123 ComSafeArrayIn(VBoxEventType, aInterested), 366 m->mListeners.clear(); 367 // m->mEvMap shall be cleared at this point too by destructors 368 } 369 370 STDMETHODIMP EventSource::RegisterListener(IEventListener * aListener, 371 ComSafeArrayIn(VBoxEventType_T, aInterested), 124 372 BOOL aActive) 125 373 { 126 return E_NOTIMPL; 374 CheckComArgNotNull(aListener); 375 CheckComArgSafeArrayNotNull(aInterested); 376 377 AutoCaller autoCaller(this); 378 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 379 380 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 381 382 Listeners::const_iterator it = m->mListeners.find(aListener); 383 if (it != m->mListeners.end()) 384 return setError(E_INVALIDARG, 385 tr("This listener already registered")); 386 387 com::SafeArray<VBoxEventType_T> interested(ComSafeArrayInArg (aInterested)); 388 m->mListeners.insert( 389 Listeners::value_type(aListener, 390 ListenerRecord(aListener, interested, aActive, this)) 391 ); 392 393 return S_OK; 127 394 } 128 395 129 396 STDMETHODIMP EventSource::UnregisterListener(IEventListener * aListener) 130 397 { 131 return E_NOTIMPL; 398 CheckComArgNotNull(aListener); 399 400 AutoCaller autoCaller(this); 401 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 402 403 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 404 405 Listeners::iterator it = m->mListeners.find(aListener); 406 HRESULT rc; 407 408 if (it != m->mListeners.end()) 409 { 410 m->mListeners.erase(it); 411 // destructor removes refs from the event map 412 rc = S_OK; 413 } 414 else 415 { 416 rc = setError(VBOX_E_OBJECT_NOT_FOUND, 417 tr("Listener was never registered")); 418 } 419 420 return rc; 132 421 } 133 422 … … 136 425 BOOL *aProcessed) 137 426 { 138 return E_NOTIMPL; 427 CheckComArgNotNull(aEvent); 428 CheckComArgOutPointerValid(aProcessed); 429 430 AutoCaller autoCaller(this); 431 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 432 433 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 434 435 VBoxEventType_T evType; 436 HRESULT hrc = aEvent->COMGETTER(Type)(&evType); 437 AssertComRCReturn(hrc, VERR_ACCESS_DENIED); 438 439 BOOL aWaitable = FALSE; 440 aEvent->COMGETTER(Waitable)(&aWaitable); 441 442 std::list<ListenerRecord*>& listeners = m->mEvMap[(int)evType-FirstEvent]; 443 444 uint32_t cListeners = listeners.size(); 445 PendingEventsMap::iterator pit; 446 447 if (cListeners > 0 && aWaitable) 448 { 449 m->mPendingMap.insert(PendingEventsMap::value_type(aEvent, cListeners)); 450 // we keep it here to allow processing active listeners without pending events lookup 451 pit = m->mPendingMap.find(aEvent); 452 } 453 for(std::list<ListenerRecord*>::const_iterator it = listeners.begin(); 454 it != listeners.end(); ++it) 455 { 456 ListenerRecord* record = *it; 457 HRESULT cbRc; 458 459 // @todo: callback under (read) lock, is it good? 460 cbRc = record->process(aEvent, aWaitable, pit); 461 // what to do with cbRc? 462 } 463 464 if (aWaitable) 465 hrc = aEvent->WaitProcessed(aTimeout, aProcessed); 466 else 467 *aProcessed = TRUE; 468 469 return hrc; 139 470 } 140 471 … … 144 475 IEvent * *aEvent) 145 476 { 146 return E_NOTIMPL; 477 478 CheckComArgNotNull(aListener); 479 480 AutoCaller autoCaller(this); 481 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 482 483 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 484 485 Listeners::iterator it = m->mListeners.find(aListener); 486 HRESULT rc; 487 488 if (it != m->mListeners.end()) 489 { 490 rc = it->second.dequeue(aEvent, aTimeout); 491 } 492 else 493 { 494 rc = setError(VBOX_E_OBJECT_NOT_FOUND, 495 tr("Listener was never registered")); 496 } 497 498 return rc; 147 499 } 148 500 … … 150 502 IEvent * aEvent) 151 503 { 152 return E_NOTIMPL; 153 } 154 504 CheckComArgNotNull(aListener); 505 CheckComArgNotNull(aEvent); 506 507 AutoCaller autoCaller(this); 508 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 509 510 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 511 512 Listeners::iterator it = m->mListeners.find(aListener); 513 HRESULT rc; 514 515 BOOL aWaitable = FALSE; 516 aEvent->COMGETTER(Waitable)(&aWaitable); 517 518 if (it != m->mListeners.end()) 519 { 520 ListenerRecord& aRecord = it->second; 521 522 if (aRecord.mActive) 523 return setError(E_INVALIDARG, 524 tr("Only applicable to passive listeners")); 525 526 if (aWaitable) 527 { 528 PendingEventsMap::iterator pit = m->mPendingMap.find(aEvent); 529 530 if (pit == m->mPendingMap.end()) 531 { 532 AssertFailed(); 533 rc = setError(VBOX_E_OBJECT_NOT_FOUND, 534 tr("Unknown event")); 535 } 536 else 537 rc = aRecord.eventProcessed(aEvent, pit); 538 } 539 else 540 { 541 // for non-waitable events we're done 542 rc = S_OK; 543 } 544 } 545 else 546 { 547 rc = setError(VBOX_E_OBJECT_NOT_FOUND, 548 tr("Listener was never registered")); 549 } 550 551 return rc; 552 } -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r30310 r30331 14556 14556 <const name="Invalid" value="0"> 14557 14557 <desc> 14558 Invalid event .14558 Invalid event, must be first. 14559 14559 </desc> 14560 14560 </const> … … 14574 14574 </const> 14575 14575 14576 <const name="LastWildcard" value="31"> 14577 <desc> 14578 Last wildcard. 14579 </desc> 14580 </const> 14581 14576 14582 <const name="OnMachineStateChange" value="32"> 14577 14583 <desc> … … 14587 14593 <desc> 14588 14594 <see>IVirtualBoxCallback::onExtraDataChange</see> 14595 </desc> 14596 </const> 14597 14598 <const name="Last" value="35"> 14599 <desc> 14600 Must be last event, used for iterations. 14589 14601 </desc> 14590 14602 </const> -
trunk/src/VBox/Main/include/EventImpl.h
r30311 r30331 100 100 // IEventSource methods 101 101 STDMETHOD(RegisterListener)(IEventListener * aListener, 102 ComSafeArrayIn(VBoxEventType , aInterested),102 ComSafeArrayIn(VBoxEventType_T, aInterested), 103 103 BOOL aActive); 104 104 STDMETHOD(UnregisterListener)(IEventListener * aListener); … … 119 119 120 120 Data* m; 121 122 friend class ListenerRecord; 121 123 }; 122 124
Note:
See TracChangeset
for help on using the changeset viewer.