tizen 2.4 release
[framework/web/wrt-commons.git] / modules / core / src / main.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.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of main for EFL
21  */
22 #include <stddef.h>
23 #include <dpl/main.h>
24 #include <dpl/log/wrt_log.h>
25 #include <sys/select.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <dpl/assert.h>
29 #include <dpl/singleton_impl.h>
30
31 IMPLEMENT_SINGLETON(DPL::Main)
32
33 namespace DPL {
34 namespace // anonymous
35 {
36 // Late EFL event handling
37 Main *g_lateMain = NULL;
38 } // namespace anonymous
39
40 Main::Main()
41 #ifdef DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND
42 // GLIB loop intergration workaround
43     : m_oldEcoreSelect(NULL)
44 #endif // DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND
45 {
46     // Late EFL event handling
47     Assert(g_lateMain == NULL);
48     g_lateMain = this;
49
50     // Increment ECORE init count to ensure we have all
51     // subsystems correctly set-up until main dispatcher dtor
52     // This is especially important when MainEventDispatcher
53     // is a global object destroyed no earlier than crt destroy routine
54     ecore_init();
55
56 #ifdef DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND
57     // GLIB loop intergration workaround
58     union ConvertPointer
59     {
60         Ecore_Select_Function pointer;
61         EcoreSelectType function;
62     } convert;
63
64     convert.pointer = ecore_main_loop_select_func_get();
65     m_oldEcoreSelect = convert.function;
66
67     ecore_main_loop_select_func_set(&EcoreSelectInterceptor);
68 #endif // DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND
69
70     // Register event invoker
71     m_invokerHandler = ecore_main_fd_handler_add(
72             WaitableHandleWatchSupport::WaitableInvokerHandle(),
73             ECORE_FD_READ,
74             &StaticDispatchInvoker,
75             this,
76             NULL,
77             NULL);
78
79     if (m_invokerHandler == NULL) {
80         ThrowMsg(Exception::CreateFailed, "Failed to register invoker handler!");
81     }
82
83     // It is impossible that there exist watchers at this time
84     // No need to add watchers
85     WrtLogD("ECORE event handler registered");
86 }
87
88 Main::~Main()
89 {
90     // Remove any watchers
91     for (EcoreFdHandlerList::iterator iterator = m_readWatchersList.begin();
92          iterator != m_readWatchersList.end();
93          ++iterator)
94     {
95         ecore_main_fd_handler_del(*iterator);
96     }
97
98     m_readWatchersList.clear();
99
100     for (EcoreFdHandlerList::iterator iterator = m_writeWatchersList.begin();
101          iterator != m_writeWatchersList.end();
102          ++iterator)
103     {
104         ecore_main_fd_handler_del(*iterator);
105     }
106
107     m_writeWatchersList.clear();
108
109     // Remove event invoker
110     ecore_main_fd_handler_del(m_invokerHandler);
111     m_invokerHandler = NULL;
112
113     //set old ecore select function, because after ecore_shutdown() call,
114     //it is being called once again and it may crash.
115     ecore_main_loop_select_func_set(m_oldEcoreSelect);
116     // Decrement ECORE init count
117     // We do not need ecore routines any more
118     ecore_shutdown();
119
120     // Late EFL event handling
121     Assert(g_lateMain == this);
122     g_lateMain = NULL;
123 }
124
125 Eina_Bool Main::StaticDispatchInvoker(void *data, Ecore_Fd_Handler *fd_handler)
126 {
127     WrtLogD("Static ECORE dispatch invoker");
128
129     Main *This = static_cast<Main *>(data);
130     (void)fd_handler;
131
132     Assert(This != NULL);
133
134     // Late EFL event handling
135     if (g_lateMain == NULL) {
136         WrtLogD("WARNING: Late EFL invoker dispatch!");
137     } else {
138         This->DispatchInvoker();
139     }
140
141     return ECORE_CALLBACK_RENEW;
142 }
143
144 Eina_Bool Main::StaticDispatchReadWatcher(void* data,
145                                           Ecore_Fd_Handler* fd_handler)
146 {
147     WrtLogD("Static ECORE dispatch read watcher");
148
149     Main *This = static_cast<Main *>(data);
150
151     Assert(This != NULL);
152
153     // Late EFL event handling
154     if (g_lateMain == NULL) {
155         WrtLogD("WARNING: Late EFL read watcher dispatch!");
156     } else {
157         This->DispatchReadWatcher(static_cast<WaitableHandle>(
158                                       ecore_main_fd_handler_fd_get(fd_handler)));
159     }
160
161     return ECORE_CALLBACK_RENEW;
162 }
163
164 Eina_Bool Main::StaticDispatchWriteWatcher(void* data,
165                                            Ecore_Fd_Handler* fd_handler)
166 {
167     WrtLogD("Static ECORE dispatch write watcher");
168
169     Main *This = static_cast<Main *>(data);
170
171     Assert(This != NULL);
172
173     // Late EFL event handling
174     if (g_lateMain == NULL) {
175         WrtLogD("WARNING: Late EFL write watcher dispatch!");
176     } else {
177         This->DispatchWriteWatcher(static_cast<WaitableHandle>(
178                                        ecore_main_fd_handler_fd_get(fd_handler)));
179     }
180
181     return ECORE_CALLBACK_RENEW;
182 }
183
184 void Main::DispatchInvoker()
185 {
186     WrtLogD("Dispatching invoker...");
187
188     // Reload watch list
189     ReloadWatchList();
190
191     // Handle base invoker
192     WaitableHandleWatchSupport::InvokerFinished();
193
194     WrtLogD("Invoker dispatched");
195 }
196
197 void Main::ReloadWatchList()
198 {
199     WrtLogD("Reloading watch list... (%i + %i)",
200             m_readWatchersList.size(), m_writeWatchersList.size());
201
202     // Reload list of watchers
203     WaitableHandleListEx waitableWatcherHandles =
204         WaitableHandleWatchSupport::WaitableWatcherHandles();
205
206     // Remove not existing read watchers
207     EcoreFdHandlerList::iterator watchersIterator = m_readWatchersList.begin();
208     WaitableHandleListEx::iterator handlesIterator;
209
210     while (watchersIterator != m_readWatchersList.end()) {
211         bool found = false;
212
213         for (handlesIterator = waitableWatcherHandles.begin();
214              handlesIterator != waitableWatcherHandles.end();
215              ++handlesIterator)
216         {
217             if (handlesIterator->second == WaitMode::Read &&
218                 handlesIterator->first ==
219                 static_cast<WaitableHandle>(ecore_main_fd_handler_fd_get(*
220                                                                          watchersIterator)))
221             {
222                 found = true;
223                 break;
224             }
225         }
226
227         if (!found) {
228             // Unregister handler
229             ecore_main_fd_handler_del(*watchersIterator);
230
231             // Remove iterator
232             EcoreFdHandlerList::iterator next = watchersIterator;
233             ++next;
234
235             m_readWatchersList.erase(watchersIterator);
236             watchersIterator = next;
237         } else {
238             ++watchersIterator;
239         }
240     }
241
242     // Remove not existing write watchers
243     watchersIterator = m_writeWatchersList.begin();
244
245     while (watchersIterator != m_writeWatchersList.end()) {
246         bool found = false;
247
248         for (handlesIterator = waitableWatcherHandles.begin();
249              handlesIterator != waitableWatcherHandles.end();
250              ++handlesIterator)
251         {
252             if (handlesIterator->second == WaitMode::Write &&
253                 handlesIterator->first ==
254                 static_cast<WaitableHandle>(ecore_main_fd_handler_fd_get(*
255                                                                          watchersIterator)))
256             {
257                 found = true;
258                 break;
259             }
260         }
261
262         if (!found) {
263             // Unregister handler
264             ecore_main_fd_handler_del(*watchersIterator);
265
266             // Remove iterator
267             EcoreFdHandlerList::iterator next = watchersIterator;
268             ++next;
269
270             m_writeWatchersList.erase(watchersIterator);
271             watchersIterator = next;
272         } else {
273             ++watchersIterator;
274         }
275     }
276
277     // Add new read/write watchers
278     for (handlesIterator = waitableWatcherHandles.begin();
279          handlesIterator != waitableWatcherHandles.end();
280          ++handlesIterator)
281     {
282         if (handlesIterator->second == WaitMode::Read) {
283             bool found = false;
284
285             for (watchersIterator = m_readWatchersList.begin();
286                  watchersIterator != m_readWatchersList.end();
287                  ++watchersIterator)
288             {
289                 if (handlesIterator->first ==
290                     static_cast<WaitableHandle>(ecore_main_fd_handler_fd_get(*
291                                                                              watchersIterator)))
292                 {
293                     found = true;
294                     break;
295                 }
296             }
297
298             if (!found) {
299                 Ecore_Fd_Handler *handler = ecore_main_fd_handler_add(
300                         handlesIterator->first,
301                         ECORE_FD_READ,
302                         &StaticDispatchReadWatcher,
303                         this,
304                         NULL,
305                         NULL);
306                 if (handler == NULL) {
307                     ThrowMsg(Exception::CreateFailed,
308                              "Failed to register read watcher handler!");
309                 }
310
311                 // Push new watcher to list
312                 m_readWatchersList.push_back(handler);
313             }
314         } else if (handlesIterator->second == WaitMode::Write) {
315             bool found = false;
316
317             for (watchersIterator = m_writeWatchersList.begin();
318                  watchersIterator != m_writeWatchersList.end();
319                  ++watchersIterator)
320             {
321                 if (handlesIterator->first ==
322                     static_cast<WaitableHandle>(ecore_main_fd_handler_fd_get(*
323                                                                              watchersIterator)))
324                 {
325                     found = true;
326                     break;
327                 }
328             }
329
330             if (!found) {
331                 Ecore_Fd_Handler *handler = ecore_main_fd_handler_add(
332                         handlesIterator->first,
333                         ECORE_FD_WRITE,
334                         &StaticDispatchWriteWatcher,
335                         this,
336                         NULL,
337                         NULL);
338                 if (handler == NULL) {
339                     ThrowMsg(Exception::CreateFailed,
340                              "Failed to register write watcher handler!");
341                 }
342
343                 // Push new watcher to list
344                 m_writeWatchersList.push_back(handler);
345             }
346         } else {
347             Assert(0);
348         }
349     }
350
351     WrtLogD("Watch list reloaded  (%i + %i)",
352             m_readWatchersList.size(), m_writeWatchersList.size());
353 }
354
355 void Main::DispatchReadWatcher(WaitableHandle waitableHandle)
356 {
357     WrtLogD("Dispatching read watcher...");
358
359     // Handle watcher
360     WaitableHandleWatchSupport::HandleWatcher(waitableHandle, WaitMode::Read);
361
362     WrtLogD("Watcher dispatched");
363 }
364
365 void Main::DispatchWriteWatcher(WaitableHandle waitableHandle)
366 {
367     WrtLogD("Dispatching write watcher...");
368
369     // Handle watcher
370     WaitableHandleWatchSupport::HandleWatcher(waitableHandle, WaitMode::Write);
371
372     WrtLogD("Watcher dispatched");
373 }
374
375 Thread *Main::GetInvokerThread()
376 {
377     return NULL;
378 }
379
380 void Main::HandleDirectInvoker()
381 {
382     // Handle direct invoker
383     ReloadWatchList();
384 }
385
386 #ifdef DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND
387 // GLIB loop intergration workaround
388 int Main::EcoreSelectInterceptor(int nfds,
389                                  fd_set *readfds,
390                                  fd_set *writefds,
391                                  fd_set *exceptfds,
392                                  struct timeval *timeout)
393 {
394     // We have to check error code here and make another try because of some
395     // glib error's.
396     fd_set rfds, wfds, efds;
397     memcpy(&rfds, readfds, sizeof(fd_set));
398     memcpy(&wfds, writefds, sizeof(fd_set));
399     memcpy(&efds, exceptfds, sizeof(fd_set));
400
401     int ret = MainSingleton::Instance().m_oldEcoreSelect(nfds,
402                                                          readfds,
403                                                          writefds,
404                                                          exceptfds,
405                                                          timeout);
406
407     if (ret == -1) {
408         // Check each descriptor to see if it is valid
409         for (int i = 0; i < nfds; i++) {
410             if (FD_ISSET(i,
411                          readfds) ||
412                 FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds))
413             {
414                 // Try to get descriptor flags
415                 int result = fcntl(i, F_GETFL);
416
417                 if (result == -1) {
418                     if (errno == EBADF) {
419                         // This a bad descriptor. Remove all occurrences of it.
420                         if (FD_ISSET(i, readfds)) {
421                             WrtLogD(
422                                 "GLIB_LOOP_INTEGRATION_WORKAROUND: Bad read descriptor: %i", i);
423                             FD_CLR(i, readfds);
424                         }
425
426                         if (FD_ISSET(i, writefds)) {
427                             WrtLogD(
428                                 "GLIB_LOOP_INTEGRATION_WORKAROUND: Bad write descriptor: %i", i);
429                             FD_CLR(i, writefds);
430                         }
431
432                         if (FD_ISSET(i, exceptfds)) {
433                             WrtLogD(
434                                 "GLIB_LOOP_INTEGRATION_WORKAROUND: Bad exception descriptor: %i", i);
435                             FD_CLR(i, exceptfds);
436                         }
437                     } else {
438                         // Unexpected error
439                         Assert(0);
440                     }
441                 }
442             }
443         }
444
445         WrtLogD("GLIB_LOOP_INTEGRATION_WORKAROUND: Bad read descriptor. Retrying with default select.");
446
447         //Retry with old values and return new error
448         memcpy(readfds, &rfds, sizeof(fd_set));
449         memcpy(writefds, &wfds, sizeof(fd_set));
450         memcpy(exceptfds, &efds, sizeof(fd_set));
451
452         // Trying to do it very short
453         timeval tm;
454         tm.tv_sec = 0;
455         tm.tv_usec = 10;
456
457         if (timeout) {
458             ret = select(nfds, readfds, writefds, exceptfds, &tm);
459         } else {
460             ret = select(nfds, readfds, writefds, exceptfds, NULL);
461         }
462     }
463
464     return ret;
465 }
466 #endif // DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND
467 } // namespace DPL