[2.2.1] Change FBase_String.h to FBaseUtil_AtomicOperations.h
[platform/framework/native/appfw.git] / src / base / runtime / FBaseRt_MainLoop.cpp
1 //
2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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 /**
18  * @file        FBaseRt_MainLoop.cpp
19  * @brief       This is the implementation file for the _MainLoop class.
20  *
21  */
22
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <memory.h>
27 #include <sys/eventfd.h>
28 #include <new>
29
30 #include <FBaseColIEnumeratorT.h>
31
32 #include <FBaseSysLog.h>
33 #include "FBaseRt_MainLoop.h"
34
35 using namespace Tizen::Base;
36 using namespace Tizen::Base::Collection;
37 using namespace Tizen::Base::Runtime;
38
39 namespace Tizen { namespace Base { namespace Runtime
40 {
41 __thread _MainLoop* pCurrentMainLoop = null;
42
43 bool
44 _MainLoop::_Message::operator==(const _Message& rhs) const
45 {
46         if (requestId == rhs.requestId && pArgs == rhs.pArgs)
47         {
48                 return true;
49         }
50
51         return false;
52 }
53
54 bool
55 _MainLoop::_Message::operator!=(const _Message& rhs) const
56 {
57         if (requestId != rhs.requestId || pArgs != rhs.pArgs)
58         {
59                 return true;
60         }
61
62         return false;
63 }
64
65 _MainLoop::_MainLoop(void)
66         : __pGmainLoop(null)
67         , __pGmainContext(null)
68         , __pChannel(null)
69         , __pSource(null)
70         , __pMutex(null)
71         , __pListener(null)
72         , __pActive(null)
73         , __pReady(null)
74 {
75
76 }
77
78 _MainLoop::~_MainLoop(void)
79 {
80
81         delete __pMutex;
82         __pMutex = null;
83
84         if (__pSource)
85         {
86                 g_source_destroy(__pSource);
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         g_io_channel_set_close_on_unref(__pChannel, TRUE);
118         eventFd = -1;
119
120         __pSource = g_io_create_watch(__pChannel, G_IO_IN);
121         SysTryCatch(NID_BASE_RT, __pSource != null, r = E_SYSTEM, E_SYSTEM,
122                            "[E_SYSTEM] Failed to create a gsource for a channel.");
123
124         g_source_set_callback(__pSource, (GSourceFunc)OnMessageArrived, this, null);
125         g_source_attach(__pSource, __pGmainContext);
126
127         __pMutex = new (std::nothrow) Mutex();
128         SysTryCatch(NID_BASE_RT, __pMutex != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
129
130         r = __pMutex->Create();
131         SysTryCatch(NID_BASE_RT, !IsFailed(r), , r, "[%s] Failed to create mutex.", GetErrorMessage(r));
132
133         pCurrentMainLoop = this;
134
135         __pActive = &__messages1;
136         __pReady = &__messages2;
137
138
139         return E_SUCCESS;
140
141 CATCH:
142
143         delete __pMutex;
144         __pMutex = null;
145
146         if (__pSource)
147         {
148                 g_source_destroy(__pSource);
149                 g_source_unref(__pSource);
150                 __pSource = null;
151         }
152
153         if (__pChannel)
154         {
155                 g_io_channel_unref(__pChannel);
156                 __pChannel = null;
157         }
158
159         if (eventFd != -1)
160         {
161                 close(eventFd);
162         }
163         return r;
164 }
165
166 result
167 _MainLoop::SendUserEvent(RequestId requestId, const IList* pArgs)
168 {
169         SysTryReturnResult(NID_BASE_RT, __pGmainContext != null, E_INVALID_STATE, "Main loop is not constructed.");
170
171         _Message message;
172
173         message.requestId = requestId;
174         message.pArgs = pArgs;
175
176         __pMutex->Acquire();
177
178         __pActive->Add(message);
179
180         __pMutex->Release();
181
182         gsize writtenSize = 0;
183         uint64_t count = 1;
184
185         g_io_channel_write(__pChannel, (const gchar*) &count, sizeof(count), &writtenSize);
186
187         return E_SUCCESS;
188 }
189
190 void
191 _MainLoop::SetMainLoopEventListener(_IMainLoopEventListener* pListener)
192 {
193         __pListener = pListener;
194 }
195
196 gboolean
197 _MainLoop::OnMessageArrived(GIOChannel* pChannel, GIOCondition condition, gpointer data)
198 {
199         _MainLoop* pMainLoop = (_MainLoop*) data;
200
201         uint64_t count = 0;
202         gsize readSize = 0;
203
204         ArrayListT<_Message>* pMessages = null;
205
206         pMainLoop->__pMutex->Acquire();
207
208         pMessages = pMainLoop->__pActive;
209         pMainLoop->__pActive = pMainLoop->__pReady;
210         pMainLoop->__pReady = pMessages;
211
212         pMainLoop->__pMutex->Release();
213
214         if (condition & G_IO_IN)
215         {
216                 g_io_channel_read(pChannel, (gchar*) &count, sizeof(count), &readSize);
217
218                 if (readSize == 0)
219                 {
220                         return TRUE;
221                 }
222
223                 if (pMainLoop->__pListener)
224                 {
225                         _Message message;
226                         IEnumeratorT<_Message>* pEnum = pMessages->GetEnumeratorN();;
227                         SysTryReturn(NID_BASE_RT, pEnum, TRUE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
228
229                         while (pEnum->MoveNext() == E_SUCCESS)
230                         {
231                                 pEnum->GetCurrent(message);
232                         }
233                 }
234
235                 pMessages->RemoveAll();
236         }
237
238         count = pMainLoop->__pActive->GetCount();
239         if (count > 0)
240         {
241                 gsize writtenSize = 0;
242                 g_io_channel_write(pChannel, (const gchar*) &count, sizeof(count), &writtenSize);
243         }
244
245         return TRUE;
246 }
247
248 _MainLoop*
249 _MainLoop::GetCurrentMainLoop(void)
250 {
251         SysTryReturn(NID_BASE_RT, pCurrentMainLoop != null, null, E_INVALID_STATE, "[E_INVALID_STATE] Main loop is exist.");
252
253         return pCurrentMainLoop;
254 }
255
256 GMainContext*
257 _MainLoop::GetGmainContext(void) const
258 {
259         SysTryReturn(NID_BASE_RT, __pGmainContext != null, null, E_INVALID_STATE, "[E_INVALID_STATE] Main loop is not constructed..");
260
261         return __pGmainContext;
262 }
263
264 } } } // Tizen::Base::Runtime