2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file event_support.h
18 * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
20 * @brief This file is the implementation file of MVC event support
22 #ifndef DPL_EVENT_SUPPORT_H
23 #define DPL_EVENT_SUPPORT_H
29 #include <type_traits>
32 #include <dpl/event/event_listener.h>
33 #include <dpl/event/abstract_event_dispatcher.h>
34 #include <dpl/event/main_event_dispatcher.h>
35 #include <dpl/event/thread_event_dispatcher.h>
36 #include <dpl/event/generic_event_call.h>
37 #include <dpl/waitable_event.h>
38 #include <dpl/exception.h>
39 #include <dpl/thread.h>
40 #include <dpl/assert.h>
41 #include <dpl/atomic.h>
42 #include <dpl/mutex.h>
43 #include <dpl/foreach.h>
44 #include <dpl/log/log.h>
51 Auto, ///< If calling thread is the same as receiver's use
52 ///< direct call, otherwise call is queued
54 Queued, ///< Call is always queued
56 Blocking, ///< If calling thread is the same as receiver's use
57 ///< direct call, otherwise call is queued and blocking
59 Deffered ///< Call is always queued for a period of time
61 } // namespace EmitMode
63 template<typename EventType>
68 typedef EventSupport<EventType> EventSupportType;
70 typedef EventListener<EventType> EventListenerType;
72 typedef void DelegateSignature(const EventType&);
73 typedef std::function<DelegateSignature> DelegateType;
75 class EventSupportData; // Forward declaration
76 typedef EventSupportData *EventSupportDataPtr;
79 typedef typename GenericEventCall<EventType, EventSupportDataPtr>::
80 template Rebind<EventType, EventSupportDataPtr>::
81 Other GenericEventCallType;
83 // Event listener list
84 typedef std::map<EventListenerType *, Thread *> EventListenerList;
85 EventListenerList m_eventListenerList;
87 struct DelegateCompare
89 typedef typename std::add_pointer<DelegateSignature>::type
92 bool operator()(const DelegateType& a, const DelegateType& b) const
94 return comparer(a.template target<DelegateSignature>(),
95 b.template target<DelegateSignature>());
98 const std::less<DelegateSignaturePtr> comparer;
102 typedef std::map<DelegateType, Thread *, DelegateCompare> DelegateList;
103 DelegateList m_delegateList;
105 // Event support operation mutex
106 Mutex m_listenerDelegateMutex;
108 // Dedicated instance of thread event dispatcher
109 ThreadEventDispatcher m_threadEventDispatcher;
111 // Guard destruction of event support in event handler
112 Atomic m_guardedCallInProgress;
114 // Events created by this support
115 typedef std::list<GenericEventCallType *> EventCallList;
116 EventCallList m_eventsList;
119 Mutex m_eventListMutex;
122 class EventSupportData
125 typedef void (EventSupportType::*ReceiveAbstractEventCallMethod)(
126 const EventType &event,
127 EventListenerType *eventListener,
128 DelegateType delegate,
129 WaitableEvent *synchronization);
131 EventSupportType *m_eventSupport;
132 ReceiveAbstractEventCallMethod m_method;
133 typename EventCallList::iterator m_iterator;
135 //TODO: Add dispatcher iterator to remove events from
136 // framework/thread's event queue
137 WaitableEvent *m_synchronization;
142 EventSupportData(EventSupportType *support,
143 ReceiveAbstractEventCallMethod method,
144 WaitableEvent *synchronization) :
145 m_eventSupport(support),
147 m_synchronization(synchronization)
152 Mutex::ScopedLock lock(&m_dataMutex);
154 if (!m_eventSupport) {
155 LogPedantic("EventSupport for this call does not exist");
159 m_eventSupport->RemoveEventCall(m_iterator);
162 // TODO: Make private and make EventSupport friend
163 void SetIterator(typename EventCallList::iterator iter)
168 // This method at the end destroys this as it will not be used anymore
169 void CallAndDestroy(const EventType &event,
170 EventListenerType *listener,
171 DelegateType delegate)
174 Mutex::ScopedLock lock(&m_dataMutex);
176 if (m_eventSupport != NULL) {
177 (*m_eventSupport.*m_method)(event,
182 LogPedantic("EventSupport for this call does not "
183 "exist anymore. Ignored.");
186 // releasing mutex lock
189 // EventSupportData object is no more used.
190 // It can be safely destroyed now.
196 LogPedantic("Reseting my EventSupport");
198 Mutex::ScopedLock lock(&m_dataMutex);
199 m_eventSupport = NULL;
204 GenericEventCallType *RegisterEventCall(const EventType &event,
205 EventListenerType *eventListener,
206 DelegateType delegate,
207 WaitableEvent *waitableEvent)
209 LogPedantic("Create and Register EventCall in EventSupport");
211 Mutex::ScopedLock lock(&m_eventListMutex);
213 EventSupportDataPtr supportData =
214 new EventSupportData(
216 &EventSupportType::ReceiveAbstractEventCall,
219 GenericEventCallType *eventCall =
220 new GenericEventCallType(supportData, eventListener,
223 typename EventCallList::iterator eventCallIter =
224 m_eventsList.insert(m_eventsList.end(), eventCall);
226 supportData->SetIterator(eventCallIter);
231 void RemoveEventCall(typename EventCallList::iterator eventIterator)
233 Mutex::ScopedLock lock(&m_eventListMutex);
235 LogPedantic("Removing event call from EventSupport");
237 m_eventsList.erase(eventIterator);
240 // Note: Reentrant metod
241 void GuardedEventCall(const EventType &event,
242 EventListenerType *eventListener)
244 LogPedantic("Guarded event listener call...");
246 ++m_guardedCallInProgress;
248 UNHANDLED_EXCEPTION_HANDLER_BEGIN
250 eventListener->OnEventReceived(event);
252 UNHANDLED_EXCEPTION_HANDLER_END
254 -- m_guardedCallInProgress;
256 LogPedantic("Guarded event listener finished");
259 // Note: Reentrant metod
260 void GuardedEventCall(const EventType &event,
261 DelegateType delegate)
263 LogPedantic("Guarded delegate call...");
265 ++m_guardedCallInProgress;
267 UNHANDLED_EXCEPTION_HANDLER_BEGIN
271 UNHANDLED_EXCEPTION_HANDLER_END
273 -- m_guardedCallInProgress;
275 LogPedantic("Guarded delegate call finished");
278 void ReceiveAbstractEventCall(const EventType &event,
279 EventListenerType *eventListener,
280 DelegateType delegate,
281 WaitableEvent *synchronization)
283 LogPedantic("Received abstract event call method");
285 Thread *targetThread;
287 // Listener might have been removed, ensure that it still exits
288 if (eventListener != NULL) {
289 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
291 typename EventListenerList::iterator iterator =
292 m_eventListenerList.find(eventListener);
294 if (iterator == m_eventListenerList.end()) {
295 LogPedantic("Abstract event call listener disappeared."
298 // Even though, synchronize caller if needed
299 if (synchronization != NULL) {
300 synchronization->Signal();
306 // Get target thread id
307 targetThread = iterator->second;
309 // Delegate might have been removed, ensure that it still exits
310 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
312 typename DelegateList::iterator iterator =
313 m_delegateList.find(delegate);
315 if (iterator == m_delegateList.end()) {
316 LogPedantic("Abstract event call delegate disappeared."
319 // Even though, synchronize caller if needed
320 if (synchronization != NULL) {
321 synchronization->Signal();
327 // Get target thread id
328 targetThread = iterator->second;
331 // Ensure that we are now in proper thread now
332 if (targetThread != Thread::GetCurrentThread()) {
333 LogPedantic("Detected event dispatching ping-pong scenario");
335 // Retry if it was not synchronized
336 if (synchronization == NULL) {
337 // Cheat with event delivery
338 EmitEvent(event, EmitMode::Queued);
340 LogPedantic("Ping-Pong: Resent as queued event");
342 // There is a problem
343 // Developer did something nasty, and we will not clean up his
345 synchronization->Signal();
347 LogPedantic("### Ping-Pong: Failed to deliver synchronized"
348 "event in ping-pong scenario!");
354 // Guard listener code for exceptions
355 if (eventListener != NULL) {
356 GuardedEventCall(event, eventListener);
358 GuardedEventCall(event, delegate);
361 // Release caller if synchronizing
362 if (synchronization != NULL) {
363 synchronization->Signal();
368 void EmitEvent(const EventType &event,
369 EmitMode::Type mode = EmitMode::Queued,
370 double dueTime = 0.0)
372 // Emit event, and retrieve later in current context to dispatch
373 std::unique_ptr<Mutex::ScopedLock> lock(
374 new Mutex::ScopedLock(&m_listenerDelegateMutex));
379 LogPedantic("Emitting AUTO event...");
382 case EmitMode::Queued:
383 LogPedantic("Emitting QUEUED event...");
386 case EmitMode::Blocking:
387 LogPedantic("Emitting BLOCKING event...");
390 case EmitMode::Deffered:
391 LogPedantic("Emitting DEFFERED event...");
398 // In some configurations there is a barrier
399 std::vector<WaitableEvent *> synchronizationBarrier;
401 // Emit to all listeners
402 FOREACH(iterator, m_eventListenerList)
404 // Switch to proper dispatcher and emit event
405 AbstractEventDispatcher *dispatcher = NULL;
407 if (iterator->second == NULL) {
408 // Send to main thread
409 LogPedantic("Sending event to main dispatcher");
410 dispatcher = &GetMainEventDispatcherInstance();
412 // Setup thread dispatcher, and send to proper thread
413 LogPedantic("Sending event to thread dispatcher");
414 m_threadEventDispatcher.SetThread(iterator->second);
415 dispatcher = &m_threadEventDispatcher;
418 // Dispatch event to abstract dispatcher
419 WaitableEvent *synchronization;
421 // TODO: Pool synchronization objects
425 if (iterator->second == Thread::GetCurrentThread()) {
426 // Guard listener code for exceptions
427 GuardedEventCall(event, iterator->first);
429 // Handle non-synchronized event
430 dispatcher->AddEventCall(
431 RegisterEventCall(event, iterator->first,
432 DelegateType(), NULL));
436 case EmitMode::Queued:
437 // Handle non-synchronized event
438 dispatcher->AddEventCall(
439 RegisterEventCall(event, iterator->first,
440 DelegateType(), NULL));
444 case EmitMode::Blocking:
446 if (iterator->second == Thread::GetCurrentThread()) {
447 // Guard listener code for exceptions
448 GuardedEventCall(event, iterator->first);
450 // New synchronization object is needed
451 synchronization = new WaitableEvent();
453 // Handle synchronized event
454 dispatcher->AddEventCall(
455 RegisterEventCall(event, iterator->first,
456 DelegateType(), synchronization));
459 synchronizationBarrier.push_back(synchronization);
463 case EmitMode::Deffered:
464 // Handle deffered events
465 Assert(dueTime >= 0.0 && "Due time must be non-negative");
467 dispatcher->AddTimedEventCall(
468 RegisterEventCall(event, iterator->first,
469 DelegateType(), NULL), dueTime);
474 Assert("Invalid emit mode");
478 LogPedantic("Added event to dispatchers");
480 // Emit to all delegates
481 FOREACH(iterator, m_delegateList)
483 // Switch to proper dispatcher and emit event
484 AbstractEventDispatcher *dispatcher = NULL;
486 if (iterator->second == NULL) {
487 // Send to main thread
488 LogPedantic("Sending event to main dispatcher");
489 dispatcher = &GetMainEventDispatcherInstance();
491 // Setup thread dispatcher, and send to proper thread
492 LogPedantic("Sending event to thread dispatcher");
493 m_threadEventDispatcher.SetThread(iterator->second);
494 dispatcher = &m_threadEventDispatcher;
497 // Dispatch event to abstract dispatcher
498 WaitableEvent *synchronization;
500 // TODO: Pool synchronization objects
504 if (iterator->second == Thread::GetCurrentThread()) {
505 // Guard listener code for exceptions
506 GuardedEventCall(event, iterator->first);
508 // Handle non-synchronized event
509 dispatcher->AddEventCall(
510 RegisterEventCall(event,
517 case EmitMode::Queued:
518 // Handle non-synchronized event
519 dispatcher->AddEventCall(
520 RegisterEventCall(event,
527 case EmitMode::Blocking:
529 if (iterator->second == Thread::GetCurrentThread()) {
530 // Guard listener code for exceptions
531 GuardedEventCall(event, iterator->first);
533 // New synchronization object is needed
534 synchronization = new WaitableEvent();
536 // Handle synchronized event
537 dispatcher->AddEventCall(
538 RegisterEventCall(event,
544 synchronizationBarrier.push_back(synchronization);
548 case EmitMode::Deffered:
549 // Handle deffered events
550 Assert(dueTime >= 0.0 && "Due time must be non-negative");
552 dispatcher->AddTimedEventCall(
553 RegisterEventCall(event,
561 Assert("Invalid emit mode");
565 LogPedantic("Added event to dispatchers");
567 // Leave listeners lock in case of blocking call
568 if (!synchronizationBarrier.empty()) {
569 LogPedantic("Leaving lock due to existing barrier");
573 LogPedantic("Size of barrier: " << synchronizationBarrier.size());
575 // Synchronize with barrier
576 // TODO: Implement generic WaitForAllMultipleHandles call
577 while (!synchronizationBarrier.empty()) {
578 // Get barrier waitable handles
579 WaitableHandleList barrierHandles;
581 FOREACH(iterator, synchronizationBarrier)
582 barrierHandles.push_back((*iterator)->GetHandle());
585 WaitableHandleIndexList indexList =
586 WaitForMultipleHandles(barrierHandles);
588 // Remove all awaited handles
589 // TODO: Return handles to pool
590 FOREACH(iterator, indexList)
593 delete synchronizationBarrier[*iterator];
596 synchronizationBarrier[*iterator] = NULL;
600 std::vector<WaitableEvent *> clearedSynchronizationBarrier;
602 FOREACH(iterator, synchronizationBarrier)
604 if (*iterator == NULL) {
608 clearedSynchronizationBarrier.push_back(*iterator);
611 synchronizationBarrier.swap(clearedSynchronizationBarrier);
613 LogPedantic("Reduced size of barrier: "
614 << synchronizationBarrier.size());
617 LogPedantic("Event emitted");
622 m_guardedCallInProgress(false)
625 virtual ~EventSupport()
627 if( m_guardedCallInProgress != 0 ){
628 LogError("The object will terminate, but guardCall is in progress, it could cause segmentation fault");
631 m_eventListenerList.clear();
632 m_delegateList.clear();
634 Mutex::ScopedLock lock(&m_eventListMutex);
636 LogPedantic("Disabling events for EventSupport");
638 FOREACH(iterator, m_eventsList)
639 (*iterator)->DisableEvent();
642 void AddListener(EventListenerType *eventListener)
644 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
646 // Listener must not be NULL
647 Assert(eventListener != NULL);
649 // Listener must not already exists
650 Assert(m_eventListenerList.find(eventListener)
651 == m_eventListenerList.end());
653 // Add new listener, inherit dispatcher from current context
654 m_eventListenerList.insert(
655 std::make_pair(eventListener, Thread::GetCurrentThread()));
658 LogPedantic("Listener registered");
661 void AddListener(DelegateType delegate)
663 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
665 // Delegate must not be empty
668 // Delegate must not already exists
669 Assert(m_delegateList.find(delegate) == m_delegateList.end());
671 // Add new delegate, inherit dispatcher from current context
672 m_delegateList.insert(
673 std::make_pair(delegate, Thread::GetCurrentThread()));
676 LogPedantic("Delegate registered");
679 void RemoveListener(EventListenerType *eventListener)
681 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
683 // Listener must not be NULL
684 Assert(eventListener != NULL);
686 // Listener must exist
687 typename EventListenerList::iterator iterator =
688 m_eventListenerList.find(eventListener);
690 Assert(iterator != m_eventListenerList.end());
692 // Remove listener from list
693 m_eventListenerList.erase(iterator);
694 LogPedantic("Listener unregistered");
697 void RemoveListener(DelegateType delegate)
699 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
701 // Delegate must not be empty
704 // Delegate must exist
705 typename DelegateList::iterator iterator =
706 m_delegateList.find(delegate);
708 Assert(iterator != m_delegateList.end());
710 // Remove delegate from list
711 m_delegateList.erase(iterator);
712 LogPedantic("Delegate unregistered");
715 void SwitchListenerToThread(EventListenerType *eventListener,
718 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
720 // Listener must not be NULL
721 Assert(eventListener != NULL);
723 // Listener must exist
724 typename EventListenerList::iterator iterator =
725 m_eventListenerList.find(eventListener);
727 Assert(iterator != m_eventListenerList.end());
729 // Set listener thread
730 iterator->second = thread;
732 LogPedantic("Listener switched");
735 void SwitchListenerToThread(DelegateType delegate,
738 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
740 // Delegate must not be empty
741 Assert(!delegate.empty());
743 // Delegate must exist
744 typename EventListenerList::iterator iterator =
745 m_delegateList.find(delegate);
747 Assert(iterator != m_delegateList.end());
749 // Set delegate thread
750 iterator->second = thread;
752 LogPedantic("Delegate switched");
755 void SwitchAllListenersToThread(Thread *thread)
757 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
759 // Switch all listeners and delegates
760 FOREACH(iterator, m_eventListenerList)
761 iterator->second = thread;
763 FOREACH(iterator, m_delegateList)
764 iterator->second = thread;
766 LogPedantic("All listeners and delegates switched");
772 #endif // DPL_EVENT_SUPPORT_H