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 Mutex::ScopedLock lock(&m_dataMutex);
197 m_eventSupport = NULL;
202 GenericEventCallType *RegisterEventCall(const EventType &event,
203 EventListenerType *eventListener,
204 DelegateType delegate,
205 WaitableEvent *waitableEvent)
207 Mutex::ScopedLock lock(&m_eventListMutex);
209 EventSupportDataPtr supportData =
210 new EventSupportData(
212 &EventSupportType::ReceiveAbstractEventCall,
215 GenericEventCallType *eventCall =
216 new GenericEventCallType(supportData, eventListener,
219 typename EventCallList::iterator eventCallIter =
220 m_eventsList.insert(m_eventsList.end(), eventCall);
222 supportData->SetIterator(eventCallIter);
227 void RemoveEventCall(typename EventCallList::iterator eventIterator)
229 Mutex::ScopedLock lock(&m_eventListMutex);
231 m_eventsList.erase(eventIterator);
234 // Note: Reentrant metod
235 void GuardedEventCall(const EventType &event,
236 EventListenerType *eventListener)
238 ++m_guardedCallInProgress;
240 UNHANDLED_EXCEPTION_HANDLER_BEGIN
242 eventListener->OnEventReceived(event);
244 UNHANDLED_EXCEPTION_HANDLER_END
246 -- m_guardedCallInProgress;
249 // Note: Reentrant metod
250 void GuardedEventCall(const EventType &event,
251 DelegateType delegate)
253 ++m_guardedCallInProgress;
255 UNHANDLED_EXCEPTION_HANDLER_BEGIN
259 UNHANDLED_EXCEPTION_HANDLER_END
261 -- m_guardedCallInProgress;
264 void ReceiveAbstractEventCall(const EventType &event,
265 EventListenerType *eventListener,
266 DelegateType delegate,
267 WaitableEvent *synchronization)
269 Thread *targetThread;
271 // Listener might have been removed, ensure that it still exits
272 if (eventListener != NULL) {
273 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
275 typename EventListenerList::iterator iterator =
276 m_eventListenerList.find(eventListener);
278 if (iterator == m_eventListenerList.end()) {
279 LogPedantic("Abstract event call listener disappeared."
282 // Even though, synchronize caller if needed
283 if (synchronization != NULL) {
284 synchronization->Signal();
290 // Get target thread id
291 targetThread = iterator->second;
293 // Delegate might have been removed, ensure that it still exits
294 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
296 typename DelegateList::iterator iterator =
297 m_delegateList.find(delegate);
299 if (iterator == m_delegateList.end()) {
300 LogPedantic("Abstract event call delegate disappeared."
303 // Even though, synchronize caller if needed
304 if (synchronization != NULL) {
305 synchronization->Signal();
311 // Get target thread id
312 targetThread = iterator->second;
315 // Ensure that we are now in proper thread now
316 if (targetThread != Thread::GetCurrentThread()) {
317 LogPedantic("Detected event dispatching ping-pong scenario");
319 // Retry if it was not synchronized
320 if (synchronization == NULL) {
321 // Cheat with event delivery
322 EmitEvent(event, EmitMode::Queued);
324 LogPedantic("Ping-Pong: Resent as queued event");
326 // There is a problem
327 // Developer did something nasty, and we will not clean up his
329 synchronization->Signal();
331 LogPedantic("### Ping-Pong: Failed to deliver synchronized"
332 "event in ping-pong scenario!");
338 // Guard listener code for exceptions
339 if (eventListener != NULL) {
340 GuardedEventCall(event, eventListener);
342 GuardedEventCall(event, delegate);
345 // Release caller if synchronizing
346 if (synchronization != NULL) {
347 synchronization->Signal();
352 void EmitEvent(const EventType &event,
353 EmitMode::Type mode = EmitMode::Queued,
354 double dueTime = 0.0)
356 // Emit event, and retrieve later in current context to dispatch
357 std::unique_ptr<Mutex::ScopedLock> lock(
358 new Mutex::ScopedLock(&m_listenerDelegateMutex));
365 case EmitMode::Queued:
368 case EmitMode::Blocking:
371 case EmitMode::Deffered:
378 // In some configurations there is a barrier
379 std::vector<WaitableEvent *> synchronizationBarrier;
381 // Emit to all listeners
382 FOREACH(iterator, m_eventListenerList)
384 // Switch to proper dispatcher and emit event
385 AbstractEventDispatcher *dispatcher = NULL;
387 if (iterator->second == NULL) {
388 // Send to main thread
389 dispatcher = &GetMainEventDispatcherInstance();
391 // Setup thread dispatcher, and send to proper thread
392 m_threadEventDispatcher.SetThread(iterator->second);
393 dispatcher = &m_threadEventDispatcher;
396 // Dispatch event to abstract dispatcher
397 WaitableEvent *synchronization;
399 // TODO: Pool synchronization objects
403 if (iterator->second == Thread::GetCurrentThread()) {
404 // Guard listener code for exceptions
405 GuardedEventCall(event, iterator->first);
407 // Handle non-synchronized event
408 dispatcher->AddEventCall(
409 RegisterEventCall(event, iterator->first,
410 DelegateType(), NULL));
414 case EmitMode::Queued:
415 // Handle non-synchronized event
416 dispatcher->AddEventCall(
417 RegisterEventCall(event, iterator->first,
418 DelegateType(), NULL));
422 case EmitMode::Blocking:
424 if (iterator->second == Thread::GetCurrentThread()) {
425 // Guard listener code for exceptions
426 GuardedEventCall(event, iterator->first);
428 // New synchronization object is needed
429 synchronization = new WaitableEvent();
431 // Handle synchronized event
432 dispatcher->AddEventCall(
433 RegisterEventCall(event, iterator->first,
434 DelegateType(), synchronization));
437 synchronizationBarrier.push_back(synchronization);
441 case EmitMode::Deffered:
442 // Handle deffered events
443 Assert(dueTime >= 0.0 && "Due time must be non-negative");
445 dispatcher->AddTimedEventCall(
446 RegisterEventCall(event, iterator->first,
447 DelegateType(), NULL), dueTime);
452 Assert("Invalid emit mode");
456 // Emit to all delegates
457 FOREACH(iterator, m_delegateList)
459 // Switch to proper dispatcher and emit event
460 AbstractEventDispatcher *dispatcher = NULL;
462 if (iterator->second == NULL) {
463 // Send to main thread
464 dispatcher = &GetMainEventDispatcherInstance();
466 // Setup thread dispatcher, and send to proper thread
467 m_threadEventDispatcher.SetThread(iterator->second);
468 dispatcher = &m_threadEventDispatcher;
471 // Dispatch event to abstract dispatcher
472 WaitableEvent *synchronization;
474 // TODO: Pool synchronization objects
478 if (iterator->second == Thread::GetCurrentThread()) {
479 // Guard listener code for exceptions
480 GuardedEventCall(event, iterator->first);
482 // Handle non-synchronized event
483 dispatcher->AddEventCall(
484 RegisterEventCall(event,
491 case EmitMode::Queued:
492 // Handle non-synchronized event
493 dispatcher->AddEventCall(
494 RegisterEventCall(event,
501 case EmitMode::Blocking:
503 if (iterator->second == Thread::GetCurrentThread()) {
504 // Guard listener code for exceptions
505 GuardedEventCall(event, iterator->first);
507 // New synchronization object is needed
508 synchronization = new WaitableEvent();
510 // Handle synchronized event
511 dispatcher->AddEventCall(
512 RegisterEventCall(event,
518 synchronizationBarrier.push_back(synchronization);
522 case EmitMode::Deffered:
523 // Handle deffered events
524 Assert(dueTime >= 0.0 && "Due time must be non-negative");
526 dispatcher->AddTimedEventCall(
527 RegisterEventCall(event,
535 Assert("Invalid emit mode");
539 // Leave listeners lock in case of blocking call
540 if (!synchronizationBarrier.empty()) {
541 LogPedantic("Leaving lock due to existing barrier");
545 // Synchronize with barrier
546 // TODO: Implement generic WaitForAllMultipleHandles call
547 while (!synchronizationBarrier.empty()) {
548 // Get barrier waitable handles
549 WaitableHandleList barrierHandles;
551 FOREACH(iterator, synchronizationBarrier)
552 barrierHandles.push_back((*iterator)->GetHandle());
555 WaitableHandleIndexList indexList =
556 WaitForMultipleHandles(barrierHandles);
558 // Remove all awaited handles
559 // TODO: Return handles to pool
560 FOREACH(iterator, indexList)
563 delete synchronizationBarrier[*iterator];
566 synchronizationBarrier[*iterator] = NULL;
570 std::vector<WaitableEvent *> clearedSynchronizationBarrier;
572 FOREACH(iterator, synchronizationBarrier)
574 if (*iterator == NULL) {
578 clearedSynchronizationBarrier.push_back(*iterator);
581 synchronizationBarrier.swap(clearedSynchronizationBarrier);
587 m_guardedCallInProgress(false)
590 virtual ~EventSupport()
592 if( m_guardedCallInProgress != 0 ){
593 LogError("The object will terminate, but guardCall is in progress, it could cause segmentation fault");
596 m_eventListenerList.clear();
597 m_delegateList.clear();
599 Mutex::ScopedLock lock(&m_eventListMutex);
601 FOREACH(iterator, m_eventsList)
602 (*iterator)->DisableEvent();
605 void AddListener(EventListenerType *eventListener)
607 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
609 // Listener must not be NULL
610 Assert(eventListener != NULL);
612 // Listener must not already exists
613 Assert(m_eventListenerList.find(eventListener)
614 == m_eventListenerList.end());
616 // Add new listener, inherit dispatcher from current context
617 m_eventListenerList.insert(
618 std::make_pair(eventListener, Thread::GetCurrentThread()));
621 void AddListener(DelegateType delegate)
623 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
625 // Delegate must not be empty
628 // Delegate must not already exists
629 Assert(m_delegateList.find(delegate) == m_delegateList.end());
631 // Add new delegate, inherit dispatcher from current context
632 m_delegateList.insert(
633 std::make_pair(delegate, Thread::GetCurrentThread()));
636 void RemoveListener(EventListenerType *eventListener)
638 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
640 // Listener must not be NULL
641 Assert(eventListener != NULL);
643 // Listener must exist
644 typename EventListenerList::iterator iterator =
645 m_eventListenerList.find(eventListener);
647 Assert(iterator != m_eventListenerList.end());
649 // Remove listener from list
650 m_eventListenerList.erase(iterator);
653 void RemoveListener(DelegateType delegate)
655 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
657 // Delegate must not be empty
660 // Delegate must exist
661 typename DelegateList::iterator iterator =
662 m_delegateList.find(delegate);
664 Assert(iterator != m_delegateList.end());
666 // Remove delegate from list
667 m_delegateList.erase(iterator);
670 void SwitchListenerToThread(EventListenerType *eventListener,
673 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
675 // Listener must not be NULL
676 Assert(eventListener != NULL);
678 // Listener must exist
679 typename EventListenerList::iterator iterator =
680 m_eventListenerList.find(eventListener);
682 Assert(iterator != m_eventListenerList.end());
684 // Set listener thread
685 iterator->second = thread;
688 void SwitchListenerToThread(DelegateType delegate,
691 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
693 // Delegate must not be empty
694 Assert(!delegate.empty());
696 // Delegate must exist
697 typename EventListenerList::iterator iterator =
698 m_delegateList.find(delegate);
700 Assert(iterator != m_delegateList.end());
702 // Set delegate thread
703 iterator->second = thread;
706 void SwitchAllListenersToThread(Thread *thread)
708 Mutex::ScopedLock lock(&m_listenerDelegateMutex);
710 // Switch all listeners and delegates
711 FOREACH(iterator, m_eventListenerList)
712 iterator->second = thread;
714 FOREACH(iterator, m_delegateList)
715 iterator->second = thread;
721 #endif // DPL_EVENT_SUPPORT_H