tizen 2.4 release
[framework/web/wrt-commons.git] / modules / event / src / main_event_dispatcher.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /*
17  * @file        main_event_dispatcher.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of main event dispatcher
21  * for EFL
22  */
23 #include <stddef.h>
24 #include <dpl/event/main_event_dispatcher.h>
25 #include <dpl/log/wrt_log.h>
26 #include <dpl/assert.h>
27 #include <dpl/singleton_impl.h>
28
29 namespace DPL {
30 IMPLEMENT_SINGLETON(Event::MainEventDispatcher)
31
32 namespace Event {
33 typedef Singleton<Event::MainEventDispatcher> MainEventDispatcherSingleton;
34
35 namespace // anonymous
36 {
37 static const pthread_t g_threadMain = pthread_self();
38
39 // Late EFL event handling
40 MainEventDispatcher *g_lateMainEventDispatcher = NULL;
41 } // namespace anonymous
42
43 MainEventDispatcher::MainEventDispatcher()
44 {
45     // Late EFL event handling
46     Assert(g_lateMainEventDispatcher == NULL);
47     g_lateMainEventDispatcher = this;
48
49     // Increment ECORE init count to ensure we have all
50     // subsystems correctly set-up until main dispatcher dtor
51     // This is especially important when MainEventDispatcher
52     // is a global object destroyed no earlier than crt destroy routine
53     ecore_init();
54
55     // Add new global ECORE event
56     m_eventId = ecore_event_type_new();
57
58     WrtLogD("ECORE event class registered: %i", m_eventId);
59
60     // Register event class handler
61     if ((m_eventCallHandler =
62              ecore_event_handler_add(m_eventId, &StaticDispatchEvent,
63                                      this)) == NULL)
64     {
65         ThrowMsg(Exception::CreateFailed, "Failed to register event handler!");
66     }
67
68     // Allocate WaitableEvent
69     m_crossEventCallInvoker = new WaitableEvent();
70
71     // Register cross event handler
72     m_crossEventCallHandler = ecore_main_fd_handler_add(
73             m_crossEventCallInvoker->GetHandle(),
74             ECORE_FD_READ,
75             &StaticDispatchCrossInvoker,
76             this,
77             NULL,
78             NULL);
79
80     if (m_crossEventCallHandler == NULL) {
81         ThrowMsg(Exception::CreateFailed,
82                  "Failed to register cross event handler!");
83     }
84
85     WrtLogD("ECORE cross-event handler registered");
86 }
87
88 MainEventDispatcher::~MainEventDispatcher()
89 {
90     // Remove cross event handler
91     ecore_main_fd_handler_del(m_crossEventCallHandler);
92     m_crossEventCallHandler = NULL;
93     WrtLogD("ECORE cross-event handler unregistered");
94
95     // Remove m_crossEventCallInvoker
96     delete m_crossEventCallInvoker;
97     m_crossEventCallInvoker = NULL;
98
99     // Remove event class handler
100     ecore_event_handler_del(m_eventCallHandler);
101     m_eventCallHandler = NULL;
102
103     // Decrement ECORE init count
104     // We do not need ecore routines any more
105     ecore_shutdown();
106
107     // Late EFL event handling
108     Assert(g_lateMainEventDispatcher == this);
109     g_lateMainEventDispatcher = NULL;
110 }
111
112 void MainEventDispatcher::ResetCrossEventCallHandler()
113 {
114     // Remove cross event handler
115     ecore_main_fd_handler_del(m_crossEventCallHandler);
116     m_crossEventCallHandler = NULL;
117     WrtLogD("ECORE cross-event handler unregistered");
118
119     // Re-allocate WaitableEvent
120     delete m_crossEventCallInvoker;
121     m_crossEventCallInvoker = new WaitableEvent();
122
123     // Register cross event handler
124     m_crossEventCallHandler =
125         ecore_main_fd_handler_add(m_crossEventCallInvoker->GetHandle(),
126                                   ECORE_FD_READ,
127                                   &StaticDispatchCrossInvoker,
128                                   this,
129                                   NULL,
130                                   NULL);
131
132     if (m_crossEventCallHandler == NULL) {
133         ThrowMsg(Exception::CreateFailed,
134                  "Failed to register cross event handler!");
135     }
136
137     WrtLogD("ECORE cross-event handler re-registered");
138 }
139
140 void MainEventDispatcher::StaticDeleteEvent(void *data, void *event)
141 {
142     WrtLogD("Static ECORE delete event handler");
143
144     MainEventDispatcher *This = static_cast<MainEventDispatcher *>(data);
145     AbstractEventCall *abstractEventCall =
146         static_cast<AbstractEventCall *>(event);
147
148     Assert(This != NULL);
149     Assert(abstractEventCall != NULL);
150
151     // Late EFL event handling
152     if (g_lateMainEventDispatcher == NULL) {
153         WrtLogD("WARNING: Late EFL event delete!");
154         delete abstractEventCall;
155     } else {
156         This->DeleteEvent(abstractEventCall);
157     }
158 }
159
160 Eina_Bool MainEventDispatcher::StaticDispatchEvent(void *data,
161                                                    int type,
162                                                    void *event)
163 {
164     WrtLogD("Static ECORE dispatch event");
165
166     MainEventDispatcher *This = static_cast<MainEventDispatcher *>(data);
167     AbstractEventCall *abstractEventCall =
168         static_cast<AbstractEventCall *>(event);
169     (void)type;
170
171     Assert(This != NULL);
172     Assert(abstractEventCall != NULL);
173
174     // Late EFL event handling
175     if (g_lateMainEventDispatcher == NULL) {
176         WrtLogD("WARNING: Late EFL event dispatch!");
177     } else {
178         This->DispatchEvent(abstractEventCall);
179     }
180
181     // Continue to handler other ECORE events
182     return ECORE_CALLBACK_RENEW;
183 }
184
185 Eina_Bool MainEventDispatcher::StaticDispatchTimedEvent(void *data)
186 {
187     WrtLogD("Static ECORE dispatch timed event");
188
189     TimedEventStruct *timedEventStruct = static_cast<TimedEventStruct *>(data);
190     MainEventDispatcher *This = timedEventStruct->This;
191     AbstractEventCall *abstractEventCall = timedEventStruct->abstractEventCall;
192     delete timedEventStruct;
193
194     Assert(This != NULL);
195     Assert(abstractEventCall != NULL);
196
197     // Late EFL event handling
198     if (g_lateMainEventDispatcher == NULL) {
199         WrtLogD("WARNING: Late EFL timed event dispatch!");
200     } else {
201         // Dispatch timed event
202         This->DispatchEvent(abstractEventCall);
203     }
204
205     // And delete manually event, because ECORE does not
206     // use delete handler for timers
207     StaticDeleteEvent(static_cast<void *>(This),
208                       static_cast<void *>(abstractEventCall));
209
210     // Do not continue timed event handlers
211     // This also releases ECORE timer
212     return ECORE_CALLBACK_CANCEL;
213 }
214
215 Eina_Bool MainEventDispatcher::StaticDispatchCrossInvoker(
216     void *data,
217     Ecore_Fd_Handler *
218     fd_handler)
219 {
220     WrtLogD("Static ECORE dispatch cross invoker");
221
222     MainEventDispatcher *This = static_cast<MainEventDispatcher *>(data);
223     (void)fd_handler;
224
225     Assert(This != NULL);
226
227     // Late EFL event handling
228     if (g_lateMainEventDispatcher == NULL) {
229         WrtLogD("WARNING: Late EFL cross invoker dispatch!");
230     } else {
231         This->DispatchCrossInvoker();
232     }
233
234     return ECORE_CALLBACK_RENEW;
235 }
236
237 void MainEventDispatcher::DeleteEvent(AbstractEventCall *abstractEventCall)
238 {
239     WrtLogD("ECORE delete event");
240     delete abstractEventCall;
241 }
242
243 void MainEventDispatcher::DispatchEvent(AbstractEventCall *abstractEventCall)
244 {
245     WrtLogD("ECORE dispatch event");
246
247     // Call event handler
248     abstractEventCall->Call();
249 }
250
251 void MainEventDispatcher::DispatchTimedEvent(
252     AbstractEventCall *abstractEventCall)
253 {
254     WrtLogD("ECORE dispatch timed event");
255
256     // Call event handler
257     abstractEventCall->Call();
258 }
259
260 void MainEventDispatcher::DispatchCrossInvoker()
261 {
262     WrtLogD("ECORE dispatch cross invoker");
263
264     // Steal cross events list
265     WrappedEventCallList stolenCrossEvents;
266
267     // Critical section
268     {
269         m_crossEventCallInvoker->Reset();
270         std::lock_guard<std::mutex> lock(m_crossEventCallMutex);
271         m_wrappedCrossEventCallList.swap(stolenCrossEvents);
272     }
273
274     WrtLogD("Cross-thread event list stolen. Number of events: %i",
275         stolenCrossEvents.size());
276
277     // Repush all stolen events
278     WrappedEventCallList::const_iterator eventIterator;
279
280     for (eventIterator = stolenCrossEvents.begin();
281          eventIterator != stolenCrossEvents.end();
282          ++eventIterator)
283     {
284         // Unwrap events
285         WrtLogD("Dispatching event from invoker");
286         InternalAddEvent(eventIterator->abstractEventCall,
287                          eventIterator->timed,
288                          eventIterator->dueTime);
289     }
290
291     WrtLogD("Cross-thread events dispatched");
292 }
293
294 void MainEventDispatcher::AddEventCall(AbstractEventCall *abstractEventCall)
295 {
296     if (pthread_equal(pthread_self(), g_threadMain)) {
297         WrtLogD("Main thread ECORE event push");
298         InternalAddEvent(abstractEventCall, false, 0.0);
299     } else {
300         WrtLogD("Cross-thread ECORE event push");
301
302         // Push event to cross event list
303         {
304             std::lock_guard<std::mutex> lock(m_crossEventCallMutex);
305             m_wrappedCrossEventCallList.push_back(WrappedEventCall(
306                                                       abstractEventCall, false,
307                                                       0.0));
308             m_crossEventCallInvoker->Signal();
309         }
310
311         WrtLogD("Event pushed to cross-thread event list");
312     }
313 }
314
315 void MainEventDispatcher::AddTimedEventCall(
316     AbstractEventCall *abstractEventCall,
317     double dueTime)
318 {
319     if (pthread_equal(pthread_self(), g_threadMain)) {
320         WrtLogD("Main thread timed ECORE event push");
321         InternalAddEvent(abstractEventCall, true, dueTime);
322     } else {
323         WrtLogD("Cross-thread timed ECORE event push");
324
325         // Push event to cross event list
326         {
327             std::lock_guard<std::mutex> lock(m_crossEventCallMutex);
328             m_wrappedCrossEventCallList.push_back(WrappedEventCall(
329                                                       abstractEventCall, true,
330                                                       dueTime));
331             m_crossEventCallInvoker->Signal();
332         }
333
334         WrtLogD("Event pushed to cross-thread event list");
335     }
336 }
337
338 void MainEventDispatcher::InternalAddEvent(AbstractEventCall *abstractEventCall,
339                                            bool timed,
340                                            double dueTime)
341 {
342     WrtLogD("Adding base event");
343
344     if (timed == true) {
345         // Push timed event onto ecore stack
346         TimedEventStruct* eventData = new TimedEventStruct(abstractEventCall,
347                                                            this);
348         Ecore_Timer *timedEvent = ecore_timer_add(dueTime,
349                                                   &StaticDispatchTimedEvent,
350                                                   eventData);
351
352         if (timedEvent == NULL) {
353             delete eventData;
354             delete abstractEventCall;
355             ThrowMsg(Exception::AddTimedEventFailed,
356                      "Failed to add ECORE timed event");
357         }
358
359         WrtLogD("Timed wrapped event added");
360     } else {
361         // Push immediate event onto ecore stack
362         Ecore_Event *event = ecore_event_add(m_eventId,
363                                              abstractEventCall,
364                                              &StaticDeleteEvent,
365                                              this);
366
367         if (event == NULL) {
368             delete abstractEventCall;
369             ThrowMsg(Exception::AddEventFailed, "Failed to add ECORE event");
370         }
371
372         WrtLogD("Wrapped event added");
373     }
374 }
375
376 MainEventDispatcher& GetMainEventDispatcherInstance()
377 {
378     return MainEventDispatcherSingleton::Instance();
379 }
380 }
381 } // namespace DPL