4133af8614893fe6436e04026144de13b88075f8
[platform/framework/native/appfw.git] / src / base / runtime / FBaseRt_MainLoop.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 /**
19  * @file        FBaseRt_MainLoop.cpp
20  * @brief       This is the implementation file for the _MainLoop class.
21  *
22  */
23
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <memory.h>
28 #include <sys/eventfd.h>
29 #include <new>
30
31 #include <FBaseColIEnumeratorT.h>
32
33 #include <FBaseSysLog.h>
34 #include "FBaseRt_MainLoop.h"
35
36 using namespace Tizen::Base;
37 using namespace Tizen::Base::Collection;
38 using namespace Tizen::Base::Runtime;
39
40 namespace Tizen { namespace Base { namespace Runtime
41 {
42 __thread _MainLoop* pCurrentMainLoop = null;
43
44 bool
45 _MainLoop::_Message::operator==(const _Message& rhs) const
46 {
47         if (requestId == rhs.requestId && pArgs == rhs.pArgs)
48         {
49                 return true;
50         }
51
52         return false;
53 }
54
55 bool
56 _MainLoop::_Message::operator!=(const _Message& rhs) const
57 {
58         if (requestId != rhs.requestId || pArgs != rhs.pArgs)
59         {
60                 return true;
61         }
62
63         return false;
64 }
65
66 _MainLoop::_MainLoop(void)
67         : __pGmainLoop(null)
68         , __pGmainContext(null)
69         , __pChannel(null)
70         , __pSource(null)
71         , __pMutex(null)
72         , __pListener(null)
73         , __pActive(null)
74         , __pReady(null)
75 {
76
77 }
78
79 _MainLoop::~_MainLoop(void)
80 {
81
82         delete __pMutex;
83         __pMutex = null;
84
85         if (__pSource)
86         {
87                 g_source_unref(__pSource);
88                 __pSource = null;
89         }
90
91         if (__pChannel)
92         {
93                 g_io_channel_unref(__pChannel);
94                 __pChannel = null;
95         }
96 }
97
98 result
99 _MainLoop::Construct(GMainLoop* pGmainLoop, GMainContext* pGmainContext)
100 {
101         result r = E_SUCCESS;
102         GError* pGError = null;
103
104         __pGmainContext = pGmainContext;
105         g_main_context_ref(__pGmainContext);
106
107         int eventFd = eventfd(0, 0);
108         SysTryCatch(NID_BASE_RT, -1 != eventFd, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to open eventfd.");
109
110
111         __pChannel = g_io_channel_unix_new(eventFd);
112         SysTryCatch(NID_BASE_RT, __pChannel != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to create a channel for eventfd.");
113
114         g_io_channel_set_encoding(__pChannel, null, &pGError);
115         g_io_channel_set_flags(__pChannel, G_IO_FLAG_NONBLOCK, &pGError);
116
117         __pSource = g_io_create_watch(__pChannel, G_IO_IN);
118         SysTryCatch(NID_BASE_RT, __pSource != null, r = E_SYSTEM, E_SYSTEM,
119                            "[E_SYSTEM] Failed to create a gsource for a channel.");
120
121         g_source_set_callback(__pSource, (GSourceFunc)OnMessageArrived, this, null);
122         g_source_attach(__pSource, __pGmainContext);
123
124         __pMutex = new (std::nothrow) Mutex();
125         SysTryCatch(NID_BASE_RT, __pMutex != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
126
127         r = __pMutex->Create();
128         SysTryCatch(NID_BASE_RT, !IsFailed(r), , r, "[%s] Failed to create mutex.", GetErrorMessage(r));
129
130         pCurrentMainLoop = this;
131
132         __pActive = &__messages1;
133         __pReady = &__messages2;
134
135
136         return E_SUCCESS;
137
138 CATCH:
139
140         delete __pMutex;
141         __pMutex = null;
142
143         if (__pSource)
144         {
145                 g_source_unref(__pSource);
146                 __pSource = null;
147         }
148
149         if (__pChannel)
150         {
151                 g_io_channel_unref(__pChannel);
152                 __pChannel = null;
153         }
154
155         return r;
156 }
157
158 result
159 _MainLoop::SendUserEvent(RequestId requestId, const IList* pArgs)
160 {
161         SysTryReturnResult(NID_BASE_RT, __pGmainContext != null, E_INVALID_STATE, "Main loop is not constructed.");
162
163         _Message message;
164
165         message.requestId = requestId;
166         message.pArgs = pArgs;
167
168         __pMutex->Acquire();
169
170         __pActive->Add(message);
171
172         __pMutex->Release();
173
174         gsize writtenSize = 0;
175         uint64_t count = 1;
176
177         g_io_channel_write(__pChannel, (const gchar*) &count, sizeof(count), &writtenSize);
178
179         return E_SUCCESS;
180 }
181
182 void
183 _MainLoop::SetMainLoopEventListener(_IMainLoopEventListener* pListener)
184 {
185         __pListener = pListener;
186 }
187
188 gboolean
189 _MainLoop::OnMessageArrived(GIOChannel* pChannel, GIOCondition condition, gpointer data)
190 {
191         _MainLoop* pMainLoop = (_MainLoop*) data;
192
193         uint64_t count = 0;
194         gsize readSize = 0;
195
196         ArrayListT<_Message>* pMessages = null;
197
198         pMainLoop->__pMutex->Acquire();
199
200         pMessages = pMainLoop->__pActive;
201         pMainLoop->__pActive = pMainLoop->__pReady;
202         pMainLoop->__pReady = pMessages;
203
204         pMainLoop->__pMutex->Release();
205
206         if (condition & G_IO_IN)
207         {
208                 g_io_channel_read(pChannel, (gchar*) &count, sizeof(count), &readSize);
209
210                 if (readSize == 0)
211                 {
212                         return TRUE;
213                 }
214
215                 if (pMainLoop->__pListener)
216                 {
217                         _Message message;
218                         IEnumeratorT<_Message>* pEnum = pMessages->GetEnumeratorN();;
219                         SysTryReturn(NID_BASE_RT, pEnum, TRUE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
220
221                         while (pEnum->MoveNext() == E_SUCCESS)
222                         {
223                                 pEnum->GetCurrent(message);
224                         }
225                 }
226
227                 pMessages->RemoveAll();
228         }
229
230         count = pMainLoop->__pActive->GetCount();
231         if (count > 0)
232         {
233                 gsize writtenSize = 0;
234                 g_io_channel_write(pChannel, (const gchar*) &count, sizeof(count), &writtenSize);
235         }
236
237         return TRUE;
238 }
239
240 _MainLoop*
241 _MainLoop::GetCurrentMainLoop(void)
242 {
243         SysTryReturn(NID_BASE_RT, pCurrentMainLoop != null, null, E_INVALID_STATE, "[E_INVALID_STATE] Main loop is exist.");
244
245         return pCurrentMainLoop;
246 }
247
248 GMainContext*
249 _MainLoop::GetGmainContext(void) const
250 {
251         SysTryReturn(NID_BASE_RT, __pGmainContext != null, null, E_INVALID_STATE, "[E_INVALID_STATE] Main loop is not constructed..");
252
253         return __pGmainContext;
254 }
255
256 } } } // Tizen::Base::Runtime