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
31 #include <type_traits>
34 #include <dpl/event/event_listener.h>
35 #include <dpl/event/abstract_event_dispatcher.h>
36 #include <dpl/event/main_event_dispatcher.h>
37 #include <dpl/event/thread_event_dispatcher.h>
38 #include <dpl/event/generic_event_call.h>
39 #include <dpl/waitable_event.h>
40 #include <dpl/exception.h>
41 #include <dpl/thread.h>
42 #include <dpl/assert.h>
43 #include <dpl/foreach.h>
44 #include <dpl/log/wrt_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 std::mutex m_listenerDelegateMutex;
108 // Dedicated instance of thread event dispatcher
109 ThreadEventDispatcher m_threadEventDispatcher;
111 // Guard destruction of event support in event handler
112 std::atomic<int> m_guardedCallInProgress;
114 // Events created by this support
115 typedef std::list<GenericEventCallType *> EventCallList;
116 EventCallList m_eventsList;
119 std::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;
139 std::mutex m_dataMutex;
142 EventSupportData(EventSupportType *support,
143 ReceiveAbstractEventCallMethod method,
144 WaitableEvent *synchronization) :
145 m_eventSupport(support),
147 m_synchronization(synchronization)
152 std::lock_guard<std::mutex> lock(m_dataMutex);
154 if (!m_eventSupport) {
155 WrtLogD("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 std::lock_guard<std::mutex> lock(m_dataMutex);
176 if (m_eventSupport != NULL) {
177 (*m_eventSupport.*m_method)(event,
182 WrtLogD("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 std::lock_guard<std::mutex> lock(m_dataMutex);
197 m_eventSupport = NULL;
202 GenericEventCallType *RegisterEventCall(const EventType &event,
203 EventListenerType *eventListener,
204 DelegateType delegate,
205 WaitableEvent *waitableEvent)
207 std::lock_guard<std::mutex> 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 std::lock_guard<std::mutex> 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 std::lock_guard<std::mutex> lock(m_listenerDelegateMutex);
275 typename EventListenerList::iterator iterator =
276 m_eventListenerList.find(eventListener);
278 if (iterator == m_eventListenerList.end()) {
279 WrtLogD("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 std::lock_guard<std::mutex> lock(m_listenerDelegateMutex);
296 typename DelegateList::iterator iterator =
297 m_delegateList.find(delegate);
299 if (iterator == m_delegateList.end()) {
300 WrtLogD("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 WrtLogD("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 WrtLogD("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 WrtLogD("### 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_lock<std::mutex> lock(m_listenerDelegateMutex);
364 case EmitMode::Queued:
367 case EmitMode::Blocking:
370 case EmitMode::Deffered:
377 // In some configurations there is a barrier
378 std::vector<WaitableEvent *> synchronizationBarrier;
380 // Emit to all listeners
381 FOREACH(iterator, m_eventListenerList)
383 // Switch to proper dispatcher and emit event
384 AbstractEventDispatcher *dispatcher = NULL;
386 if (iterator->second == NULL) {
387 // Send to main thread
388 dispatcher = &GetMainEventDispatcherInstance();
390 // Setup thread dispatcher, and send to proper thread
391 m_threadEventDispatcher.SetThread(iterator->second);
392 dispatcher = &m_threadEventDispatcher;
395 // Dispatch event to abstract dispatcher
396 WaitableEvent *synchronization;
398 // TODO: Pool synchronization objects
402 if (iterator->second == Thread::GetCurrentThread()) {
403 // Guard listener code for exceptions
404 GuardedEventCall(event, iterator->first);
406 // Handle non-synchronized event
407 dispatcher->AddEventCall(
408 RegisterEventCall(event, iterator->first,
409 DelegateType(), NULL));
413 case EmitMode::Queued:
414 // Handle non-synchronized event
415 dispatcher->AddEventCall(
416 RegisterEventCall(event, iterator->first,
417 DelegateType(), NULL));
421 case EmitMode::Blocking:
423 if (iterator->second == Thread::GetCurrentThread()) {
424 // Guard listener code for exceptions
425 GuardedEventCall(event, iterator->first);
427 // New synchronization object is needed
428 synchronization = new WaitableEvent();
430 // Handle synchronized event
431 dispatcher->AddEventCall(
432 RegisterEventCall(event, iterator->first,
433 DelegateType(), synchronization));
436 synchronizationBarrier.push_back(synchronization);
440 case EmitMode::Deffered:
441 // Handle deffered events
442 Assert(dueTime >= 0.0 && "Due time must be non-negative");
444 dispatcher->AddTimedEventCall(
445 RegisterEventCall(event, iterator->first,
446 DelegateType(), NULL), dueTime);
451 Assert("Invalid emit mode");
455 // Emit to all delegates
456 FOREACH(iterator, m_delegateList)
458 // Switch to proper dispatcher and emit event
459 AbstractEventDispatcher *dispatcher = NULL;
461 if (iterator->second == NULL) {
462 // Send to main thread
463 dispatcher = &GetMainEventDispatcherInstance();
465 // Setup thread dispatcher, and send to proper thread
466 m_threadEventDispatcher.SetThread(iterator->second);
467 dispatcher = &m_threadEventDispatcher;
470 // Dispatch event to abstract dispatcher
471 WaitableEvent *synchronization;
473 // TODO: Pool synchronization objects
477 if (iterator->second == Thread::GetCurrentThread()) {
478 // Guard listener code for exceptions
479 GuardedEventCall(event, iterator->first);
481 // Handle non-synchronized event
482 dispatcher->AddEventCall(
483 RegisterEventCall(event,
490 case EmitMode::Queued:
491 // Handle non-synchronized event
492 dispatcher->AddEventCall(
493 RegisterEventCall(event,
500 case EmitMode::Blocking:
502 if (iterator->second == Thread::GetCurrentThread()) {
503 // Guard listener code for exceptions
504 GuardedEventCall(event, iterator->first);
506 // New synchronization object is needed
507 synchronization = new WaitableEvent();
509 // Handle synchronized event
510 dispatcher->AddEventCall(
511 RegisterEventCall(event,
517 synchronizationBarrier.push_back(synchronization);
521 case EmitMode::Deffered:
522 // Handle deffered events
523 Assert(dueTime >= 0.0 && "Due time must be non-negative");
525 dispatcher->AddTimedEventCall(
526 RegisterEventCall(event,
534 Assert("Invalid emit mode");
538 // Leave listeners lock in case of blocking call
539 if (!synchronizationBarrier.empty()) {
540 WrtLogD("Leaving lock due to existing barrier");
544 // Synchronize with barrier
545 // TODO: Implement generic WaitForAllMultipleHandles call
546 while (!synchronizationBarrier.empty()) {
547 // Get barrier waitable handles
548 WaitableHandleList barrierHandles;
550 FOREACH(iterator, synchronizationBarrier)
551 barrierHandles.push_back((*iterator)->GetHandle());
554 WaitableHandleIndexList indexList =
555 WaitForMultipleHandles(barrierHandles);
557 // Remove all awaited handles
558 // TODO: Return handles to pool
559 FOREACH(iterator, indexList)
562 delete synchronizationBarrier[*iterator];
565 synchronizationBarrier[*iterator] = NULL;
569 std::vector<WaitableEvent *> clearedSynchronizationBarrier;
571 FOREACH(iterator, synchronizationBarrier)
573 if (*iterator == NULL) {
577 clearedSynchronizationBarrier.push_back(*iterator);
580 synchronizationBarrier.swap(clearedSynchronizationBarrier);
586 m_guardedCallInProgress(false)
589 virtual ~EventSupport()
591 if( m_guardedCallInProgress != 0 ){
592 WrtLogD("The object will terminate, but guardCall is in progress, it could cause segmentation fault");
595 m_eventListenerList.clear();
596 m_delegateList.clear();
598 std::lock_guard<std::mutex> lock(m_eventListMutex);
600 FOREACH(iterator, m_eventsList)
601 (*iterator)->DisableEvent();
604 void AddListener(EventListenerType *eventListener)
606 std::lock_guard<std::mutex> lock(m_listenerDelegateMutex);
608 // Listener must not be NULL
609 Assert(eventListener != NULL);
611 // Listener must not already exists
612 Assert(m_eventListenerList.find(eventListener)
613 == m_eventListenerList.end());
615 // Add new listener, inherit dispatcher from current context
616 m_eventListenerList.insert(
617 std::make_pair(eventListener, Thread::GetCurrentThread()));
620 void AddListener(DelegateType delegate)
622 std::lock_guard<std::mutex> lock(m_listenerDelegateMutex);
624 // Delegate must not be empty
627 // Delegate must not already exists
628 Assert(m_delegateList.find(delegate) == m_delegateList.end());
630 // Add new delegate, inherit dispatcher from current context
631 m_delegateList.insert(
632 std::make_pair(delegate, Thread::GetCurrentThread()));
635 void RemoveListener(EventListenerType *eventListener)
637 std::lock_guard<std::mutex> lock(m_listenerDelegateMutex);
639 // Listener must not be NULL
640 Assert(eventListener != NULL);
642 // Listener must exist
643 typename EventListenerList::iterator iterator =
644 m_eventListenerList.find(eventListener);
646 Assert(iterator != m_eventListenerList.end());
648 // Remove listener from list
649 m_eventListenerList.erase(iterator);
652 void RemoveListener(DelegateType delegate)
654 std::lock_guard<std::mutex> lock(m_listenerDelegateMutex);
656 // Delegate must not be empty
659 // Delegate must exist
660 typename DelegateList::iterator iterator =
661 m_delegateList.find(delegate);
663 Assert(iterator != m_delegateList.end());
665 // Remove delegate from list
666 m_delegateList.erase(iterator);
669 void SwitchListenerToThread(EventListenerType *eventListener,
672 std::lock_guard<std::mutex> lock(m_listenerDelegateMutex);
674 // Listener must not be NULL
675 Assert(eventListener != NULL);
677 // Listener must exist
678 typename EventListenerList::iterator iterator =
679 m_eventListenerList.find(eventListener);
681 Assert(iterator != m_eventListenerList.end());
683 // Set listener thread
684 iterator->second = thread;
687 void SwitchListenerToThread(DelegateType delegate,
690 std::lock_guard<std::mutex> lock(m_listenerDelegateMutex);
692 // Delegate must not be empty
693 Assert(!delegate.empty());
695 // Delegate must exist
696 typename EventListenerList::iterator iterator =
697 m_delegateList.find(delegate);
699 Assert(iterator != m_delegateList.end());
701 // Set delegate thread
702 iterator->second = thread;
705 void SwitchAllListenersToThread(Thread *thread)
707 std::lock_guard<std::mutex> lock(m_listenerDelegateMutex);
709 // Switch all listeners and delegates
710 FOREACH(iterator, m_eventListenerList)
711 iterator->second = thread;
713 FOREACH(iterator, m_delegateList)
714 iterator->second = thread;
720 #endif // DPL_EVENT_SUPPORT_H