2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @file FBaseRt_TimerImpl.cpp
19 * @brief This is the implementation file for the _TimerImpl class.
25 #include <sys/timerfd.h>
29 #include <FBaseRtTimer.h>
31 #include "FApp_AppInfo.h"
32 #include <FBaseSysLog.h>
33 #include "FBaseRt_EventDispatcher.h"
34 #include "FBaseRt_TimerImpl.h"
37 namespace Tizen { namespace Base { namespace Runtime
40 _TimerImpl::_TimerImpl(void)
44 , __pTimerSource(null)
45 , __pTimerEventListener(null)
46 , __status(TIMER_STATUS_NOT_ACTIVATED)
51 _TimerImpl::~_TimerImpl(void)
53 if (__pTimerSource != null)
55 g_source_destroy(__pTimerSource);
56 g_source_unref(__pTimerSource);
59 if (__pTimerIo != null)
61 g_io_channel_unref(__pTimerIo);
66 _TimerImpl::Construct(const Timer& timer, ITimerEventListener& listener)
70 GIOChannel* pGIOChannel = null;
71 GSource* pGSource = null;
72 _EventDispatcher* pEventDispatcher = null;
73 GMainContext* pGMainContext = null;
75 pEventDispatcher = _EventDispatcher::GetCurrentEventDispatcher();
76 SysTryReturnResult(NID_BASE_RT, pEventDispatcher != null, E_SYSTEM,
77 "Called by a worker thread.");
79 pGMainContext = pEventDispatcher->GetGMainContext();
80 SysTryReturnResult(NID_BASE_RT, pGMainContext != null, E_SYSTEM,
81 "Can't get GMainContext.");
83 timerFd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
84 SysTryReturnResult(NID_BASE_RT, timerFd != -1, E_SYSTEM, "failed to create a timerfd.");
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.");
89 g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
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.");
96 g_source_set_callback(pGSource, (GSourceFunc) _TimerImpl::OnTimerExpired, this, null);
97 g_source_attach(pGSource, pGMainContext);
99 __pTimerIo = pGIOChannel;
100 __pTimerSource = pGSource;
102 __pTimer = const_cast <Timer*>(&timer);
103 __pTimerEventListener = &listener;
108 if (pGIOChannel != null)
110 g_io_channel_unref(pGIOChannel);
122 _TimerImpl::Construct(const Timer& timer, ITimerEventListener& listener, bool awake)
124 return Construct(timer, listener);
128 _TimerImpl::OnTimerExpired(GIOChannel* pGIOChannel, GIOCondition condition, gpointer data)
131 _TimerImpl* pTimerImpl = (_TimerImpl*) data;
133 if (condition & G_IO_IN)
135 ssize_t ret = read(pTimerImpl->__timerFd, &exp, sizeof(uint64_t));
136 SysTryLog(NID_BASE_RT, ret >= 0, "Timer read failure : %s.", strerror(errno));
138 if (pTimerImpl->__status != TIMER_STATUS_ACTIVATED_REPEATABLE)
140 pTimerImpl->__status = TIMER_STATUS_EXPIRED;
144 pTimerImpl->__status = TIMER_STATUS_ACTIVATED_REPEATABLE;
146 pTimerImpl->__pTimerEventListener->OnTimerExpired(*pTimerImpl->__pTimer);
153 _TimerImpl::Start(int timeout)
157 struct itimerspec newTimeout;
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.");
162 if (Tizen::App::_AppInfo::GetApiVersion() == _API_VERSION_2_0 && Tizen::App::_AppInfo::IsOspCompat())
164 SysTryReturnResult(NID_BASE_RT, timeout > 0, E_INVALID_ARG, "timeout should be greater than 0.");
168 SysTryReturnResult(NID_BASE_RT, (timeout > 0) || (timeout == 0), E_INVALID_ARG, "timeout should not be less than 0.");
171 clock_gettime(CLOCK_MONOTONIC, &now);
175 newTimeout.it_value.tv_sec = now.tv_sec + timeout / 1000;
176 newTimeout.it_value.tv_nsec = now.tv_nsec + (timeout % 1000) * 1000000;
180 newTimeout.it_value.tv_sec = now.tv_sec;
181 newTimeout.it_value.tv_nsec = now.tv_nsec + 1;
184 if (newTimeout.it_value.tv_nsec >= 1000000000)
186 newTimeout.it_value.tv_sec += 1;
187 newTimeout.it_value.tv_nsec -= 1000000000;
190 newTimeout.it_interval.tv_sec = 0;
191 newTimeout.it_interval.tv_nsec = 0;
193 ret = timerfd_settime(__timerFd, TFD_TIMER_ABSTIME, &newTimeout, null);
194 SysTryReturnResult(NID_BASE_RT, ret != -1, E_SYSTEM, "Failed to set timeout.");
196 __status = TIMER_STATUS_ACTIVATED;
202 _TimerImpl::StartAsRepeatable(int interval)
206 struct itimerspec newTimeout;
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.");
212 clock_gettime(CLOCK_MONOTONIC, &now);
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)
218 newTimeout.it_value.tv_sec += 1;
219 newTimeout.it_value.tv_nsec -= 1000000000;
222 newTimeout.it_interval.tv_sec = interval / 1000;
223 newTimeout.it_interval.tv_nsec = (interval % 1000)*1000000;
225 ret = timerfd_settime(__timerFd, TFD_TIMER_ABSTIME, &newTimeout, null);
226 SysTryReturnResult(NID_BASE_RT, ret != -1, E_SYSTEM, "Failed to set interval.");
228 __status = TIMER_STATUS_ACTIVATED_REPEATABLE;
234 _TimerImpl::Cancel(void)
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.");
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;
245 ret = timerfd_settime(__timerFd, TFD_TIMER_ABSTIME, &newTimeout, null);
246 SysTryReturnResult(NID_BASE_RT, ret != -1, E_SYSTEM, "Failed to unset timeout.");
248 __status = TIMER_STATUS_CANCELED;
253 } } } // Tizen::Runtime