VirtualBox

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

Last change on this file since 69498 was 69498, checked in by vboxsync, 7 years ago

backed out r118835 as it incorrectly updated the 'This file is based on' file headers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.6 KB
Line 
1/* $Id: EventImpl.cpp 69498 2017-10-28 15:07:25Z 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 const mActive;
601 EventSource *mOwner;
602
603 RTSEMEVENT mQEvent;
604 int32_t volatile mQEventBusyCnt;
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), mQEventBusyCnt(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 LogRel(("Event: forcefully unregistering passive event listener %p due to excessive queue size\n", this));
865 return E_ABORT;
866 }
867
868
869 RTSEMEVENT hEvt = mQEvent;
870 if (queueSize != 0 && mQueue.back() == aEvent)
871 /* if same event is being pushed multiple times - it's reusable event and
872 we don't really need multiple instances of it in the queue */
873 hEvt = NIL_RTSEMEVENT;
874 else if (hEvt != NIL_RTSEMEVENT) /* don't bother queuing after shutdown */
875 {
876 mQueue.push_back(aEvent);
877 ASMAtomicIncS32(&mQEventBusyCnt);
878 }
879
880 ::RTCritSectLeave(&mcsQLock);
881
882 // notify waiters unless we've been shut down.
883 if (hEvt != NIL_RTSEMEVENT)
884 {
885 ::RTSemEventSignal(hEvt);
886 ASMAtomicDecS32(&mQEventBusyCnt);
887 }
888
889 return S_OK;
890}
891
892HRESULT ListenerRecord::dequeue(IEvent **aEvent,
893 LONG aTimeout,
894 AutoLockBase &aAlock)
895{
896 if (mActive)
897 return VBOX_E_INVALID_OBJECT_STATE;
898
899 // retain listener record
900 RecordHolder<ListenerRecord> holder(this);
901
902 ::RTCritSectEnter(&mcsQLock);
903
904 mLastRead = RTTimeMilliTS();
905
906 /*
907 * If waiting both desired and necessary, then try grab the event
908 * semaphore and mark it busy. If it's NIL we've been shut down already.
909 */
910 if (aTimeout != 0 && mQueue.empty())
911 {
912 RTSEMEVENT hEvt = mQEvent;
913 if (hEvt != NIL_RTSEMEVENT)
914 {
915 ASMAtomicIncS32(&mQEventBusyCnt);
916 ::RTCritSectLeave(&mcsQLock);
917
918 // release lock while waiting, listener will not go away due to above holder
919 aAlock.release();
920
921 ::RTSemEventWait(hEvt, aTimeout);
922 ASMAtomicDecS32(&mQEventBusyCnt);
923
924 // reacquire lock
925 aAlock.acquire();
926 ::RTCritSectEnter(&mcsQLock);
927 }
928 }
929
930 if (mQueue.empty())
931 *aEvent = NULL;
932 else
933 {
934 mQueue.front().queryInterfaceTo(aEvent);
935 mQueue.pop_front();
936 }
937
938 ::RTCritSectLeave(&mcsQLock);
939 return S_OK;
940}
941
942HRESULT ListenerRecord::eventProcessed(IEvent *aEvent, PendingEventsMap::iterator &pit)
943{
944 if (--pit->second == 0)
945 {
946 Assert(pit->first == aEvent);
947 aEvent->SetProcessed();
948 mOwner->m->mPendingMap.erase(pit);
949 }
950
951 return S_OK;
952}
953
954void ListenerRecord::shutdown()
955{
956 if (mQEvent != NIL_RTSEMEVENT)
957 {
958 /* Grab the event semaphore. Must do this while owning the CS or we'll
959 be racing user wanting to use the handle. */
960 ::RTCritSectEnter(&mcsQLock);
961 RTSEMEVENT hEvt = mQEvent;
962 mQEvent = NIL_RTSEMEVENT;
963 ::RTCritSectLeave(&mcsQLock);
964
965 /*
966 * Signal waiters and wait for them and any other signallers to stop using the sempahore.
967 *
968 * Note! RTSemEventDestroy does not necessarily guarantee that waiting threads are
969 * out of RTSemEventWait or even woken up when it returns. Darwin is (or was?)
970 * an example of this, the result was undesirable freezes on shutdown.
971 */
972 int32_t cBusy = ASMAtomicReadS32(&mQEventBusyCnt);
973 if (cBusy > 0)
974 {
975 Log(("Wait for %d waiters+signalers to release.\n", cBusy));
976 while (cBusy-- > 0)
977 ::RTSemEventSignal(hEvt);
978
979 for (uint32_t cLoops = 0;; cLoops++)
980 {
981 RTThreadSleep(RT_MIN(8, cLoops));
982 if (ASMAtomicReadS32(&mQEventBusyCnt) <= 0)
983 break;
984 ::RTSemEventSignal(hEvt); /* (Technically unnecessary, but just in case.) */
985 }
986 Log(("All waiters+signalers just released the lock.\n"));
987 }
988
989 ::RTSemEventDestroy(hEvt);
990 }
991}
992
993EventSource::EventSource()
994{}
995
996EventSource::~EventSource()
997{}
998
999HRESULT EventSource::FinalConstruct()
1000{
1001 m = new Data;
1002 return BaseFinalConstruct();
1003}
1004
1005void EventSource::FinalRelease()
1006{
1007 uninit();
1008 delete m;
1009 BaseFinalRelease();
1010}
1011
1012HRESULT EventSource::init()
1013{
1014 HRESULT rc = S_OK;
1015
1016 AutoInitSpan autoInitSpan(this);
1017 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1018
1019 /* Confirm a successful initialization */
1020 autoInitSpan.setSucceeded();
1021 return rc;
1022}
1023
1024void EventSource::uninit()
1025{
1026 {
1027 // First of all (before even thinking about entering the uninit span):
1028 // make sure that all listeners are are shut down (no pending events or
1029 // wait calls), because they cannot be alive without the associated
1030 // event source. Otherwise API clients which use long-term (or
1031 // indefinite) waits will block VBoxSVC termination (just one example)
1032 // for a long time or even infinitely long.
1033 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1034 if (!m->fShutdown)
1035 {
1036 m->fShutdown = true;
1037 for (Listeners::iterator it = m->mListeners.begin();
1038 it != m->mListeners.end();
1039 ++it)
1040 {
1041 it->second.obj()->shutdown();
1042 }
1043 }
1044 }
1045
1046 AutoUninitSpan autoUninitSpan(this);
1047 if (autoUninitSpan.uninitDone())
1048 return;
1049
1050 m->mListeners.clear();
1051 // m->mEvMap shall be cleared at this point too by destructors, assert?
1052}
1053
1054HRESULT EventSource::registerListener(const ComPtr<IEventListener> &aListener,
1055 const std::vector<VBoxEventType_T> &aInteresting,
1056 BOOL aActive)
1057{
1058 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1059
1060 if (m->fShutdown)
1061 return setError(VBOX_E_INVALID_OBJECT_STATE,
1062 tr("This event source is already shut down"));
1063
1064 Listeners::const_iterator it = m->mListeners.find(aListener);
1065 if (it != m->mListeners.end())
1066 return setError(E_INVALIDARG,
1067 tr("This listener already registered"));
1068
1069 com::SafeArray<VBoxEventType_T> interested(aInteresting);
1070 RecordHolder<ListenerRecord> lrh(new ListenerRecord(aListener, interested, aActive, this));
1071 m->mListeners.insert(Listeners::value_type((IEventListener *)aListener, lrh));
1072
1073 VBoxEventDesc evDesc;
1074 evDesc.init(this, VBoxEventType_OnEventSourceChanged, (IEventListener *)aListener, TRUE);
1075 evDesc.fire(0);
1076
1077 return S_OK;
1078}
1079
1080HRESULT EventSource::unregisterListener(const ComPtr<IEventListener> &aListener)
1081{
1082 HRESULT rc = S_OK;;
1083
1084 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1085
1086 Listeners::iterator it = m->mListeners.find(aListener);
1087
1088 if (it != m->mListeners.end())
1089 {
1090 it->second.obj()->shutdown();
1091 m->mListeners.erase(it);
1092 // destructor removes refs from the event map
1093 rc = S_OK;
1094 }
1095 else
1096 {
1097 rc = setError(VBOX_E_OBJECT_NOT_FOUND,
1098 tr("Listener was never registered"));
1099 }
1100
1101 if (SUCCEEDED(rc))
1102 {
1103 VBoxEventDesc evDesc;
1104 evDesc.init(this, VBoxEventType_OnEventSourceChanged, (IEventListener *)aListener, FALSE);
1105 evDesc.fire(0);
1106 }
1107
1108 return rc;
1109}
1110
1111HRESULT EventSource::fireEvent(const ComPtr<IEvent> &aEvent,
1112 LONG aTimeout,
1113 BOOL *aResult)
1114{
1115
1116 HRESULT hrc = S_OK;
1117 BOOL aWaitable = FALSE;
1118 aEvent->COMGETTER(Waitable)(&aWaitable);
1119
1120 do {
1121 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1122
1123 if (m->fShutdown)
1124 return setError(VBOX_E_INVALID_OBJECT_STATE,
1125 tr("This event source is already shut down"));
1126
1127 VBoxEventType_T evType;
1128 hrc = aEvent->COMGETTER(Type)(&evType);
1129 AssertComRCReturn(hrc, hrc);
1130
1131 EventMapList &listeners = m->mEvMap[(int)evType - FirstEvent];
1132
1133 /* Anyone interested in this event? */
1134 uint32_t cListeners = listeners.size();
1135 if (cListeners == 0)
1136 {
1137 aEvent->SetProcessed();
1138 break; // just leave the lock and update event object state
1139 }
1140
1141 PendingEventsMap::iterator pit;
1142
1143 if (aWaitable)
1144 {
1145 m->mPendingMap.insert(PendingEventsMap::value_type(aEvent, cListeners));
1146 // we keep iterator here to allow processing active listeners without
1147 // pending events lookup
1148 pit = m->mPendingMap.find(aEvent);
1149 }
1150 for (EventMapList::iterator it = listeners.begin();
1151 it != listeners.end();
1152 ++it)
1153 {
1154 HRESULT cbRc;
1155 // keep listener record reference, in case someone will remove it while in callback
1156 RecordHolder<ListenerRecord> record(*it);
1157
1158 /*
1159 * We pass lock here to allow modifying ops on EventSource inside callback
1160 * in active mode. Note that we expect list iterator stability as 'alock'
1161 * could be temporary released when calling event handler.
1162 */
1163 cbRc = record.obj()->process(aEvent, aWaitable, pit, alock);
1164
1165 /* Note that E_ABORT is used above to signal that a passive
1166 * listener was unregistered due to not picking up its event.
1167 * This overlaps with XPCOM specific use of E_ABORT to signal
1168 * death of an active listener, but that's irrelevant here. */
1169 if (FAILED_DEAD_INTERFACE(cbRc) || cbRc == E_ABORT)
1170 {
1171 Listeners::iterator lit = m->mListeners.find(record.obj()->mListener);
1172 if (lit != m->mListeners.end())
1173 {
1174 lit->second.obj()->shutdown();
1175 m->mListeners.erase(lit);
1176 }
1177 }
1178 // anything else to do with cbRc?
1179 }
1180 } while (0);
1181 /* We leave the lock here */
1182
1183 if (aWaitable)
1184 hrc = aEvent->WaitProcessed(aTimeout, aResult);
1185 else
1186 *aResult = TRUE;
1187
1188 return hrc;
1189}
1190
1191HRESULT EventSource::getEvent(const ComPtr<IEventListener> &aListener,
1192 LONG aTimeout,
1193 ComPtr<IEvent> &aEvent)
1194{
1195 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1196
1197 if (m->fShutdown)
1198 return setError(VBOX_E_INVALID_OBJECT_STATE,
1199 tr("This event source is already shut down"));
1200
1201 Listeners::iterator it = m->mListeners.find(aListener);
1202 HRESULT rc = S_OK;
1203
1204 if (it != m->mListeners.end())
1205 rc = it->second.obj()->dequeue(aEvent.asOutParam(), aTimeout, alock);
1206 else
1207 rc = setError(VBOX_E_OBJECT_NOT_FOUND,
1208 tr("Listener was never registered"));
1209
1210 if (rc == VBOX_E_INVALID_OBJECT_STATE)
1211 return setError(rc, tr("Listener must be passive"));
1212
1213 return rc;
1214}
1215
1216HRESULT EventSource::eventProcessed(const ComPtr<IEventListener> &aListener,
1217 const ComPtr<IEvent> &aEvent)
1218{
1219 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1220
1221 if (m->fShutdown)
1222 return setError(VBOX_E_INVALID_OBJECT_STATE,
1223 tr("This event source is already shut down"));
1224
1225 Listeners::iterator it = m->mListeners.find(aListener);
1226 HRESULT rc;
1227
1228 BOOL aWaitable = FALSE;
1229 aEvent->COMGETTER(Waitable)(&aWaitable);
1230
1231 if (it != m->mListeners.end())
1232 {
1233 ListenerRecord *aRecord = it->second.obj();
1234
1235 if (aRecord->isActive())
1236 return setError(E_INVALIDARG,
1237 tr("Only applicable to passive listeners"));
1238
1239 if (aWaitable)
1240 {
1241 PendingEventsMap::iterator pit = m->mPendingMap.find(aEvent);
1242
1243 if (pit == m->mPendingMap.end())
1244 {
1245 AssertFailed();
1246 rc = setError(VBOX_E_OBJECT_NOT_FOUND,
1247 tr("Unknown event"));
1248 }
1249 else
1250 rc = aRecord->eventProcessed(aEvent, pit);
1251 }
1252 else
1253 {
1254 // for non-waitable events we're done
1255 rc = S_OK;
1256 }
1257 }
1258 else
1259 {
1260 rc = setError(VBOX_E_OBJECT_NOT_FOUND,
1261 tr("Listener was never registered"));
1262 }
1263
1264 return rc;
1265}
1266
1267/**
1268 * This class serves as feasible listener implementation
1269 * which could be used by clients not able to create local
1270 * COM objects, but still willing to receive event
1271 * notifications in passive mode, such as webservices.
1272 */
1273class ATL_NO_VTABLE PassiveEventListener :
1274 public VirtualBoxBase,
1275 VBOX_SCRIPTABLE_IMPL(IEventListener)
1276{
1277public:
1278
1279 VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(PassiveEventListener, IEventListener)
1280
1281 DECLARE_NOT_AGGREGATABLE(PassiveEventListener)
1282
1283 DECLARE_PROTECT_FINAL_CONSTRUCT()
1284
1285 BEGIN_COM_MAP(PassiveEventListener)
1286 COM_INTERFACE_ENTRY(ISupportErrorInfo)
1287 COM_INTERFACE_ENTRY(IEventListener)
1288 COM_INTERFACE_ENTRY2(IDispatch, IEventListener)
1289 VBOX_TWEAK_INTERFACE_ENTRY(IEventListener)
1290 END_COM_MAP()
1291
1292 PassiveEventListener()
1293 {}
1294 ~PassiveEventListener()
1295 {}
1296
1297 HRESULT FinalConstruct()
1298 {
1299 return BaseFinalConstruct();
1300 }
1301 void FinalRelease()
1302 {
1303 BaseFinalRelease();
1304 }
1305
1306 // IEventListener methods
1307 STDMETHOD(HandleEvent)(IEvent *)
1308 {
1309 ComAssertMsgRet(false, ("HandleEvent() of wrapper shall never be called"),
1310 E_FAIL);
1311 }
1312};
1313
1314/* Proxy listener class, used to aggregate multiple event sources into one */
1315class ATL_NO_VTABLE ProxyEventListener :
1316 public VirtualBoxBase,
1317 VBOX_SCRIPTABLE_IMPL(IEventListener)
1318{
1319 ComPtr<IEventSource> mSource;
1320public:
1321
1322 VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(ProxyEventListener, IEventListener)
1323
1324 DECLARE_NOT_AGGREGATABLE(ProxyEventListener)
1325
1326 DECLARE_PROTECT_FINAL_CONSTRUCT()
1327
1328 BEGIN_COM_MAP(ProxyEventListener)
1329 COM_INTERFACE_ENTRY(ISupportErrorInfo)
1330 COM_INTERFACE_ENTRY(IEventListener)
1331 COM_INTERFACE_ENTRY2(IDispatch, IEventListener)
1332 VBOX_TWEAK_INTERFACE_ENTRY(IEventListener)
1333 END_COM_MAP()
1334
1335 ProxyEventListener()
1336 {}
1337 ~ProxyEventListener()
1338 {}
1339
1340 HRESULT FinalConstruct()
1341 {
1342 return BaseFinalConstruct();
1343 }
1344 void FinalRelease()
1345 {
1346 BaseFinalRelease();
1347 }
1348
1349 HRESULT init(IEventSource *aSource)
1350 {
1351 mSource = aSource;
1352 return S_OK;
1353 }
1354
1355 // IEventListener methods
1356 STDMETHOD(HandleEvent)(IEvent *aEvent)
1357 {
1358 BOOL fProcessed = FALSE;
1359 if (mSource)
1360 return mSource->FireEvent(aEvent, 0, &fProcessed);
1361 else
1362 return S_OK;
1363 }
1364};
1365
1366class ATL_NO_VTABLE EventSourceAggregator :
1367 public VirtualBoxBase,
1368 VBOX_SCRIPTABLE_IMPL(IEventSource)
1369{
1370 typedef std::list <ComPtr<IEventSource> > EventSourceList;
1371 /* key is weak reference */
1372 typedef std::map<IEventListener *, ComPtr<IEventListener> > ProxyListenerMap;
1373
1374 EventSourceList mEventSources;
1375 ProxyListenerMap mListenerProxies;
1376 ComObjPtr<EventSource> mSource;
1377
1378public:
1379
1380 VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(EventSourceAggregator, IEventSource)
1381
1382 DECLARE_NOT_AGGREGATABLE(EventSourceAggregator)
1383
1384 DECLARE_PROTECT_FINAL_CONSTRUCT()
1385
1386 BEGIN_COM_MAP(EventSourceAggregator)
1387 COM_INTERFACE_ENTRY(ISupportErrorInfo)
1388 COM_INTERFACE_ENTRY(IEventSource)
1389 COM_INTERFACE_ENTRY2(IDispatch, IEventSource)
1390 VBOX_TWEAK_INTERFACE_ENTRY(IEventSource)
1391 END_COM_MAP()
1392
1393 EventSourceAggregator()
1394 {}
1395 ~EventSourceAggregator()
1396 {}
1397
1398 HRESULT FinalConstruct()
1399 {
1400 return BaseFinalConstruct();
1401 }
1402 void FinalRelease()
1403 {
1404 mEventSources.clear();
1405 mListenerProxies.clear();
1406 mSource->uninit();
1407 BaseFinalRelease();
1408 }
1409
1410 // internal public
1411 HRESULT init(const std::vector<ComPtr<IEventSource> > aSourcesIn);
1412
1413 // IEventSource methods
1414 STDMETHOD(CreateListener)(IEventListener **aListener);
1415 STDMETHOD(CreateAggregator)(ComSafeArrayIn(IEventSource *, aSubordinates),
1416 IEventSource **aAggregator);
1417 STDMETHOD(RegisterListener)(IEventListener *aListener,
1418 ComSafeArrayIn(VBoxEventType_T, aInterested),
1419 BOOL aActive);
1420 STDMETHOD(UnregisterListener)(IEventListener *aListener);
1421 STDMETHOD(FireEvent)(IEvent *aEvent,
1422 LONG aTimeout,
1423 BOOL *aProcessed);
1424 STDMETHOD(GetEvent)(IEventListener *aListener,
1425 LONG aTimeout,
1426 IEvent **aEvent);
1427 STDMETHOD(EventProcessed)(IEventListener *aListener,
1428 IEvent *aEvent);
1429
1430 protected:
1431 HRESULT createProxyListener(IEventListener *aListener,
1432 IEventListener **aProxy);
1433 HRESULT getProxyListener(IEventListener *aListener,
1434 IEventListener **aProxy);
1435 HRESULT removeProxyListener(IEventListener *aListener);
1436};
1437
1438#ifdef VBOX_WITH_XPCOM
1439NS_DECL_CLASSINFO(ProxyEventListener)
1440NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ProxyEventListener, IEventListener)
1441NS_DECL_CLASSINFO(PassiveEventListener)
1442NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PassiveEventListener, IEventListener)
1443NS_DECL_CLASSINFO(EventSourceAggregator)
1444NS_IMPL_THREADSAFE_ISUPPORTS1_CI(EventSourceAggregator, IEventSource)
1445#endif
1446
1447
1448HRESULT EventSource::createListener(ComPtr<IEventListener> &aListener)
1449{
1450 ComObjPtr<PassiveEventListener> listener;
1451
1452 HRESULT rc = listener.createObject();
1453 ComAssertMsgRet(SUCCEEDED(rc), ("Could not create wrapper object (%Rhrc)", rc),
1454 E_FAIL);
1455 listener.queryInterfaceTo(aListener.asOutParam());
1456 return S_OK;
1457}
1458
1459HRESULT EventSource::createAggregator(const std::vector<ComPtr<IEventSource> > &aSubordinates,
1460 ComPtr<IEventSource> &aResult)
1461{
1462 ComObjPtr<EventSourceAggregator> agg;
1463
1464 HRESULT rc = agg.createObject();
1465 ComAssertMsgRet(SUCCEEDED(rc), ("Could not create aggregator (%Rhrc)", rc),
1466 E_FAIL);
1467
1468 rc = agg->init(aSubordinates);
1469 if (FAILED(rc))
1470 return rc;
1471
1472 agg.queryInterfaceTo(aResult.asOutParam());
1473 return S_OK;
1474}
1475
1476HRESULT EventSourceAggregator::init(const std::vector<ComPtr<IEventSource> > aSourcesIn)
1477{
1478 HRESULT rc;
1479
1480 AutoInitSpan autoInitSpan(this);
1481 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1482
1483 rc = mSource.createObject();
1484 ComAssertMsgRet(SUCCEEDED(rc), ("Could not create source (%Rhrc)", rc),
1485 E_FAIL);
1486 rc = mSource->init();
1487 ComAssertMsgRet(SUCCEEDED(rc), ("Could not init source (%Rhrc)", rc),
1488 E_FAIL);
1489
1490 for (size_t i = 0; i < aSourcesIn.size(); i++)
1491 {
1492 if (aSourcesIn[i] != NULL)
1493 mEventSources.push_back(aSourcesIn[i]);
1494 }
1495
1496 /* Confirm a successful initialization */
1497 autoInitSpan.setSucceeded();
1498
1499 return rc;
1500}
1501
1502STDMETHODIMP EventSourceAggregator::CreateListener(IEventListener **aListener)
1503{
1504 return mSource->CreateListener(aListener);
1505}
1506
1507STDMETHODIMP EventSourceAggregator::CreateAggregator(ComSafeArrayIn(IEventSource *, aSubordinates),
1508 IEventSource **aResult)
1509{
1510 return mSource->CreateAggregator(ComSafeArrayInArg(aSubordinates), aResult);
1511}
1512
1513STDMETHODIMP EventSourceAggregator::RegisterListener(IEventListener *aListener,
1514 ComSafeArrayIn(VBoxEventType_T, aInterested),
1515 BOOL aActive)
1516{
1517 CheckComArgNotNull(aListener);
1518 CheckComArgSafeArrayNotNull(aInterested);
1519
1520 AutoCaller autoCaller(this);
1521 if (FAILED(autoCaller.rc()))
1522 return autoCaller.rc();
1523
1524 HRESULT rc;
1525
1526 ComPtr<IEventListener> proxy;
1527 rc = createProxyListener(aListener, proxy.asOutParam());
1528 if (FAILED(rc))
1529 return rc;
1530
1531 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1532 for (EventSourceList::const_iterator it = mEventSources.begin(); it != mEventSources.end();
1533 ++it)
1534 {
1535 ComPtr<IEventSource> es = *it;
1536 /* Register active proxy listener on real event source */
1537 rc = es->RegisterListener(proxy, ComSafeArrayInArg(aInterested), TRUE);
1538 }
1539 /* And add real listener on our event source */
1540 rc = mSource->RegisterListener(aListener, ComSafeArrayInArg(aInterested), aActive);
1541
1542 rc = S_OK;
1543
1544 return rc;
1545}
1546
1547STDMETHODIMP EventSourceAggregator::UnregisterListener(IEventListener *aListener)
1548{
1549 CheckComArgNotNull(aListener);
1550
1551 AutoCaller autoCaller(this);
1552 if (FAILED(autoCaller.rc()))
1553 return autoCaller.rc();
1554
1555 HRESULT rc = S_OK;
1556
1557 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1558
1559 ComPtr<IEventListener> proxy;
1560 rc = getProxyListener(aListener, proxy.asOutParam());
1561 if (FAILED(rc))
1562 return rc;
1563
1564 for (EventSourceList::const_iterator it = mEventSources.begin(); it != mEventSources.end();
1565 ++it)
1566 {
1567 ComPtr<IEventSource> es = *it;
1568 rc = es->UnregisterListener(proxy);
1569 }
1570 rc = mSource->UnregisterListener(aListener);
1571
1572 return removeProxyListener(aListener);
1573
1574}
1575
1576STDMETHODIMP EventSourceAggregator::FireEvent(IEvent *aEvent,
1577 LONG aTimeout,
1578 BOOL *aProcessed)
1579{
1580 CheckComArgNotNull(aEvent);
1581 CheckComArgOutPointerValid(aProcessed);
1582
1583 AutoCaller autoCaller(this);
1584 if (FAILED(autoCaller.rc()))
1585 return autoCaller.rc();
1586
1587 HRESULT rc = S_OK;
1588 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1589 /* Aggregator event source shall not have direct event firing, but we may
1590 wish to support aggregation chains */
1591 for (EventSourceList::const_iterator it = mEventSources.begin(); it != mEventSources.end();
1592 ++it)
1593 {
1594 ComPtr<IEventSource> es = *it;
1595 rc = es->FireEvent(aEvent, aTimeout, aProcessed);
1596 /* Current behavior is that aggregator's FireEvent() always succeeds,
1597 so that multiple event sources don't affect each other. */
1598 NOREF(rc);
1599 }
1600
1601 return S_OK;
1602}
1603
1604STDMETHODIMP EventSourceAggregator::GetEvent(IEventListener *aListener,
1605 LONG aTimeout,
1606 IEvent **aEvent)
1607{
1608 return mSource->GetEvent(aListener, aTimeout, aEvent);
1609}
1610
1611STDMETHODIMP EventSourceAggregator::EventProcessed(IEventListener *aListener,
1612 IEvent *aEvent)
1613{
1614 return mSource->EventProcessed(aListener, aEvent);
1615}
1616
1617HRESULT EventSourceAggregator::createProxyListener(IEventListener *aListener,
1618 IEventListener **aProxy)
1619{
1620 ComObjPtr<ProxyEventListener> proxy;
1621
1622 HRESULT rc = proxy.createObject();
1623 ComAssertMsgRet(SUCCEEDED(rc), ("Could not create proxy (%Rhrc)", rc),
1624 E_FAIL);
1625
1626 rc = proxy->init(mSource);
1627 if (FAILED(rc))
1628 return rc;
1629
1630 ProxyListenerMap::const_iterator it = mListenerProxies.find(aListener);
1631 if (it != mListenerProxies.end())
1632 return setError(E_INVALIDARG,
1633 tr("This listener already registered"));
1634
1635 mListenerProxies.insert(ProxyListenerMap::value_type(aListener, proxy));
1636
1637 proxy.queryInterfaceTo(aProxy);
1638 return S_OK;
1639}
1640
1641HRESULT EventSourceAggregator::getProxyListener(IEventListener *aListener,
1642 IEventListener **aProxy)
1643{
1644 ProxyListenerMap::const_iterator it = mListenerProxies.find(aListener);
1645 if (it == mListenerProxies.end())
1646 return setError(E_INVALIDARG,
1647 tr("This listener never registered"));
1648
1649 (*it).second.queryInterfaceTo(aProxy);
1650 return S_OK;
1651}
1652
1653HRESULT EventSourceAggregator::removeProxyListener(IEventListener *aListener)
1654{
1655 ProxyListenerMap::iterator it = mListenerProxies.find(aListener);
1656 if (it == mListenerProxies.end())
1657 return setError(E_INVALIDARG,
1658 tr("This listener never registered"));
1659
1660 mListenerProxies.erase(it);
1661 return S_OK;
1662}
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