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