#define MILLIS_PER_MIN 60000
#define TIMER_ID (++__timerCnt)
-#define INIT_CONTEXT if (!__context) __context = g_main_context_ref_thread_default()
using namespace ctx;
-static std::atomic_uint __timerCnt;
-struct ctx::Timer::ListenerInfo {
- Timer* timer;
- ITimerListener* listener;
+class Timer::TimerInstance {
+protected:
+ Timer* hostTimer;
unsigned int timerId;
unsigned int intervalMs;
- GSource* gSrc;
- int alarmId;
- ListenerInfo(Timer* t, ITimerListener* l) :
- timer(t),
- listener(l),
- timerId(0),
- intervalMs(0),
- gSrc(NULL),
- alarmId(-1) {}
+ void* userData;
+ ITimerListener* timerListener;
+ GSourceFunc sourceFunc;
+
+private:
+ bool __onListenerExpired()
+ {
+ _D("Expire <Id: %u, Interval: %u ms>", timerId, intervalMs);
+
+ bool cont = timerListener->onTimerExpired(timerId, intervalMs, userData);
+ if (!cont) {
+ deregisterSelf();
+ delete this;
+ return false;
+ }
+ return true;
+ }
+
+ bool __onFunctionExpired()
+ {
+ _D("Expire <Id: %u, Interval: %u ms>", timerId, intervalMs);
+
+ gboolean cont = sourceFunc(userData);
+ if (cont == G_SOURCE_REMOVE) {
+ deregisterSelf();
+ delete this;
+ return false;
+ }
+ return true;
+ }
+
+protected:
+ TimerInstance(Timer* t, unsigned int tid, unsigned int interval, void* data) :
+ hostTimer(t),
+ timerId(tid),
+ intervalMs(interval),
+ userData(data),
+ timerListener(NULL),
+ sourceFunc(NULL)
+ {
+ }
+
+ void registerSelf()
+ {
+ hostTimer->__timerInstances.push_back(this);
+ }
+
+ void deregisterSelf()
+ {
+ hostTimer->__timerInstances.remove(this);
+ }
+
+ GMainContext* getMainContext()
+ {
+ return hostTimer->__mainContext;
+ }
+
+ static gboolean onListenerExpired(gpointer data)
+ {
+ if (static_cast<TimerInstance*>(data)->__onListenerExpired())
+ return G_SOURCE_CONTINUE;
+
+ return G_SOURCE_REMOVE;
+ }
+
+ static gboolean onFunctionExpired(gpointer data)
+ {
+ if (static_cast<TimerInstance*>(data)->__onFunctionExpired())
+ return G_SOURCE_CONTINUE;
+
+ return G_SOURCE_REMOVE;
+ }
+
+public:
+ unsigned int getId()
+ {
+ return timerId;
+ }
+
+ virtual ~TimerInstance() {}
+
+ virtual bool run() = 0;
+ virtual void terminate() = 0;
};
-Timer::Timer() :
- __context(NULL)
-{
-}
-Timer::Timer(GMainContext* mainContext) :
- __context(mainContext)
-{
- if (__context)
- g_main_context_ref(__context);
-}
+class Timer::IdleListener : public Timer::TimerInstance {
+private:
+ GSource* __gSrc;
-Timer::Timer(ServiceBase* hostService) :
- Timer(hostService->getMainContext())
-{
-}
+public:
+ IdleListener(Timer* t, unsigned int tid, ITimerListener* listener, void* data) :
+ TimerInstance(t, tid, 0, data),
+ __gSrc(NULL)
+ {
+ timerListener = listener;
+ }
-Timer::~Timer()
-{
- cancelAll();
+ ~IdleListener() {}
- if (__context)
- g_main_context_unref(__context);
-}
+ bool run()
+ {
+ _D("Add <Id: %u, Interval: %u ms>", timerId, intervalMs);
-unsigned int Timer::schedule(unsigned int intervalMs, ITimerListener* listener)
-{
- IF_FAIL_RETURN(listener, 0);
+ __gSrc = g_idle_source_new();
+ IF_FAIL_RETURN_TAG(__gSrc, false, _E, E_STR_ALLOC);
- if (intervalMs == 0)
- return addIdle(listener);
+ g_source_set_callback(__gSrc, onListenerExpired, this, NULL);
+ g_source_attach(__gSrc, getMainContext());
+ g_source_unref(__gSrc);
- if (intervalMs < MILLIS_PER_MIN)
- return addTimeout(intervalMs, listener);
+ registerSelf();
- unsigned int intervalMin = intervalMs / MILLIS_PER_MIN;
- return addAlarm(intervalMin, listener);
-}
+ return true;
+ }
-void Timer::cancel(unsigned int timerId)
-{
- auto iter = __listeners.begin();
+ void terminate()
+ {
+ _D("Remove <Id: %u, Interval: %u ms>", timerId, intervalMs);
+
+ deregisterSelf();
+
+ g_source_destroy(__gSrc);
+ g_source_unref(__gSrc);
- while (iter != __listeners.end() && (*iter)->timerId != timerId) {
- ++iter;
+ delete this;
}
+};
- IF_FAIL_VOID_TAG(iter != __listeners.end(), _W, "Unknown timer (%d)", timerId);
- if ((*iter)->gSrc)
- __removeGSource(*iter);
- else
- __removeAlarm(*iter);
+class Timer::IdleFunction : public Timer::TimerInstance {
+private:
+ GSource* __gSrc;
- __listeners.erase(iter);
-}
+public:
+ IdleFunction(Timer* t, unsigned int tid, GSourceFunc func, void* data) :
+ TimerInstance(t, tid, 0, data),
+ __gSrc(NULL)
+ {
+ sourceFunc = func;
+ }
-void Timer::cancelAll()
-{
- auto iter = __listeners.begin();
+ ~IdleFunction() {}
+
+ bool run()
+ {
+ _D("Add <Id: %u, Interval: %u ms>", timerId, intervalMs);
- while (iter != __listeners.end()) {
- if ((*iter)->gSrc)
- __removeGSource(*iter);
- else
- __removeAlarm(*iter);
+ __gSrc = g_idle_source_new();
+ IF_FAIL_RETURN_TAG(__gSrc, false, _E, E_STR_ALLOC);
- iter = __listeners.erase(iter);
+ g_source_set_callback(__gSrc, onFunctionExpired, this, NULL);
+ g_source_attach(__gSrc, getMainContext());
+ g_source_unref(__gSrc);
+
+ registerSelf();
+
+ return true;
}
-}
-unsigned int Timer::addIdle(ITimerListener* listener)
-{
- INIT_CONTEXT;
+ void terminate()
+ {
+ _D("Remove <Id: %u, Interval: %u ms>", timerId, intervalMs);
- GSource* gSrc = g_idle_source_new();
- IF_FAIL_RETURN_TAG(gSrc, 0, _E, E_STR_ALLOC);
+ deregisterSelf();
- ListenerInfo* info = new ListenerInfo(this, listener);
+ g_source_destroy(__gSrc);
+ g_source_unref(__gSrc);
- info->timerId = TIMER_ID;
- info->gSrc = gSrc;
+ delete this;
+ }
+};
- _D("Add Idle <Id: %u>", info->timerId);
- __listeners.insert(info);
- g_source_set_callback(gSrc, __onGSourceExpired, info, NULL);
- g_source_attach(gSrc, __context);
- g_source_unref(gSrc);
+class Timer::TimeoutListener : public Timer::TimerInstance {
+private:
+ GSource* __gSrc;
- return info->timerId;
-}
+public:
+ TimeoutListener(Timer* t, unsigned int tid, unsigned int interval, ITimerListener* listener, void* data) :
+ TimerInstance(t, tid, interval, data),
+ __gSrc(NULL)
+ {
+ timerListener = listener;
+ }
-unsigned int Timer::addTimeout(unsigned int intervalMs, ITimerListener* listener)
-{
- INIT_CONTEXT;
+ ~TimeoutListener() {}
- GSource* gSrc = g_timeout_source_new(intervalMs);
- IF_FAIL_RETURN_TAG(gSrc, 0, _E, E_STR_ALLOC);
+ bool run()
+ {
+ _D("Add <Id: %u, Interval: %u ms>", timerId, intervalMs);
- ListenerInfo* info = new ListenerInfo(this, listener);
+ __gSrc = g_timeout_source_new(intervalMs);
+ IF_FAIL_RETURN_TAG(__gSrc, false, _E, E_STR_ALLOC);
- info->timerId = TIMER_ID;
- info->intervalMs = intervalMs;
- info->gSrc = gSrc;
+ g_source_set_callback(__gSrc, onListenerExpired, this, NULL);
+ g_source_attach(__gSrc, getMainContext());
+ g_source_unref(__gSrc);
- _D("Add Timeout <Id: %u, Interval: %u ms>", info->timerId, intervalMs);
- __listeners.insert(info);
+ registerSelf();
- g_source_set_callback(gSrc, __onGSourceExpired, info, NULL);
- g_source_attach(gSrc, __context);
- g_source_unref(gSrc);
+ return true;
+ }
- return info->timerId;
-}
+ void terminate()
+ {
+ _D("Remove <Id: %u, Interval: %u ms>", timerId, intervalMs);
-gboolean Timer::__onGSourceExpired(gpointer userData)
-{
- ListenerInfo* info = static_cast<ListenerInfo*>(userData);
- _D("Expire <Id: %u, Interval: %u ms>", info->timerId, info->intervalMs);
+ deregisterSelf();
- bool cont = info->listener->onExpired(info->timerId, info->intervalMs);
+ g_source_destroy(__gSrc);
+ g_source_unref(__gSrc);
- if (!cont) {
- _D("Remove <Id: %u, Interval: %u ms>", info->timerId, info->intervalMs);
- info->timer->__listeners.erase(info);
- delete info;
- return G_SOURCE_REMOVE;
+ delete this;
}
+};
- return G_SOURCE_CONTINUE;
-}
-void Timer::__removeGSource(ListenerInfo* info)
-{
- _D("Remove <Id: %u, Interval: %u ms>", info->timerId, info->intervalMs);
- g_source_destroy(info->gSrc);
- g_source_unref(info->gSrc);
- delete info;
-}
+class Timer::TimeoutFunction : public Timer::TimerInstance {
+private:
+ GSource* __gSrc;
-unsigned int Timer::addAlarm(unsigned int intervalMin, ITimerListener* listener)
-{
- INIT_CONTEXT;
+public:
+ TimeoutFunction(Timer* t, unsigned int tid, unsigned int interval, GSourceFunc func, void* data) :
+ TimerInstance(t, tid, interval, data),
+ __gSrc(NULL)
+ {
+ sourceFunc = func;
+ }
+
+ ~TimeoutFunction() {}
+
+ bool run()
+ {
+ _D("Add <Id: %u, Interval: %u ms>", timerId, intervalMs);
+
+ __gSrc = g_timeout_source_new(intervalMs);
+ IF_FAIL_RETURN_TAG(__gSrc, false, _E, E_STR_ALLOC);
+
+ g_source_set_callback(__gSrc, onFunctionExpired, this, NULL);
+ g_source_attach(__gSrc, getMainContext());
+ g_source_unref(__gSrc);
+
+ registerSelf();
+
+ return true;
+ }
+
+ void terminate()
+ {
+ _D("Remove <Id: %u, Interval: %u ms>", timerId, intervalMs);
- int alarmId, result;
+ deregisterSelf();
+
+ g_source_destroy(__gSrc);
+ g_source_unref(__gSrc);
+
+ delete this;
+ }
+};
+
+
+class Timer::AlarmListener : public Timer::TimerInstance {
+private:
+ int __alarmId;
+
+ void __onAlarmExpired(void)
+ {
+ _D("Expire <Id: %u, Interval: %u ms>", timerId, intervalMs);
+
+ bool cont = timerListener->onTimerExpired(timerId, intervalMs, userData);
+ if (!cont) {
+ deregisterSelf();
+ alarmmgr_remove_alarm(__alarmId);
+ delete this;
+ }
+ }
- ListenerInfo* info = new ListenerInfo(this, listener);
+ static gboolean __onAlarmExpired(gpointer userData)
+ {
+ static_cast<AlarmListener*>(userData)->__onAlarmExpired();
+ return G_SOURCE_REMOVE;
+ }
- info->intervalMs = intervalMin * MILLIS_PER_MIN;
+ static int __alarmMgrCb(int alarmId, void* userData)
+ {
+ GSource* gSrc = g_idle_source_new();
+ IF_FAIL_RETURN_TAG(gSrc, 0, _E, E_STR_ALLOC);
- result = alarmmgr_add_periodic_alarm_withcb(intervalMin, QUANTUMIZE, __alarmMgrCb, info, &alarmId);
+ g_source_set_callback(gSrc, __onAlarmExpired, userData, NULL);
+ g_source_attach(gSrc, static_cast<AlarmListener*>(userData)->getMainContext());
+ g_source_unref(gSrc);
- if (result != ALARMMGR_RESULT_SUCCESS) {
- delete info;
return 0;
}
- info->timerId = TIMER_ID;
- info->alarmId = alarmId;
+public:
+ AlarmListener(Timer* t, unsigned int tid, unsigned int interval, ITimerListener* listener, void* data) :
+ TimerInstance(t, tid, interval, data),
+ __alarmId(-1)
+ {
+ timerListener = listener;
+ }
+
+ ~AlarmListener() {}
+
+ bool run()
+ {
+ unsigned int intervalMin = intervalMs / MILLIS_PER_MIN;
+ int result = alarmmgr_add_periodic_alarm_withcb(intervalMin, QUANTUMIZE, __alarmMgrCb, this, &__alarmId);
+ IF_FAIL_RETURN(result == ALARMMGR_RESULT_SUCCESS, false);
+
+ _D("Add <Id: %u (%d), Interval: %u ms>", timerId, __alarmId, intervalMs);
+
+ registerSelf();
+
+ return true;
+ }
+
+ void terminate()
+ {
+ _D("Remove <Id: %u (%d), Interval: %u ms>", timerId, __alarmId, intervalMs);
+
+ deregisterSelf();
+
+ alarmmgr_remove_alarm(__alarmId);
+
+ delete this;
+ }
+};
+
+
+static std::atomic_uint __timerCnt;
+
+Timer::Timer(GMainContext* mainContext) :
+ __mainContext(mainContext)
+{
+}
- _D("Add Alarm <Id: %u (%d), Interval: %u ms>", info->timerId, alarmId, info->intervalMs);
- __listeners.insert(info);
+Timer::Timer(ServiceBase* hostService) :
+ Timer(hostService->getMainContext())
+{
+}
- return info->timerId;
+Timer::~Timer()
+{
+ cancelAll();
}
-int Timer::__alarmMgrCb(int alarmId, void *userData)
+unsigned int Timer::schedule(unsigned int intervalMs, ITimerListener* listener, void* userData)
{
- ListenerInfo* info = static_cast<ListenerInfo*>(userData);
- _D("Id: %u (%d), Interval: %u ms", info->timerId, info->alarmId, info->intervalMs);
+ IF_FAIL_RETURN(listener, 0);
- GSource* gSrc = g_idle_source_new();
- IF_FAIL_RETURN_TAG(gSrc, 0, _E, E_STR_ALLOC);
+ if (intervalMs == 0)
+ return addIdle(listener, userData);
- g_source_set_callback(gSrc, __onAlarmExpired, userData, NULL);
- g_source_attach(gSrc, info->timer->__context);
- g_source_unref(gSrc);
+ if (intervalMs < MILLIS_PER_MIN)
+ return addTimeout(intervalMs, listener, userData);
- return 0;
+ unsigned int intervalMin = intervalMs / MILLIS_PER_MIN;
+ return addAlarm(intervalMin, listener, userData);
}
-gboolean Timer::__onAlarmExpired(gpointer userData)
+void Timer::cancel(unsigned int timerId)
{
- ListenerInfo* info = static_cast<ListenerInfo*>(userData);
- _D("Expire <Id: %u, Interval: %u ms>", info->timerId, info->intervalMs);
+ for (auto it = __timerInstances.begin(); it != __timerInstances.end(); ++it) {
+ if ((*it)->getId() == timerId) {
+ (*it)->terminate();
+ return;
+ }
+ }
- bool cont = info->listener->onExpired(info->timerId, info->intervalMs);
+ _W("Unknown TimerId: %u", timerId);
+}
- if (!cont) {
- info->timer->__listeners.erase(info);
- info->timer->__removeAlarm(info);
+void Timer::cancelAll()
+{
+ for (auto it = __timerInstances.begin(); it != __timerInstances.end();) {
+ TimerInstance* tInst = *it;
+ ++it;
+ tInst->terminate();
}
+}
+
+unsigned int Timer::addIdle(ITimerListener* listener, void* userData)
+{
+ TimerInstance* tInst = new IdleListener(this, TIMER_ID, listener, userData);
+ return __run(tInst);
+}
+
+unsigned int Timer::addIdle(GSourceFunc callback, void* userData)
+{
+ TimerInstance* tInst = new IdleFunction(this, TIMER_ID, callback, userData);
+ return __run(tInst);
+}
- return G_SOURCE_REMOVE;
+unsigned int Timer::addTimeout(unsigned int intervalMs, ITimerListener* listener, void* userData)
+{
+ TimerInstance* tInst = new TimeoutListener(this, TIMER_ID, intervalMs, listener, userData);
+ return __run(tInst);
}
-void Timer::__removeAlarm(ListenerInfo* info)
+unsigned int Timer::addTimeout(unsigned int intervalMs, GSourceFunc callback, void* userData)
{
- _D("Remove <Id: %u, Interval: %u ms>", info->timerId, info->intervalMs);
- alarmmgr_remove_alarm(info->alarmId);
- delete info;
+ TimerInstance* tInst = new TimeoutFunction(this, TIMER_ID, intervalMs, callback, userData);
+ return __run(tInst);
+}
+
+unsigned int Timer::addAlarm(unsigned int intervalMin, ITimerListener* listener, void* userData)
+{
+ TimerInstance* tInst = new AlarmListener(this, TIMER_ID, intervalMin * MILLIS_PER_MIN, listener, userData);
+ return __run(tInst);
+}
+
+unsigned int Timer::__run(TimerInstance* tInst)
+{
+ if (!tInst->run()) {
+ _E("Timer starting failed");
+ delete tInst;
+ return 0;
+ }
+ return tInst->getId();
}