Fix the boiler plate codes
[platform/framework/native/appfw.git] / src / base / runtime / FBaseRt_TimerImpl.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_TimerImpl.cpp
19  * @brief       This is the implementation file for the _TimerImpl class.
20  *
21  */
22
23 #include <stdint.h>
24 #include <unistd.h>
25 #include <sys/timerfd.h>
26 #include <glib.h>
27 #include <errno.h>
28
29 #include <FBaseRtTimer.h>
30
31 #include "FApp_AppInfo.h"
32 #include <FBaseSysLog.h>
33 #include "FBaseRt_EventDispatcher.h"
34 #include "FBaseRt_TimerImpl.h"
35
36
37 namespace Tizen { namespace Base { namespace Runtime
38 {
39
40 _TimerImpl::_TimerImpl(void)
41         : __pTimer(null)
42         , __timerFd(-1)
43         , __pTimerIo(null)
44         , __pTimerSource(null)
45         , __pTimerEventListener(null)
46         , __status(TIMER_STATUS_NOT_ACTIVATED)
47 {
48
49 }
50
51 _TimerImpl::~_TimerImpl(void)
52 {
53         if (__pTimerSource != null)
54         {
55                 g_source_destroy(__pTimerSource);
56                 g_source_unref(__pTimerSource);
57         }
58
59         if (__pTimerIo != null)
60         {
61                 g_io_channel_unref(__pTimerIo);
62         }
63 }
64
65 result
66 _TimerImpl::Construct(const Timer& timer, ITimerEventListener& listener)
67 {
68         result r = E_SUCCESS;
69         int timerFd = -1;
70         GIOChannel* pGIOChannel = null;
71         GSource* pGSource = null;
72         _EventDispatcher* pEventDispatcher = null;
73         GMainContext* pGMainContext = null;
74
75         pEventDispatcher = _EventDispatcher::GetCurrentEventDispatcher();
76         SysTryReturnResult(NID_BASE_RT, pEventDispatcher != null, E_SYSTEM,
77                                 "Called by a worker thread.");
78
79         pGMainContext = pEventDispatcher->GetGMainContext();
80         SysTryReturnResult(NID_BASE_RT, pGMainContext != null, E_SYSTEM,
81                                 "Can't get GMainContext.");
82
83         timerFd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
84         SysTryReturnResult(NID_BASE_RT, timerFd != -1, E_SYSTEM, "failed to create a timerfd.");
85
86         pGIOChannel = g_io_channel_unix_new(timerFd);
87         SysTryCatch(NID_BASE_RT, pGIOChannel != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to create a GIOChannel for timerfd.");
88
89         g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
90         __timerFd = timerFd;
91         timerFd = -1;
92
93         pGSource = g_io_create_watch(pGIOChannel, G_IO_IN);
94         SysTryCatch(NID_BASE_RT, pGSource != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to create a GSource for timerfd.");
95
96         g_source_set_callback(pGSource, (GSourceFunc) _TimerImpl::OnTimerExpired, this, null);
97         g_source_attach(pGSource, pGMainContext);
98
99         __pTimerIo = pGIOChannel;
100         __pTimerSource = pGSource;
101
102         __pTimer = const_cast <Timer*>(&timer);
103         __pTimerEventListener = &listener;
104
105         return E_SUCCESS;
106
107 CATCH:
108         if (pGIOChannel != null)
109         {
110                 g_io_channel_unref(pGIOChannel);
111         }
112
113         if (timerFd != -1)
114         {
115                 close(timerFd);
116         }
117
118         return r;
119 }
120
121 result
122 _TimerImpl::Construct(const Timer& timer, ITimerEventListener& listener, bool awake)
123 {
124         return Construct(timer, listener);
125 }
126
127 gboolean
128 _TimerImpl::OnTimerExpired(GIOChannel* pGIOChannel, GIOCondition condition, gpointer data)
129 {
130         uint64_t exp = 0;
131         _TimerImpl* pTimerImpl = (_TimerImpl*) data;
132
133         if (condition & G_IO_IN)
134         {
135                 ssize_t ret = read(pTimerImpl->__timerFd, &exp, sizeof(uint64_t));
136                 SysTryLog(NID_BASE_RT, ret >= 0, "Timer read failure : %s.", strerror(errno));
137
138                 if (pTimerImpl->__status != TIMER_STATUS_ACTIVATED_REPEATABLE)
139                 {
140                         pTimerImpl->__status = TIMER_STATUS_EXPIRED;
141                 }
142                 else
143                 {
144                         pTimerImpl->__status = TIMER_STATUS_ACTIVATED_REPEATABLE;
145                 }               
146                 pTimerImpl->__pTimerEventListener->OnTimerExpired(*pTimerImpl->__pTimer);
147         }
148
149         return TRUE;
150 }
151
152 result
153 _TimerImpl::Start(int timeout)
154 {
155         int ret = -1;
156         struct timespec now;
157         struct itimerspec newTimeout;
158
159         SysTryReturnResult(NID_BASE_RT, (__status != TIMER_STATUS_ACTIVATED) && (__status != TIMER_STATUS_ACTIVATED_REPEATABLE), E_INVALID_STATE, "Timer is already started.");
160         SysTryReturnResult(NID_BASE_RT, __pTimerEventListener != null, E_INVALID_STATE, "not initialized.");
161
162         if (Tizen::App::_AppInfo::GetApiVersion() == _API_VERSION_2_0 && Tizen::App::_AppInfo::IsOspCompat())
163         {
164                 SysTryReturnResult(NID_BASE_RT, timeout > 0, E_INVALID_ARG, "timeout should be greater than 0.");
165         }
166         else
167         {
168                 SysTryReturnResult(NID_BASE_RT, (timeout > 0) || (timeout == 0), E_INVALID_ARG, "timeout should not be less than 0.");
169         }
170
171         clock_gettime(CLOCK_MONOTONIC, &now);
172
173         if (timeout != 0)
174         {
175                 newTimeout.it_value.tv_sec = now.tv_sec + timeout / 1000;
176                 newTimeout.it_value.tv_nsec = now.tv_nsec + (timeout % 1000) * 1000000;
177         }
178         else
179         {
180                 newTimeout.it_value.tv_sec = now.tv_sec;
181                 newTimeout.it_value.tv_nsec = now.tv_nsec + 1;
182         }
183
184         if (newTimeout.it_value.tv_nsec >= 1000000000)
185         {
186                 newTimeout.it_value.tv_sec += 1;
187                 newTimeout.it_value.tv_nsec -= 1000000000;
188         }
189
190         newTimeout.it_interval.tv_sec = 0;
191         newTimeout.it_interval.tv_nsec = 0;
192
193         ret = timerfd_settime(__timerFd, TFD_TIMER_ABSTIME, &newTimeout, null);
194         SysTryReturnResult(NID_BASE_RT, ret != -1, E_SYSTEM, "Failed to set timeout.");
195
196         __status = TIMER_STATUS_ACTIVATED;
197
198         return E_SUCCESS;
199 }
200
201 result
202 _TimerImpl::StartAsRepeatable(int interval)
203 {
204         int ret = -1;
205         struct timespec now;
206         struct itimerspec newTimeout;
207
208         SysTryReturnResult(NID_BASE_RT, (__status != TIMER_STATUS_ACTIVATED) && (__status != TIMER_STATUS_ACTIVATED_REPEATABLE), E_INVALID_STATE, "Timer is already started.");
209         SysTryReturnResult(NID_BASE_RT, interval > 0, E_INVALID_ARG, "interval should greater than 0.");
210         SysTryReturnResult(NID_BASE_RT, __pTimerEventListener != null, E_INVALID_STATE, "not initialized.");
211
212         clock_gettime(CLOCK_MONOTONIC, &now);
213
214         newTimeout.it_value.tv_sec = now.tv_sec + interval / 1000;
215         newTimeout.it_value.tv_nsec = now.tv_nsec + (interval % 1000) * 1000000;
216         if (newTimeout.it_value.tv_nsec >= 1000000000)
217         {
218                 newTimeout.it_value.tv_sec += 1;
219                 newTimeout.it_value.tv_nsec -= 1000000000;
220         }
221
222         newTimeout.it_interval.tv_sec = interval / 1000;
223         newTimeout.it_interval.tv_nsec = (interval % 1000)*1000000;
224
225         ret = timerfd_settime(__timerFd, TFD_TIMER_ABSTIME, &newTimeout, null);
226         SysTryReturnResult(NID_BASE_RT, ret != -1, E_SYSTEM, "Failed to set interval.");
227
228         __status = TIMER_STATUS_ACTIVATED_REPEATABLE;
229
230         return E_SUCCESS;
231 }
232
233 result
234 _TimerImpl::Cancel(void)
235 {
236         int ret = -1;
237         struct itimerspec newTimeout;
238         SysTryReturnResult(NID_BASE_RT, (__status == TIMER_STATUS_ACTIVATED) || (__status == TIMER_STATUS_ACTIVATED_REPEATABLE), E_INVALID_STATE, "Timer is not started.");
239
240         newTimeout.it_value.tv_sec = 0;
241         newTimeout.it_value.tv_nsec = 0;
242         newTimeout.it_interval.tv_sec = 0;
243         newTimeout.it_interval.tv_nsec = 0;
244
245         ret = timerfd_settime(__timerFd, TFD_TIMER_ABSTIME, &newTimeout, null);
246         SysTryReturnResult(NID_BASE_RT, ret != -1, E_SYSTEM, "Failed to unset timeout.");
247
248         __status = TIMER_STATUS_CANCELED;
249
250         return E_SUCCESS;
251 }
252
253 } } } // Tizen::Runtime