server: refactor Timer to accept GSourceFunc as callback points 99/127299/3
authorMu-Woong Lee <muwoong.lee@samsung.com>
Thu, 27 Apr 2017 04:12:48 +0000 (13:12 +0900)
committerMu-Woong Lee <muwoong.lee@samsung.com>
Thu, 27 Apr 2017 06:03:00 +0000 (15:03 +0900)
Change-Id: I7465cf32491c3c648e55e2811c3181ffaa4c7c50
Signed-off-by: Mu-Woong Lee <muwoong.lee@samsung.com>
include/ITimerListener.h
include/Timer.h
src/server/Timer.cpp

index 1dde2ae..4d2571a 100644 (file)
@@ -25,7 +25,7 @@ namespace ctx {
        public:
                virtual ~ITimerListener() {}
 
-               virtual bool onExpired(unsigned int timerId, unsigned int intervalMs) = 0;
+               virtual bool onTimerExpired(unsigned int timerId, unsigned int intervalMs, void* userData) = 0;
        };
 
 }
index 3e0d019..6a226d2 100644 (file)
@@ -17,7 +17,7 @@
 #ifndef __CONTEXT_TIMER_H__
 #define __CONTEXT_TIMER_H__
 
-#include <set>
+#include <list>
 #include <ContextTypes.h>
 
 namespace ctx {
@@ -28,40 +28,41 @@ namespace ctx {
        /* All timers expire in the context where the Timer object is created. */
        class EXPORT_API Timer {
        public:
-               Timer();
                Timer(ServiceBase* hostService);
                Timer(GMainContext* mainContext);
+
                ~Timer();
 
                /* This is a helper function that chooses and executes one of the below three functions. */
-               unsigned int schedule(unsigned int intervalMs, ITimerListener* listener);
+               unsigned int schedule(unsigned int intervalMs, ITimerListener* listener, void* userData);
 
                void cancel(unsigned int timerId);
                void cancelAll();
 
                /* This runs in a simliar manner to g_idle_add(). */
-               unsigned int addIdle(ITimerListener* listener);
+               unsigned int addIdle(ITimerListener* listener, void* userData);
+               unsigned int addIdle(GSourceFunc callback, gpointer userData);
 
                /* This runs in a simliar manner to g_timeout_add(). */
-               unsigned int addTimeout(unsigned int intervalMs, ITimerListener* listener);
+               unsigned int addTimeout(unsigned int intervalMs, ITimerListener* listener, void* userData);
+               unsigned int addTimeout(unsigned int intervalMs, GSourceFunc callback, gpointer userData);
 
                /* This runs on the alarm-service, thus the device will be woken up whenever the interval passes.
                   Unlike the above functions, this takes an interval in minutes. */
-               unsigned int addAlarm(unsigned int intervalMin, ITimerListener* listener);
+               unsigned int addAlarm(unsigned int intervalMin, ITimerListener* listener, void* userData);
 
        private:
-               struct ListenerInfo;
-
-               static gboolean __onGSourceExpired(gpointer userData);
-               static gboolean __onAlarmExpired(gpointer userData);
-               static int __alarmMgrCb(int alarmId, void *userData);
-
-               void __removeGSource(ListenerInfo* info);
-               void __removeAlarm(ListenerInfo* info);
+               class TimerInstance;
+               class IdleListener;
+               class IdleFunction;
+               class TimeoutListener;
+               class TimeoutFunction;
+               class AlarmListener;
 
-               GMainContext* __context;
+               unsigned int __run(TimerInstance* tInst);
 
-               std::set<ListenerInfo*> __listeners;
+               GMainContext* __mainContext;
+               std::list<TimerInstance*> __timerInstances;
        };
 
 }
index 7256509..71fab3d 100644 (file)
 
 #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();
 }