VirtualBox

source: vbox/trunk/src/VBox/Main/src-all/EventImpl.cpp@ 61015

Last change on this file since 61015 was 60765, checked in by vboxsync, 9 years ago

API: stop using ATL and use a vastly smaller lookalike instead, plus a lot of cleanups

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.5 KB
Line 
1/* $Id: EventImpl.cpp 60765 2016-04-29 14:26:58Z vboxsync $ */
2/** @file
3 * VirtualBox COM Event class implementation
4 */
5
6/*
7 * Copyright (C) 2010-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/** @page pg_main_events Events
19 *
20 * Theory of operations.
21 *
22 * This code implements easily extensible event mechanism, letting us
23 * to make any VirtualBox object an event source (by aggregating an EventSource instance).
24 * Another entity could subscribe to the event source for events it is interested in.
25 * If an event is waitable, it's possible to wait until all listeners
26 * registered at the moment of firing event as ones interested in this
27 * event acknowledged that they finished event processing (thus allowing
28 * vetoable events).
29 *
30 * Listeners can be registered as active or passive ones, defining policy of delivery.
31 * For *active* listeners, their HandleEvent() method is invoked when event is fired by
32 * the event source (pretty much callbacks).
33 * For *passive* listeners, it's up to an event consumer to perform GetEvent() operation
34 * with given listener, and then perform desired operation with returned event, if any.
35 * For passive listeners case, listener instance serves as merely a key referring to
36 * particular event consumer, thus HandleEvent() implementation isn't that important.
37 * IEventSource's CreateListener() could be used to create such a listener.
38 * Passive mode is designed for transports not allowing callbacks, such as webservices
39 * running on top of HTTP, and for situations where consumer wants exact control on
40 * context where event handler is executed (such as GUI thread for some toolkits).
41 *
42 * Internal EventSource data structures are optimized for fast event delivery, while
43 * listener registration/unregistration operations are expected being pretty rare.
44 * Passive mode listeners keep an internal event queue for all events they receive,
45 * and all waitable events are added to the pending events map. This map keeps track
46 * of how many listeners are still not acknowledged their event, and once this counter
47 * reach zero, element is removed from pending events map, and event is marked as processed.
48 * Thus if passive listener's user forgets to call IEventSource's EventProcessed()
49 * waiters may never know that event processing finished.
50 */
51
52#include <list>
53#include <map>
54#include <deque>
55
56#include "EventImpl.h"
57#include "AutoCaller.h"
58#include "Logging.h"
59
60#include <iprt/semaphore.h>
61#include <iprt/critsect.h>
62#include <iprt/asm.h>
63#include <iprt/time.h>
64
65#include <VBox/com/array.h>
66
67class ListenerRecord;
68
69struct VBoxEvent::Data
70{
71 Data()
72 : mType(VBoxEventType_Invalid),
73 mWaitEvent(NIL_RTSEMEVENT),
74 mWaitable(FALSE),
75 mProcessed(FALSE)
76 {}
77
78 VBoxEventType_T mType;
79 RTSEMEVENT mWaitEvent;
80 BOOL mWaitable;
81 BOOL mProcessed;
82 ComPtr<IEventSource> mSource;
83};
84
85DEFINE_EMPTY_CTOR_DTOR(VBoxEvent)
86
87HRESULT VBoxEvent::FinalConstruct()
88{
89 m = new Data;
90 return BaseFinalConstruct();
91}
92
93void VBoxEvent::FinalRelease()
94{
95 if (m)
96 {
97 uninit();
98 delete m;
99 m = NULL;
100 }
101 BaseFinalRelease();
102}
103
104HRESULT VBoxEvent::init(IEventSource *aSource, VBoxEventType_T aType, BOOL aWaitable)
105{
106 HRESULT rc = S_OK;
107
108 AssertReturn(aSource != NULL, E_INVALIDARG);
109
110 AutoInitSpan autoInitSpan(this);
111 AssertReturn(autoInitSpan.isOk(), E_FAIL);
112
113 m->mSource = aSource;
114 m->mType = aType;
115 m->mWaitable = aWaitable;
116 m->mProcessed = !aWaitable;
117
118 do {
119 if (aWaitable)
120 {
121 int vrc = ::RTSemEventCreate(&m->mWaitEvent);
122
123 if (RT_FAILURE(vrc))
124 {
125 AssertFailed();
126 return setError(E_FAIL,
127 tr("Internal error (%Rrc)"), vrc);
128 }
129 }
130 } while (0);
131
132 /* Confirm a successful initialization */
133 autoInitSpan.setSucceeded();
134
135 return rc;
136}
137
138void VBoxEvent::uninit()
139{
140 AutoUninitSpan autoUninitSpan(this);
141 if (autoUninitSpan.uninitDone())
142 return;
143
144 if (!m)
145 return;
146
147 m->mProcessed = TRUE;
148 m->mType = VBoxEventType_Invalid;
149 m->mSource.setNull();
150
151 if (m->mWaitEvent != NIL_RTSEMEVENT)
152 {
153 Assert(m->mWaitable);
154 ::RTSemEventDestroy(m->mWaitEvent);
155 m->mWaitEvent = NIL_RTSEMEVENT;
156 }
157}
158
159HRESULT VBoxEvent::getType(VBoxEventType_T *aType)
160{
161 // never changes while event alive, no locking
162 *aType = m->mType;
163 return S_OK;
164}
165
166HRESULT VBoxEvent::getSource(ComPtr<IEventSource> &aSource)
167{
168 m->mSource.queryInterfaceTo(aSource.asOutParam());
169 return S_OK;
170}
171
172HRESULT VBoxEvent::getWaitable(BOOL *aWaitable)
173{
174 // never changes while event alive, no locking
175 *aWaitable = m->mWaitable;
176 return S_OK;
177}
178
179HRESULT VBoxEvent::setProcessed()
180{
181 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
182
183 if (m->mProcessed)
184 return S_OK;
185
186 m->mProcessed = TRUE;
187
188 // notify waiters
189 ::RTSemEventSignal(m->mWaitEvent);
190
191 return S_OK;
192}
193
194HRESULT VBoxEvent::waitProcessed(LONG aTimeout, BOOL *aResult)
195{
196 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
197
198 if (m->mProcessed)
199 {
200 *aResult = TRUE;
201 return S_OK;
202 }
203
204 if (aTimeout == 0)
205 {
206 *aResult = m->mProcessed;
207 return S_OK;
208 }
209
210 // must drop lock while waiting, because setProcessed() needs synchronization.
211 alock.release();
212 /* @todo: maybe while loop for spurious wakeups? */
213 int vrc = ::RTSemEventWait(m->mWaitEvent, aTimeout);
214 AssertMsg(RT_SUCCESS(vrc) || vrc == VERR_TIMEOUT || vrc == VERR_INTERRUPTED,
215 ("RTSemEventWait returned %Rrc\n", vrc));
216 alock.acquire();
217
218 if (RT_SUCCESS(vrc))
219 {
220 AssertMsg(m->mProcessed,
221 ("mProcessed must be set here\n"));
222 *aResult = m->mProcessed;
223 }
224 else
225 {
226 *aResult = FALSE;
227 }
228
229 return S_OK;
230}
231
232typedef std::list<Utf8Str> VetoList;
233typedef std::list<Utf8Str> ApprovalList;
234struct VBoxVetoEvent::Data
235{
236 Data() :
237 mVetoed(FALSE)
238 {}
239 ComObjPtr<VBoxEvent> mEvent;
240 BOOL mVetoed;
241 VetoList mVetoList;
242 ApprovalList mApprovalList;
243};
244
245HRESULT VBoxVetoEvent::FinalConstruct()
246{
247 m = new Data;
248 HRESULT rc = m->mEvent.createObject();
249 BaseFinalConstruct();
250 return rc;
251}
252
253void VBoxVetoEvent::FinalRelease()
254{
255 if (m)
256 {
257 uninit();
258 delete m;
259 m = NULL;
260 }
261 BaseFinalRelease();
262}
263
264DEFINE_EMPTY_CTOR_DTOR(VBoxVetoEvent)
265
266HRESULT VBoxVetoEvent::init(IEventSource *aSource, VBoxEventType_T aType)
267{
268 HRESULT rc = S_OK;
269 // all veto events are waitable
270 rc = m->mEvent->init(aSource, aType, TRUE);
271 if (FAILED(rc))
272 return rc;
273
274 AutoInitSpan autoInitSpan(this);
275 AssertReturn(autoInitSpan.isOk(), E_FAIL);
276
277 m->mVetoed = FALSE;
278 m->mVetoList.clear();
279 m->mApprovalList.clear();
280
281 /* Confirm a successful initialization */
282 autoInitSpan.setSucceeded();
283
284 return S_OK;
285}
286
287void VBoxVetoEvent::uninit()
288{
289 AutoUninitSpan autoUninitSpan(this);
290 if (autoUninitSpan.uninitDone())
291 return;
292
293 if (!m)
294 return;
295
296 m->mVetoed = FALSE;
297 if (!m->mEvent.isNull())
298 {
299 m->mEvent->uninit();
300 m->mEvent.setNull();
301 }
302}
303
304HRESULT VBoxVetoEvent::getType(VBoxEventType_T *aType)
305{
306 return m->mEvent->COMGETTER(Type)(aType);
307}
308
309HRESULT VBoxVetoEvent::getSource(ComPtr<IEventSource> &aSource)
310{
311 return m->mEvent->COMGETTER(Source)(aSource.asOutParam());
312}
313
314HRESULT VBoxVetoEvent::getWaitable(BOOL *aWaitable)
315{
316 return m->mEvent->COMGETTER(Waitable)(aWaitable);
317}
318
319HRESULT VBoxVetoEvent::setProcessed()
320{
321 return m->mEvent->SetProcessed();
322}
323
324HRESULT VBoxVetoEvent::waitProcessed(LONG aTimeout, BOOL *aResult)
325{
326 return m->mEvent->WaitProcessed(aTimeout, aResult);
327}
328
329HRESULT VBoxVetoEvent::addVeto(const com::Utf8Str &aReason)
330{
331 // AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
332 if (aReason.length())
333 m->mVetoList.push_back(aReason);
334
335 m->mVetoed = TRUE;
336
337 return S_OK;
338}
339
340HRESULT VBoxVetoEvent::isVetoed(BOOL *aResult)
341{
342 // AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
343 *aResult = m->mVetoed;
344
345 return S_OK;
346}
347
348HRESULT VBoxVetoEvent::getVetos(std::vector<com::Utf8Str> &aResult)
349{
350 // AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
351 aResult.resize(m->mVetoList.size());
352 size_t i = 0;
353 for (VetoList::const_iterator it = m->mVetoList.begin(); it != m->mVetoList.end(); ++it, ++i)
354 aResult[i] = (*it);
355
356 return S_OK;
357
358}
359
360HRESULT VBoxVetoEvent::addApproval(const com::Utf8Str &aReason)
361{
362 // AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
363 m->mApprovalList.push_back(aReason);
364 return S_OK;
365}
366
367HRESULT VBoxVetoEvent::isApproved(BOOL *aResult)
368{
369 // AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
370 *aResult = !m->mApprovalList.empty();
371 return S_OK;
372}
373
374HRESULT VBoxVetoEvent::getApprovals(std::vector<com::Utf8Str> &aResult)
375{
376 // AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
377 aResult.resize(m->mApprovalList.size());
378 size_t i = 0;
379 for (ApprovalList::const_iterator it = m->mApprovalList.begin(); it != m->mApprovalList.end(); ++it, ++i)
380 aResult[i] = (*it);
381 return S_OK;
382}
383
384static const int FirstEvent = (int)VBoxEventType_LastWildcard + 1;
385static const int LastEvent = (int)VBoxEventType_Last;
386static const int NumEvents = LastEvent - FirstEvent;
387
388/**
389 * Class replacing std::list and able to provide required stability
390 * during iteration. It's acheived by delaying structural modifications
391 * to the list till the moment particular element is no longer used by
392 * current iterators.
393 */
394class EventMapRecord
395{
396public:
397 /**
398 * We have to be double linked, as structural modifications in list are delayed
399 * till element removed, so we have to know our previous one to update its next
400 */
401 EventMapRecord *mNext;
402 bool mAlive;
403private:
404 EventMapRecord *mPrev;
405 ListenerRecord *mRef; /* must be weak reference */
406 int32_t mRefCnt;
407
408public:
409 EventMapRecord(ListenerRecord *aRef) :
410 mNext(0), mAlive(true), mPrev(0), mRef(aRef), mRefCnt(1)
411 {}
412
413 EventMapRecord(EventMapRecord &aOther)
414 {
415 mNext = aOther.mNext;
416 mPrev = aOther.mPrev;
417 mRef = aOther.mRef;
418 mRefCnt = aOther.mRefCnt;
419 mAlive = aOther.mAlive;
420 }
421
422 ~EventMapRecord()
423 {
424 if (mNext)
425 mNext->mPrev = mPrev;
426 if (mPrev)
427 mPrev->mNext = mNext;
428 }
429
430 void addRef()
431 {
432 ASMAtomicIncS32(&mRefCnt);
433 }
434
435 void release()
436 {
437 if (ASMAtomicDecS32(&mRefCnt) <= 0)
438 delete this;
439 }
440
441 // Called when an element is no longer needed
442 void kill()
443 {
444 mAlive = false;
445 release();
446 }
447
448 ListenerRecord *ref()
449 {
450 return mAlive ? mRef : 0;
451 }
452
453 friend class EventMapList;
454};
455
456
457class EventMapList
458{
459 EventMapRecord *mHead;
460 uint32_t mSize;
461public:
462 EventMapList()
463 :
464 mHead(0),
465 mSize(0)
466 {}
467 ~EventMapList()
468 {
469 EventMapRecord *pCur = mHead;
470 while (pCur)
471 {
472 EventMapRecord *pNext = pCur->mNext;
473 pCur->release();
474 pCur = pNext;
475 }
476 }
477
478 /*
479 * Elements have to be added to the front of the list, to make sure
480 * that iterators doesn't see newly added listeners, and iteration
481 * will always complete.
482 */
483 void add(ListenerRecord *aRec)
484 {
485 EventMapRecord *pNew = new EventMapRecord(aRec);
486 pNew->mNext = mHead;
487 if (mHead)
488 mHead->mPrev = pNew;
489 mHead = pNew;
490 mSize++;
491 }
492
493 /*
494 * Mark element as removed, actual removal could be delayed until
495 * all consumers release it too. This helps to keep list stable
496 * enough for iterators to allow long and probably intrusive callbacks.
497 */
498 void remove(ListenerRecord *aRec)
499 {
500 EventMapRecord *pCur = mHead;
501 while (pCur)
502 {
503 EventMapRecord *aNext = pCur->mNext;
504 if (pCur->ref() == aRec)
505 {
506 if (pCur == mHead)
507 mHead = aNext;
508 pCur->kill();
509 mSize--;
510 // break?
511 }
512 pCur = aNext;
513 }
514 }
515
516 uint32_t size() const
517 {
518 return mSize;
519 }
520
521 struct iterator
522 {
523 EventMapRecord *mCur;
524
525 iterator() :
526 mCur(0)
527 {}
528
529 explicit
530 iterator(EventMapRecord *aCur) :
531 mCur(aCur)
532 {
533 // Prevent element removal, till we're at it
534 if (mCur)
535 mCur->addRef();
536 }
537
538 ~iterator()
539 {
540 if (mCur)
541 mCur->release();
542 }
543
544 ListenerRecord *
545 operator*() const
546 {
547 return mCur->ref();
548 }
549
550 EventMapList::iterator &
551 operator++()
552 {
553 EventMapRecord *pPrev = mCur;
554 do {
555 mCur = mCur->mNext;
556 } while (mCur && !mCur->mAlive);
557
558 // now we can safely release previous element
559 pPrev->release();
560
561 // And grab the new current
562 if (mCur)
563 mCur->addRef();
564
565 return *this;
566 }
567
568 bool
569 operator==(const EventMapList::iterator &aOther) const
570 {
571 return mCur == aOther.mCur;
572 }
573
574 bool
575 operator!=(const EventMapList::iterator &aOther) const
576 {
577 return mCur != aOther.mCur;
578 }
579 };
580
581 iterator begin()
582 {
583 return iterator(mHead);
584 }
585
586 iterator end()
587 {
588 return iterator(0);
589 }
590};
591
592typedef EventMapList EventMap[NumEvents];
593typedef std::map<IEvent *, int32_t> PendingEventsMap;
594typedef std::deque<ComPtr<IEvent> > PassiveQueue;
595
596class ListenerRecord
597{
598private:
599 ComPtr<IEventListener> mListener;
600 BOOL mActive;
601 EventSource *mOwner;
602
603 RTSEMEVENT mQEvent;
604 int32_t volatile mWaitCnt;
605 RTCRITSECT mcsQLock;
606 PassiveQueue mQueue;
607 int32_t volatile mRefCnt;
608 uint64_t mLastRead;
609
610public:
611 ListenerRecord(IEventListener *aListener,
612 com::SafeArray<VBoxEventType_T> &aInterested,
613 BOOL aActive,
614 EventSource *aOwner);
615 ~ListenerRecord();
616
617 HRESULT process(IEvent *aEvent, BOOL aWaitable, PendingEventsMap::iterator &pit, AutoLockBase &alock);
618 HRESULT enqueue(IEvent *aEvent);
619 HRESULT dequeue(IEvent **aEvent, LONG aTimeout, AutoLockBase &aAlock);
620 HRESULT eventProcessed(IEvent *aEvent, PendingEventsMap::iterator &pit);
621 void shutdown();
622
623 void addRef()
624 {
625 ASMAtomicIncS32(&mRefCnt);
626 }
627
628 void release()
629 {
630 if (ASMAtomicDecS32(&mRefCnt) <= 0)
631 delete this;
632 }
633
634 BOOL isActive()
635 {
636 return mActive;
637 }
638
639 friend class EventSource;
640};
641
642/* Handy class with semantics close to ComPtr, but for list records */
643template<typename Held>
644class RecordHolder
645{
646public:
647 RecordHolder(Held *lr) :
648 held(lr)
649 {
650 addref();
651 }
652 RecordHolder(const RecordHolder &that) :
653 held(that.held)
654 {
655 addref();
656 }
657 RecordHolder()
658 :
659 held(0)
660 {
661 }
662 ~RecordHolder()
663 {
664 release();
665 }
666
667 Held *obj()
668 {
669 return held;
670 }
671
672 RecordHolder &operator=(const RecordHolder &that)
673 {
674 safe_assign(that.held);
675 return *this;
676 }
677private:
678 Held *held;
679
680 void addref()
681 {
682 if (held)
683 held->addRef();
684 }
685 void release()
686 {
687 if (held)
688 held->release();
689 }
690 void safe_assign(Held *that_p)
691 {
692 if (that_p)
693 that_p->addRef();
694 release();
695 held = that_p;
696 }
697};
698
699typedef std::map<IEventListener *, RecordHolder<ListenerRecord> > Listeners;
700
701struct EventSource::Data
702{
703 Data() : fShutdown(false)
704 {}
705
706 Listeners mListeners;
707 EventMap mEvMap;
708 PendingEventsMap mPendingMap;
709 bool fShutdown;
710};
711
712/**
713 * This function defines what wildcard expands to.
714 */
715static BOOL implies(VBoxEventType_T who, VBoxEventType_T what)
716{
717 switch (who)
718 {
719 case VBoxEventType_Any:
720 return TRUE;
721 case VBoxEventType_Vetoable:
722 return (what == VBoxEventType_OnExtraDataCanChange)
723 || (what == VBoxEventType_OnCanShowWindow);
724 case VBoxEventType_MachineEvent:
725 return (what == VBoxEventType_OnMachineStateChanged)
726 || (what == VBoxEventType_OnMachineDataChanged)
727 || (what == VBoxEventType_OnMachineRegistered)
728 || (what == VBoxEventType_OnSessionStateChanged)
729 || (what == VBoxEventType_OnGuestPropertyChanged);
730 case VBoxEventType_SnapshotEvent:
731 return (what == VBoxEventType_OnSnapshotTaken)
732 || (what == VBoxEventType_OnSnapshotDeleted)
733 || (what == VBoxEventType_OnSnapshotChanged) ;
734 case VBoxEventType_InputEvent:
735 return (what == VBoxEventType_OnKeyboardLedsChanged)
736 || (what == VBoxEventType_OnMousePointerShapeChanged)
737 || (what == VBoxEventType_OnMouseCapabilityChanged);
738 case VBoxEventType_Invalid:
739 return FALSE;
740 default:
741 break;
742 }
743
744 return who == what;
745}
746
747ListenerRecord::ListenerRecord(IEventListener *aListener,
748 com::SafeArray<VBoxEventType_T> &aInterested,
749 BOOL aActive,
750 EventSource *aOwner) :
751 mActive(aActive), mOwner(aOwner), mWaitCnt(0), mRefCnt(0)
752{
753 mListener = aListener;
754 EventMap *aEvMap = &aOwner->m->mEvMap;
755
756 for (size_t i = 0; i < aInterested.size(); ++i)
757 {
758 VBoxEventType_T interested = aInterested[i];
759 for (int j = FirstEvent; j < LastEvent; j++)
760 {
761 VBoxEventType_T candidate = (VBoxEventType_T)j;
762 if (implies(interested, candidate))
763 {
764 (*aEvMap)[j - FirstEvent].add(this);
765 }
766 }
767 }
768
769 if (!mActive)
770 {
771 ::RTCritSectInit(&mcsQLock);
772 ::RTSemEventCreate(&mQEvent);
773 mLastRead = RTTimeMilliTS();
774 }
775 else
776 {
777 mQEvent = NIL_RTSEMEVENT;
778 RT_ZERO(mcsQLock);
779 mLastRead = 0;
780 }
781}
782
783ListenerRecord::~ListenerRecord()
784{
785 /* Remove references to us from the event map */
786 EventMap *aEvMap = &mOwner->m->mEvMap;
787 for (int j = FirstEvent; j < LastEvent; j++)
788 {
789 (*aEvMap)[j - FirstEvent].remove(this);
790 }
791
792 if (!mActive)
793 {
794 // at this moment nobody could add elements to our queue, so we can safely
795 // clean it up, otherwise there will be pending events map elements
796 PendingEventsMap *aPem = &mOwner->m->mPendingMap;
797 while (true)
798 {
799 ComPtr<IEvent> aEvent;
800
801 if (mQueue.empty())
802 break;
803
804 mQueue.front().queryInterfaceTo(aEvent.asOutParam());
805 mQueue.pop_front();
806
807 BOOL aWaitable = FALSE;
808 aEvent->COMGETTER(Waitable)(&aWaitable);
809 if (aWaitable)
810 {
811 PendingEventsMap::iterator pit = aPem->find(aEvent);
812 if (pit != aPem->end())
813 eventProcessed(aEvent, pit);
814 }
815 }
816
817 ::RTCritSectDelete(&mcsQLock);
818 }
819 shutdown();
820}
821
822HRESULT ListenerRecord::process(IEvent *aEvent,
823 BOOL aWaitable,
824 PendingEventsMap::iterator &pit,
825 AutoLockBase &aAlock)
826{
827 if (mActive)
828 {
829 /*
830 * We release lock here to allow modifying ops on EventSource inside callback.
831 */
832 HRESULT rc = S_OK;
833 if (mListener)
834 {
835 aAlock.release();
836 rc = mListener->HandleEvent(aEvent);
837#ifdef RT_OS_WINDOWS
838 Assert(rc != RPC_E_WRONG_THREAD);
839#endif
840 aAlock.acquire();
841 }
842 if (aWaitable)
843 eventProcessed(aEvent, pit);
844 return rc;
845 }
846 return enqueue(aEvent);
847}
848
849
850HRESULT ListenerRecord::enqueue(IEvent *aEvent)
851{
852 AssertMsg(!mActive, ("must be passive\n"));
853
854 // put an event the queue
855 ::RTCritSectEnter(&mcsQLock);
856
857 // If there was no events reading from the listener for the long time,
858 // and events keep coming, or queue is oversized we shall unregister this listener.
859 uint64_t sinceRead = RTTimeMilliTS() - mLastRead;
860 size_t queueSize = mQueue.size();
861 if ((queueSize > 1000) || ((queueSize > 500) && (sinceRead > 60 * 1000)))
862 {
863 ::RTCritSectLeave(&mcsQLock);
864 return E_ABORT;
865 }
866
867
868 if (queueSize != 0 && mQueue.back() == aEvent)
869 /* if same event is being pushed multiple times - it's reusable event and
870 we don't really need multiple instances of it in the queue */
871 (void)aEvent;
872 else
873 mQueue.push_back(aEvent);
874
875 ::RTCritSectLeave(&mcsQLock);
876
877 // notify waiters
878 ::RTSemEventSignal(mQEvent);
879
880 return S_OK;
881}
882
883HRESULT ListenerRecord::dequeue(IEvent **aEvent,
884 LONG aTimeout,
885 AutoLockBase &aAlock)
886{
887 if (mActive)
888 return VBOX_E_INVALID_OBJECT_STATE;
889
890 // retain listener record
891 RecordHolder<ListenerRecord> holder(this);
892
893 ::RTCritSectEnter(&mcsQLock);
894
895 mLastRead = RTTimeMilliTS();
896
897 if (mQueue.empty())
898 {
899 ::RTCritSectLeave(&mcsQLock);
900 // Speed up common case
901 if (aTimeout == 0)
902 {
903 *aEvent = NULL;
904 return S_OK;
905 }
906 // release lock while waiting, listener will not go away due to above holder
907 aAlock.release();
908
909 // In order to safely shutdown, count all waiting threads here.
910 ASMAtomicIncS32(&mWaitCnt);
911 ::RTSemEventWait(mQEvent, aTimeout);
912 ASMAtomicDecS32(&mWaitCnt);
913
914 // reacquire lock
915 aAlock.acquire();
916 ::RTCritSectEnter(&mcsQLock);
917 }
918 if (mQueue.empty())
919 {
920 *aEvent = NULL;
921 }
922 else
923 {
924 mQueue.front().queryInterfaceTo(aEvent);
925 mQueue.pop_front();
926 }
927 ::RTCritSectLeave(&mcsQLock);
928 return S_OK;
929}
930
931HRESULT ListenerRecord::eventProcessed(IEvent *aEvent, PendingEventsMap::iterator &pit)
932{
933 if (--pit->second == 0)
934 {
935 Assert(pit->first == aEvent);
936 aEvent->SetProcessed();
937 mOwner->m->mPendingMap.erase(pit);
938 }
939
940 return S_OK;
941}
942
943void ListenerRecord::shutdown()
944{
945 if (mQEvent != NIL_RTSEMEVENT)
946 {
947 RTSEMEVENT tmp = mQEvent;
948 mQEvent = NIL_RTSEMEVENT;
949
950 /* On Darwin it is known that RTSemEventDestroy() returns 0 while
951 * corresponding thread remains to be blocked after that. In order to prevent
952 * undesireble freeze on shutdown, this workaround is used. */
953 Log(("Wait for %d waiters to release.\n", ASMAtomicReadS32(&mWaitCnt)));
954 while (ASMAtomicReadS32(&mWaitCnt) > 0)
955 {
956 ::RTSemEventSignal(tmp);
957
958 /* Are we already done? */
959 if (ASMAtomicReadS32(&mWaitCnt) == 0)
960 break;
961
962 RTThreadSleep(10);
963 }
964 Log(("All waiters just released the lock.\n"));
965
966 ::RTSemEventDestroy(tmp);
967 }
968}
969
970EventSource::EventSource()
971{}
972
973EventSource::~EventSource()
974{}
975
976HRESULT EventSource::FinalConstruct()
977{
978 m = new Data;
979 return BaseFinalConstruct();
980}
981
982void EventSource::FinalRelease()
983{
984 uninit();
985 delete m;
986 BaseFinalRelease();
987}
988
989HRESULT EventSource::init()
990{
991 HRESULT rc = S_OK;
992
993 AutoInitSpan autoInitSpan(this);
994 AssertReturn(autoInitSpan.isOk(), E_FAIL);
995
996 /* Confirm a successful initialization */
997 autoInitSpan.setSucceeded();
998 return rc;
999}
1000
1001void EventSource::uninit()
1002{
1003 {
1004 // First of all (before even thinking about entering the uninit span):
1005 // make sure that all listeners are are shut down (no pending events or
1006 // wait calls), because they cannot be alive without the associated
1007 // event source. Otherwise API clients which use long-term (or
1008 // indefinite) waits will block VBoxSVC termination (just one example)
1009 // for a long time or even infinitely long.
1010 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1011 if (!m->fShutdown)
1012 {
1013 m->fShutdown = true;
1014 for (Listeners::iterator it = m->mListeners.begin();
1015 it != m->mListeners.end();
1016 ++it)
1017 {
1018 it->second.obj()->shutdown();
1019 }
1020 }
1021 }
1022
1023 AutoUninitSpan autoUninitSpan(this);
1024 if (autoUninitSpan.uninitDone())
1025 return;
1026
1027 m->mListeners.clear();
1028 // m->mEvMap shall be cleared at this point too by destructors, assert?
1029}
1030
1031HRESULT EventSource::registerListener(const ComPtr<IEventListener> &aListener,
1032 const std::vector<VBoxEventType_T> &aInteresting,
1033 BOOL aActive)
1034{
1035 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1036
1037 if (m->fShutdown)
1038 return setError(VBOX_E_INVALID_OBJECT_STATE,
1039 tr("This event source is already shut down"));
1040
1041 Listeners::const_iterator it = m->mListeners.find(aListener);
1042 if (it != m->mListeners.end())
1043 return setError(E_INVALIDARG,
1044 tr("This listener already registered"));
1045
1046 com::SafeArray<VBoxEventType_T> interested(aInteresting);
1047 RecordHolder<ListenerRecord> lrh(new ListenerRecord(aListener, interested, aActive, this));
1048 m->mListeners.insert(Listeners::value_type((IEventListener *)aListener, lrh));
1049
1050 VBoxEventDesc evDesc;
1051 evDesc.init(this, VBoxEventType_OnEventSourceChanged, (IEventListener *)aListener, TRUE);
1052 evDesc.fire(0);
1053
1054 return S_OK;
1055}
1056
1057HRESULT EventSource::unregisterListener(const ComPtr<IEventListener> &aListener)
1058{
1059 HRESULT rc = S_OK;;
1060
1061 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1062
1063 Listeners::iterator it = m->mListeners.find(aListener);
1064
1065 if (it != m->mListeners.end())
1066 {
1067 it->second.obj()->shutdown();
1068 m->mListeners.erase(it);
1069 // destructor removes refs from the event map
1070 rc = S_OK;
1071 }
1072 else
1073 {
1074 rc = setError(VBOX_E_OBJECT_NOT_FOUND,
1075 tr("Listener was never registered"));
1076 }
1077
1078 if (SUCCEEDED(rc))
1079 {
1080 VBoxEventDesc evDesc;
1081 evDesc.init(this, VBoxEventType_OnEventSourceChanged, (IEventListener *)aListener, FALSE);
1082 evDesc.fire(0);
1083 }
1084
1085 return rc;
1086}
1087
1088HRESULT EventSource::fireEvent(const ComPtr<IEvent> &aEvent,
1089 LONG aTimeout,
1090 BOOL *aResult)
1091{
1092
1093 HRESULT hrc = S_OK;
1094 BOOL aWaitable = FALSE;
1095 aEvent->COMGETTER(Waitable)(&aWaitable);
1096
1097 do {
1098 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1099
1100 if (m->fShutdown)
1101 return setError(VBOX_E_INVALID_OBJECT_STATE,
1102 tr("This event source is already shut down"));
1103
1104 VBoxEventType_T evType;
1105 hrc = aEvent->COMGETTER(Type)(&evType);
1106 AssertComRCReturn(hrc, hrc);
1107
1108 EventMapList &listeners = m->mEvMap[(int)evType - FirstEvent];
1109
1110 /* Anyone interested in this event? */
1111 uint32_t cListeners = listeners.size();
1112 if (cListeners == 0)
1113 {
1114 aEvent->SetProcessed();
1115 break; // just leave the lock and update event object state
1116 }
1117
1118 PendingEventsMap::iterator pit;
1119
1120 if (aWaitable)
1121 {
1122 m->mPendingMap.insert(PendingEventsMap::value_type(aEvent, cListeners));
1123 // we keep iterator here to allow processing active listeners without
1124 // pending events lookup
1125 pit = m->mPendingMap.find(aEvent);
1126 }
1127 for (EventMapList::iterator it = listeners.begin();
1128 it != listeners.end();
1129 ++it)
1130 {
1131 HRESULT cbRc;
1132 // keep listener record reference, in case someone will remove it while in callback
1133 RecordHolder<ListenerRecord> record(*it);
1134
1135 /*
1136 * We pass lock here to allow modifying ops on EventSource inside callback
1137 * in active mode. Note that we expect list iterator stability as 'alock'
1138 * could be temporary released when calling event handler.
1139 */
1140 cbRc = record.obj()->process(aEvent, aWaitable, pit, alock);
1141
1142 /* Note that E_ABORT is used above to signal that a passive
1143 * listener was unregistered due to not picking up its event.
1144 * This overlaps with XPCOM specific use of E_ABORT to signal
1145 * death of an active listener, but that's irrelevant here. */
1146 if (FAILED_DEAD_INTERFACE(cbRc) || cbRc == E_ABORT)
1147 {
1148 Listeners::iterator lit = m->mListeners.find(record.obj()->mListener);
1149 if (lit != m->mListeners.end())
1150 {
1151 lit->second.obj()->shutdown();
1152 m->mListeners.erase(lit);
1153 }
1154 }
1155 // anything else to do with cbRc?
1156 }
1157 } while (0);
1158 /* We leave the lock here */
1159
1160 if (aWaitable)
1161 hrc = aEvent->WaitProcessed(aTimeout, aResult);
1162 else
1163 *aResult = TRUE;
1164
1165 return hrc;
1166}
1167
1168HRESULT EventSource::getEvent(const ComPtr<IEventListener> &aListener,
1169 LONG aTimeout,
1170 ComPtr<IEvent> &aEvent)
1171{
1172 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1173
1174 if (m->fShutdown)
1175 return setError(VBOX_E_INVALID_OBJECT_STATE,
1176 tr("This event source is already shut down"));
1177
1178 Listeners::iterator it = m->mListeners.find(aListener);
1179 HRESULT rc = S_OK;
1180
1181 if (it != m->mListeners.end())
1182 rc = it->second.obj()->dequeue(aEvent.asOutParam(), aTimeout, alock);
1183 else
1184 rc = setError(VBOX_E_OBJECT_NOT_FOUND,
1185 tr("Listener was never registered"));
1186
1187 if (rc == VBOX_E_INVALID_OBJECT_STATE)
1188 return setError(rc, tr("Listener must be passive"));
1189
1190 return rc;
1191}
1192
1193HRESULT EventSource::eventProcessed(const ComPtr<IEventListener> &aListener,
1194 const ComPtr<IEvent> &aEvent)
1195{
1196 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1197
1198 if (m->fShutdown)
1199 return setError(VBOX_E_INVALID_OBJECT_STATE,
1200 tr("This event source is already shut down"));
1201
1202 Listeners::iterator it = m->mListeners.find(aListener);
1203 HRESULT rc;
1204
1205 BOOL aWaitable = FALSE;
1206 aEvent->COMGETTER(Waitable)(&aWaitable);
1207
1208 if (it != m->mListeners.end())
1209 {
1210 ListenerRecord *aRecord = it->second.obj();
1211
1212 if (aRecord->isActive())
1213 return setError(E_INVALIDARG,
1214 tr("Only applicable to passive listeners"));
1215
1216 if (aWaitable)
1217 {
1218 PendingEventsMap::iterator pit = m->mPendingMap.find(aEvent);
1219
1220 if (pit == m->mPendingMap.end())
1221 {
1222 AssertFailed();
1223 rc = setError(VBOX_E_OBJECT_NOT_FOUND,
1224 tr("Unknown event"));
1225 }
1226 else
1227 rc = aRecord->eventProcessed(aEvent, pit);
1228 }
1229 else
1230 {
1231 // for non-waitable events we're done
1232 rc = S_OK;
1233 }
1234 }
1235 else
1236 {
1237 rc = setError(VBOX_E_OBJECT_NOT_FOUND,
1238 tr("Listener was never registered"));
1239 }
1240
1241 return rc;
1242}
1243
1244/**
1245 * This class serves as feasible listener implementation
1246 * which could be used by clients not able to create local
1247 * COM objects, but still willing to receive event
1248 * notifications in passive mode, such as webservices.
1249 */
1250class ATL_NO_VTABLE PassiveEventListener :
1251 public VirtualBoxBase,
1252 VBOX_SCRIPTABLE_IMPL(IEventListener)
1253{
1254public:
1255
1256 VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(PassiveEventListener, IEventListener)
1257
1258 DECLARE_NOT_AGGREGATABLE(PassiveEventListener)
1259
1260 DECLARE_PROTECT_FINAL_CONSTRUCT()
1261
1262 BEGIN_COM_MAP(PassiveEventListener)
1263 COM_INTERFACE_ENTRY(ISupportErrorInfo)
1264 COM_INTERFACE_ENTRY(IEventListener)
1265 COM_INTERFACE_ENTRY2(IDispatch, IEventListener)
1266 VBOX_TWEAK_INTERFACE_ENTRY(IEventListener)
1267 END_COM_MAP()
1268
1269 PassiveEventListener()
1270 {}
1271 ~PassiveEventListener()
1272 {}
1273
1274 HRESULT FinalConstruct()
1275 {
1276 return BaseFinalConstruct();
1277 }
1278 void FinalRelease()
1279 {
1280 BaseFinalRelease();
1281 }
1282
1283 // IEventListener methods
1284 STDMETHOD(HandleEvent)(IEvent *)
1285 {
1286 ComAssertMsgRet(false, ("HandleEvent() of wrapper shall never be called"),
1287 E_FAIL);
1288 }
1289};
1290
1291/* Proxy listener class, used to aggregate multiple event sources into one */
1292class ATL_NO_VTABLE ProxyEventListener :
1293 public VirtualBoxBase,
1294 VBOX_SCRIPTABLE_IMPL(IEventListener)
1295{
1296 ComPtr<IEventSource> mSource;
1297public:
1298
1299 VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(ProxyEventListener, IEventListener)
1300
1301 DECLARE_NOT_AGGREGATABLE(ProxyEventListener)
1302
1303 DECLARE_PROTECT_FINAL_CONSTRUCT()
1304
1305 BEGIN_COM_MAP(ProxyEventListener)
1306 COM_INTERFACE_ENTRY(ISupportErrorInfo)
1307 COM_INTERFACE_ENTRY(IEventListener)
1308 COM_INTERFACE_ENTRY2(IDispatch, IEventListener)
1309 VBOX_TWEAK_INTERFACE_ENTRY(IEventListener)
1310 END_COM_MAP()
1311
1312 ProxyEventListener()
1313 {}
1314 ~ProxyEventListener()
1315 {}
1316
1317 HRESULT FinalConstruct()
1318 {
1319 return BaseFinalConstruct();
1320 }
1321 void FinalRelease()
1322 {
1323 BaseFinalRelease();
1324 }
1325
1326 HRESULT init(IEventSource *aSource)
1327 {
1328 mSource = aSource;
1329 return S_OK;
1330 }
1331
1332 // IEventListener methods
1333 STDMETHOD(HandleEvent)(IEvent *aEvent)
1334 {
1335 BOOL fProcessed = FALSE;
1336 if (mSource)
1337 return mSource->FireEvent(aEvent, 0, &fProcessed);
1338 else
1339 return S_OK;
1340 }
1341};
1342
1343class ATL_NO_VTABLE EventSourceAggregator :
1344 public VirtualBoxBase,
1345 VBOX_SCRIPTABLE_IMPL(IEventSource)
1346{
1347 typedef std::list <ComPtr<IEventSource> > EventSourceList;
1348 /* key is weak reference */
1349 typedef std::map<IEventListener *, ComPtr<IEventListener> > ProxyListenerMap;
1350
1351 EventSourceList mEventSources;
1352 ProxyListenerMap mListenerProxies;
1353 ComObjPtr<EventSource> mSource;
1354
1355public:
1356
1357 VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(EventSourceAggregator, IEventSource)
1358
1359 DECLARE_NOT_AGGREGATABLE(EventSourceAggregator)
1360
1361 DECLARE_PROTECT_FINAL_CONSTRUCT()
1362
1363 BEGIN_COM_MAP(EventSourceAggregator)
1364 COM_INTERFACE_ENTRY(ISupportErrorInfo)
1365 COM_INTERFACE_ENTRY(IEventSource)
1366 COM_INTERFACE_ENTRY2(IDispatch, IEventSource)
1367 VBOX_TWEAK_INTERFACE_ENTRY(IEventSource)
1368 END_COM_MAP()
1369
1370 EventSourceAggregator()
1371 {}
1372 ~EventSourceAggregator()
1373 {}
1374
1375 HRESULT FinalConstruct()
1376 {
1377 return BaseFinalConstruct();
1378 }
1379 void FinalRelease()
1380 {
1381 mEventSources.clear();
1382 mListenerProxies.clear();
1383 mSource->uninit();
1384 BaseFinalRelease();
1385 }
1386
1387 // internal public
1388 HRESULT init(const std::vector<ComPtr<IEventSource> > aSourcesIn);
1389
1390 // IEventSource methods
1391 STDMETHOD(CreateListener)(IEventListener **aListener);
1392 STDMETHOD(CreateAggregator)(ComSafeArrayIn(IEventSource *, aSubordinates),
1393 IEventSource **aAggregator);
1394 STDMETHOD(RegisterListener)(IEventListener *aListener,
1395 ComSafeArrayIn(VBoxEventType_T, aInterested),
1396 BOOL aActive);
1397 STDMETHOD(UnregisterListener)(IEventListener *aListener);
1398 STDMETHOD(FireEvent)(IEvent *aEvent,
1399 LONG aTimeout,
1400 BOOL *aProcessed);
1401 STDMETHOD(GetEvent)(IEventListener *aListener,
1402 LONG aTimeout,
1403 IEvent **aEvent);
1404 STDMETHOD(EventProcessed)(IEventListener *aListener,
1405 IEvent *aEvent);
1406
1407 protected:
1408 HRESULT createProxyListener(IEventListener *aListener,
1409 IEventListener **aProxy);
1410 HRESULT getProxyListener(IEventListener *aListener,
1411 IEventListener **aProxy);
1412 HRESULT removeProxyListener(IEventListener *aListener);
1413};
1414
1415#ifdef VBOX_WITH_XPCOM
1416NS_DECL_CLASSINFO(ProxyEventListener)
1417NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ProxyEventListener, IEventListener)
1418NS_DECL_CLASSINFO(PassiveEventListener)
1419NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PassiveEventListener, IEventListener)
1420NS_DECL_CLASSINFO(EventSourceAggregator)
1421NS_IMPL_THREADSAFE_ISUPPORTS1_CI(EventSourceAggregator, IEventSource)
1422#endif
1423
1424
1425HRESULT EventSource::createListener(ComPtr<IEventListener> &aListener)
1426{
1427 ComObjPtr<PassiveEventListener> listener;
1428
1429 HRESULT rc = listener.createObject();
1430 ComAssertMsgRet(SUCCEEDED(rc), ("Could not create wrapper object (%Rhrc)", rc),
1431 E_FAIL);
1432 listener.queryInterfaceTo(aListener.asOutParam());
1433 return S_OK;
1434}
1435
1436HRESULT EventSource::createAggregator(const std::vector<ComPtr<IEventSource> > &aSubordinates,
1437 ComPtr<IEventSource> &aResult)
1438{
1439 ComObjPtr<EventSourceAggregator> agg;
1440
1441 HRESULT rc = agg.createObject();
1442 ComAssertMsgRet(SUCCEEDED(rc), ("Could not create aggregator (%Rhrc)", rc),
1443 E_FAIL);
1444
1445 rc = agg->init(aSubordinates);
1446 if (FAILED(rc))
1447 return rc;
1448
1449 agg.queryInterfaceTo(aResult.asOutParam());
1450 return S_OK;
1451}
1452
1453HRESULT EventSourceAggregator::init(const std::vector<ComPtr<IEventSource> > aSourcesIn)
1454{
1455 HRESULT rc;
1456
1457 AutoInitSpan autoInitSpan(this);
1458 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1459
1460 rc = mSource.createObject();
1461 ComAssertMsgRet(SUCCEEDED(rc), ("Could not create source (%Rhrc)", rc),
1462 E_FAIL);
1463 rc = mSource->init();
1464 ComAssertMsgRet(SUCCEEDED(rc), ("Could not init source (%Rhrc)", rc),
1465 E_FAIL);
1466
1467 for (size_t i = 0; i < aSourcesIn.size(); i++)
1468 {
1469 if (aSourcesIn[i] != NULL)
1470 mEventSources.push_back(aSourcesIn[i]);
1471 }
1472
1473 /* Confirm a successful initialization */
1474 autoInitSpan.setSucceeded();
1475
1476 return rc;
1477}
1478
1479STDMETHODIMP EventSourceAggregator::CreateListener(IEventListener **aListener)
1480{
1481 return mSource->CreateListener(aListener);
1482}
1483
1484STDMETHODIMP EventSourceAggregator::CreateAggregator(ComSafeArrayIn(IEventSource *, aSubordinates),
1485 IEventSource **aResult)
1486{
1487 return mSource->CreateAggregator(ComSafeArrayInArg(aSubordinates), aResult);
1488}
1489
1490STDMETHODIMP EventSourceAggregator::RegisterListener(IEventListener *aListener,
1491 ComSafeArrayIn(VBoxEventType_T, aInterested),
1492 BOOL aActive)
1493{
1494 CheckComArgNotNull(aListener);
1495 CheckComArgSafeArrayNotNull(aInterested);
1496
1497 AutoCaller autoCaller(this);
1498 if (FAILED(autoCaller.rc()))
1499 return autoCaller.rc();
1500
1501 HRESULT rc;
1502
1503 ComPtr<IEventListener> proxy;
1504 rc = createProxyListener(aListener, proxy.asOutParam());
1505 if (FAILED(rc))
1506 return rc;
1507
1508 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1509 for (EventSourceList::const_iterator it = mEventSources.begin(); it != mEventSources.end();
1510 ++it)
1511 {
1512 ComPtr<IEventSource> es = *it;
1513 /* Register active proxy listener on real event source */
1514 rc = es->RegisterListener(proxy, ComSafeArrayInArg(aInterested), TRUE);
1515 }
1516 /* And add real listener on our event source */
1517 rc = mSource->RegisterListener(aListener, ComSafeArrayInArg(aInterested), aActive);
1518
1519 rc = S_OK;
1520
1521 return rc;
1522}
1523
1524STDMETHODIMP EventSourceAggregator::UnregisterListener(IEventListener *aListener)
1525{
1526 CheckComArgNotNull(aListener);
1527
1528 AutoCaller autoCaller(this);
1529 if (FAILED(autoCaller.rc()))
1530 return autoCaller.rc();
1531
1532 HRESULT rc = S_OK;
1533
1534 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1535
1536 ComPtr<IEventListener> proxy;
1537 rc = getProxyListener(aListener, proxy.asOutParam());
1538 if (FAILED(rc))
1539 return rc;
1540
1541 for (EventSourceList::const_iterator it = mEventSources.begin(); it != mEventSources.end();
1542 ++it)
1543 {
1544 ComPtr<IEventSource> es = *it;
1545 rc = es->UnregisterListener(proxy);
1546 }
1547 rc = mSource->UnregisterListener(aListener);
1548
1549 return removeProxyListener(aListener);
1550
1551}
1552
1553STDMETHODIMP EventSourceAggregator::FireEvent(IEvent *aEvent,
1554 LONG aTimeout,
1555 BOOL *aProcessed)
1556{
1557 CheckComArgNotNull(aEvent);
1558 CheckComArgOutPointerValid(aProcessed);
1559
1560 AutoCaller autoCaller(this);
1561 if (FAILED(autoCaller.rc()))
1562 return autoCaller.rc();
1563
1564 HRESULT rc = S_OK;
1565 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1566 /* Aggregator event source shall not have direct event firing, but we may
1567 wish to support aggregation chains */
1568 for (EventSourceList::const_iterator it = mEventSources.begin(); it != mEventSources.end();
1569 ++it)
1570 {
1571 ComPtr<IEventSource> es = *it;
1572 rc = es->FireEvent(aEvent, aTimeout, aProcessed);
1573 /* Current behavior is that aggregator's FireEvent() always succeeds,
1574 so that multiple event sources don't affect each other. */
1575 NOREF(rc);
1576 }
1577
1578 return S_OK;
1579}
1580
1581STDMETHODIMP EventSourceAggregator::GetEvent(IEventListener *aListener,
1582 LONG aTimeout,
1583 IEvent **aEvent)
1584{
1585 return mSource->GetEvent(aListener, aTimeout, aEvent);
1586}
1587
1588STDMETHODIMP EventSourceAggregator::EventProcessed(IEventListener *aListener,
1589 IEvent *aEvent)
1590{
1591 return mSource->EventProcessed(aListener, aEvent);
1592}
1593
1594HRESULT EventSourceAggregator::createProxyListener(IEventListener *aListener,
1595 IEventListener **aProxy)
1596{
1597 ComObjPtr<ProxyEventListener> proxy;
1598
1599 HRESULT rc = proxy.createObject();
1600 ComAssertMsgRet(SUCCEEDED(rc), ("Could not create proxy (%Rhrc)", rc),
1601 E_FAIL);
1602
1603 rc = proxy->init(mSource);
1604 if (FAILED(rc))
1605 return rc;
1606
1607 ProxyListenerMap::const_iterator it = mListenerProxies.find(aListener);
1608 if (it != mListenerProxies.end())
1609 return setError(E_INVALIDARG,
1610 tr("This listener already registered"));
1611
1612 mListenerProxies.insert(ProxyListenerMap::value_type(aListener, proxy));
1613
1614 proxy.queryInterfaceTo(aProxy);
1615 return S_OK;
1616}
1617
1618HRESULT EventSourceAggregator::getProxyListener(IEventListener *aListener,
1619 IEventListener **aProxy)
1620{
1621 ProxyListenerMap::const_iterator it = mListenerProxies.find(aListener);
1622 if (it == mListenerProxies.end())
1623 return setError(E_INVALIDARG,
1624 tr("This listener never registered"));
1625
1626 (*it).second.queryInterfaceTo(aProxy);
1627 return S_OK;
1628}
1629
1630HRESULT EventSourceAggregator::removeProxyListener(IEventListener *aListener)
1631{
1632 ProxyListenerMap::iterator it = mListenerProxies.find(aListener);
1633 if (it == mListenerProxies.end())
1634 return setError(E_INVALIDARG,
1635 tr("This listener never registered"));
1636
1637 mListenerProxies.erase(it);
1638 return S_OK;
1639}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette