7b9fcf6747531dbd63a6e680dfbb2656bfddefca
[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                 g_source_destroy(__pSource);
89                 __pSource = null;
90         }
91
92         if (__pChannel)
93         {
94                 g_io_channel_unref(__pChannel);
95                 __pChannel = null;
96         }
97 }
98
99 result
100 _MainLoop::Construct(GMainLoop* pGmainLoop, GMainContext* pGmainContext)
101 {
102         result r = E_SUCCESS;
103         GError* pGError = null;
104
105         __pGmainContext = pGmainContext;
106         g_main_context_ref(__pGmainContext);
107
108         int eventFd = eventfd(0, 0);
109         SysTryCatch(NID_BASE_RT, -1 != eventFd, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to open eventfd.");
110
111
112         __pChannel = g_io_channel_unix_new(eventFd);
113         SysTryCatch(NID_BASE_RT, __pChannel != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to create a channel for eventfd.");
114
115         g_io_channel_set_encoding(__pChannel, null, &pGError);
116         g_io_channel_set_flags(__pChannel, G_IO_FLAG_NONBLOCK, &pGError);
117
118         g_io_channel_set_close_on_unref(__pChannel, TRUE);
119         eventFd = -1;
120
121         __pSource = g_io_create_watch(__pChannel, G_IO_IN);
122         SysTryCatch(NID_BASE_RT, __pSource != null, r = E_SYSTEM, E_SYSTEM,
123                            "[E_SYSTEM] Failed to create a gsource for a channel.");
124
125         g_source_set_callback(__pSource, (GSourceFunc)OnMessageArrived, this, null);
126         g_source_attach(__pSource, __pGmainContext);
127
128         __pMutex = new (std::nothrow) Mutex();
129         SysTryCatch(NID_BASE_RT, __pMutex != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
130
131         r = __pMutex->Create();
132         SysTryCatch(NID_BASE_RT, !IsFailed(r), , r, "[%s] Failed to create mutex.", GetErrorMessage(r));
133
134         pCurrentMainLoop = this;
135
136         __pActive = &__messages1;
137         __pReady = &__messages2;
138
139
140         return E_SUCCESS;
141
142 CATCH:
143
144         delete __pMutex;
145         __pMutex = null;
146
147         if (__pSource)
148         {
149                 g_source_unref(__pSource);
150                 g_source_destroy(__pSource);
151                 __pSource = null;
152         }
153
154         if (__pChannel)
155         {
156                 g_io_channel_unref(__pChannel);
157                 __pChannel = null;
158         }
159
160         if (eventFd != -1)
161         {
162                 close(eventFd);
163         }
164         return r;
165 }
166
167 result
168 _MainLoop::SendUserEvent(RequestId requestId, const IList* pArgs)
169 {
170         SysTryReturnResult(NID_BASE_RT, __pGmainContext != null, E_INVALID_STATE, "Main loop is not constructed.");
171
172         _Message message;
173
174         message.requestId = requestId;
175         message.pArgs = pArgs;
176
177         __pMutex->Acquire();
178
179         __pActive->Add(message);
180
181         __pMutex->Release();
182
183         gsize writtenSize = 0;
184         uint64_t count = 1;
185
186         g_io_channel_write(__pChannel, (const gchar*) &count, sizeof(count), &writtenSize);
187
188         return E_SUCCESS;
189 }
190
191 void
192 _MainLoop::SetMainLoopEventListener(_IMainLoopEventListener* pListener)
193 {
194         __pListener = pListener;
195 }
196
197 gboolean
198 _MainLoop::OnMessageArrived(GIOChannel* pChannel, GIOCondition condition, gpointer data)
199 {
200         _MainLoop* pMainLoop = (_MainLoop*) data;
201
202         uint64_t count = 0;
203         gsize readSize = 0;
204
205         ArrayListT<_Message>* pMessages = null;
206
207         pMainLoop->__pMutex->Acquire();
208
209         pMessages = pMainLoop->__pActive;
210         pMainLoop->__pActive = pMainLoop->__pReady;
211         pMainLoop->__pReady = pMessages;
212
213         pMainLoop->__pMutex->Release();
214
215         if (condition & G_IO_IN)
216         {
217                 g_io_channel_read(pChannel, (gchar*) &count, sizeof(count), &readSize);
218
219                 if (readSize == 0)
220                 {
221                         return TRUE;
222                 }
223
224                 if (pMainLoop->__pListener)
225                 {
226                         _Message message;
227                         IEnumeratorT<_Message>* pEnum = pMessages->GetEnumeratorN();;
228                         SysTryReturn(NID_BASE_RT, pEnum, TRUE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
229
230                         while (pEnum->MoveNext() == E_SUCCESS)
231                         {
232                                 pEnum->GetCurrent(message);
233                         }
234                 }
235
236                 pMessages->RemoveAll();
237         }
238
239         count = pMainLoop->__pActive->GetCount();
240         if (count > 0)
241         {
242                 gsize writtenSize = 0;
243                 g_io_channel_write(pChannel, (const gchar*) &count, sizeof(count), &writtenSize);
244         }
245
246         return TRUE;
247 }
248
249 _MainLoop*
250 _MainLoop::GetCurrentMainLoop(void)
251 {
252         SysTryReturn(NID_BASE_RT, pCurrentMainLoop != null, null, E_INVALID_STATE, "[E_INVALID_STATE] Main loop is exist.");
253
254         return pCurrentMainLoop;
255 }
256
257 GMainContext*
258 _MainLoop::GetGmainContext(void) const
259 {
260         SysTryReturn(NID_BASE_RT, __pGmainContext != null, null, E_INVALID_STATE, "[E_INVALID_STATE] Main loop is not constructed..");
261
262         return __pGmainContext;
263 }
264
265 } } } // Tizen::Base::Runtime