2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 * @file FBaseRt_TimerImpl.cpp
20 * @brief This is the implementation file for the _TimerImpl class.
26 #include <sys/timerfd.h>
30 #include <FBaseRtTimer.h>
32 #include "FApp_AppInfo.h"
33 #include <FBaseSysLog.h>
34 #include "FBaseRt_EventDispatcher.h"
35 #include "FBaseRt_TimerImpl.h"
38 namespace Tizen { namespace Base { namespace Runtime
41 _TimerImpl::_TimerImpl(void)
45 , __pTimerSource(null)
46 , __pTimerEventListener(null)
47 , __status(TIMER_STATUS_NOT_ACTIVATED)
52 _TimerImpl::~_TimerImpl(void)
54 if (__pTimerSource != null)
56 g_source_destroy(__pTimerSource);
57 g_source_unref(__pTimerSource);
60 if (__pTimerIo != null)
62 g_io_channel_unref(__pTimerIo);
67 _TimerImpl::Construct(const Timer& timer, ITimerEventListener& listener)
71 GIOChannel* pGIOChannel = null;
72 GSource* pGSource = null;
73 _EventDispatcher* pEventDispatcher = null;
74 GMainContext* pGMainContext = null;
76 pEventDispatcher = _EventDispatcher::GetCurrentEventDispatcher();
77 SysTryReturnResult(NID_BASE_RT, pEventDispatcher != null, E_SYSTEM,
78 "Called by a worker thread.");
80 pGMainContext = pEventDispatcher->GetGMainContext();
81 SysTryReturnResult(NID_BASE_RT, pGMainContext != null, E_SYSTEM,
82 "Can't get GMainContext.");
84 timerFd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
85 SysTryReturnResult(NID_BASE_RT, timerFd != -1, E_SYSTEM, "failed to create a timerfd.");
87 pGIOChannel = g_io_channel_unix_new(timerFd);
88 SysTryCatch(NID_BASE_RT, pGIOChannel != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to create a GIOChannel for timerfd.");
90 g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
94 pGSource = g_io_create_watch(pGIOChannel, G_IO_IN);
95 SysTryCatch(NID_BASE_RT, pGSource != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to create a GSource for timerfd.");
97 g_source_set_callback(pGSource, (GSourceFunc) _TimerImpl::OnTimerExpired, this, null);
98 g_source_attach(pGSource, pGMainContext);
100 __pTimerIo = pGIOChannel;
101 __pTimerSource = pGSource;
103 __pTimer = const_cast <Timer*>(&timer);
104 __pTimerEventListener = &listener;
109 if (pGIOChannel != null)
111 g_io_channel_unref(pGIOChannel);
123 _TimerImpl::Construct(const Timer& timer, ITimerEventListener& listener, bool awake)
125 return Construct(timer, listener);
129 _TimerImpl::OnTimerExpired(GIOChannel* pGIOChannel, GIOCondition condition, gpointer data)
132 _TimerImpl* pTimerImpl = (_TimerImpl*) data;
134 if (condition & G_IO_IN)
136 ssize_t ret = read(pTimerImpl->__timerFd, &exp, sizeof(uint64_t));
137 SysTryLog(NID_BASE_RT, ret >= 0, "Timer read failure : %s.", strerror(errno));
139 if (pTimerImpl->__status != TIMER_STATUS_ACTIVATED_REPEATABLE)
141 pTimerImpl->__status = TIMER_STATUS_EXPIRED;
145 pTimerImpl->__status = TIMER_STATUS_ACTIVATED_REPEATABLE;
147 pTimerImpl->__pTimerEventListener->OnTimerExpired(*pTimerImpl->__pTimer);
154 _TimerImpl::Start(int timeout)
158 struct itimerspec newTimeout;
160 SysTryReturnResult(NID_BASE_RT, (__status != TIMER_STATUS_ACTIVATED) && (__status != TIMER_STATUS_ACTIVATED_REPEATABLE), E_INVALID_STATE, "Timer is already started.");
161 SysTryReturnResult(NID_BASE_RT, __pTimerEventListener != null, E_INVALID_STATE, "not initialized.");
163 if (Tizen::App::_AppInfo::GetApiVersion() == _API_VERSION_2_0 && Tizen::App::_AppInfo::IsOspCompat())
165 SysTryReturnResult(NID_BASE_RT, timeout > 0, E_INVALID_ARG, "timeout should be greater than 0.");
169 SysTryReturnResult(NID_BASE_RT, (timeout > 0) || (timeout == 0), E_INVALID_ARG, "timeout should not be less than 0.");
172 clock_gettime(CLOCK_MONOTONIC, &now);
176 newTimeout.it_value.tv_sec = now.tv_sec + timeout / 1000;
177 newTimeout.it_value.tv_nsec = now.tv_nsec + (timeout % 1000) * 1000000;
181 newTimeout.it_value.tv_sec = now.tv_sec;
182 newTimeout.it_value.tv_nsec = now.tv_nsec + 1;
185 if (newTimeout.it_value.tv_nsec >= 1000000000)
187 newTimeout.it_value.tv_sec += 1;
188 newTimeout.it_value.tv_nsec -= 1000000000;
191 newTimeout.it_interval.tv_sec = 0;
192 newTimeout.it_interval.tv_nsec = 0;
194 ret = timerfd_settime(__timerFd, TFD_TIMER_ABSTIME, &newTimeout, null);
195 SysTryReturnResult(NID_BASE_RT, ret != -1, E_SYSTEM, "Failed to set timeout.");
197 __status = TIMER_STATUS_ACTIVATED;
203 _TimerImpl::StartAsRepeatable(int interval)
207 struct itimerspec newTimeout;
209 SysTryReturnResult(NID_BASE_RT, (__status != TIMER_STATUS_ACTIVATED) && (__status != TIMER_STATUS_ACTIVATED_REPEATABLE), E_INVALID_STATE, "Timer is already started.");
210 SysTryReturnResult(NID_BASE_RT, interval > 0, E_INVALID_ARG, "interval should greater than 0.");
211 SysTryReturnResult(NID_BASE_RT, __pTimerEventListener != null, E_INVALID_STATE, "not initialized.");
213 clock_gettime(CLOCK_MONOTONIC, &now);
215 newTimeout.it_value.tv_sec = now.tv_sec + interval / 1000;
216 newTimeout.it_value.tv_nsec = now.tv_nsec + (interval % 1000) * 1000000;
217 if (newTimeout.it_value.tv_nsec >= 1000000000)
219 newTimeout.it_value.tv_sec += 1;
220 newTimeout.it_value.tv_nsec -= 1000000000;
223 newTimeout.it_interval.tv_sec = interval / 1000;
224 newTimeout.it_interval.tv_nsec = (interval % 1000)*1000000;
226 ret = timerfd_settime(__timerFd, TFD_TIMER_ABSTIME, &newTimeout, null);
227 SysTryReturnResult(NID_BASE_RT, ret != -1, E_SYSTEM, "Failed to set interval.");
229 __status = TIMER_STATUS_ACTIVATED_REPEATABLE;
235 _TimerImpl::Cancel(void)
238 struct itimerspec newTimeout;
239 SysTryReturnResult(NID_BASE_RT, (__status == TIMER_STATUS_ACTIVATED) || (__status == TIMER_STATUS_ACTIVATED_REPEATABLE), E_INVALID_STATE, "Timer is not started.");
241 newTimeout.it_value.tv_sec = 0;
242 newTimeout.it_value.tv_nsec = 0;
243 newTimeout.it_interval.tv_sec = 0;
244 newTimeout.it_interval.tv_nsec = 0;
246 ret = timerfd_settime(__timerFd, TFD_TIMER_ABSTIME, &newTimeout, null);
247 SysTryReturnResult(NID_BASE_RT, ret != -1, E_SYSTEM, "Failed to unset timeout.");
249 __status = TIMER_STATUS_CANCELED;
254 } } } // Tizen::Runtime