From eb86b1eb728e0209d86630dc573c5e7c5ec919c7 Mon Sep 17 00:00:00 2001 From: Sung-jae Park Date: Wed, 4 Dec 2013 16:45:39 +0900 Subject: [PATCH] Apply force update option Change-Id: I7a54b3daac2f9204cdc1d7f0915af8251acf0f7e --- include/lb.h | 4 +- packaging/org.tizen.data-provider-slave.spec | 2 +- src/client.c | 4 +- src/lb.c | 457 ++++++++++++++++++++------- 4 files changed, 351 insertions(+), 116 deletions(-) diff --git a/include/lb.h b/include/lb.h index 1579457..9864481 100644 --- a/include/lb.h +++ b/include/lb.h @@ -26,8 +26,8 @@ extern int lb_clicked(const char *pkgname, const char *id, const char *event, do extern int lb_script_event(const char *pkgname, const char *id, const char *emission, const char *source, struct event_info *event_info); extern int lb_change_group(const char *pkgname, const char *id, const char *cluster, const char *category); -extern int lb_update(const char *pkgname, const char *id); -extern int lb_update_all(const char *pkgname, const char *cluster, const char *category); +extern int lb_update(const char *pkgname, const char *id, int force); +extern int lb_update_all(const char *pkgname, const char *cluster, const char *category, int force); extern void lb_pause_all(void); extern void lb_resume_all(void); extern int lb_set_period(const char *pkgname, const char *id, double period); diff --git a/packaging/org.tizen.data-provider-slave.spec b/packaging/org.tizen.data-provider-slave.spec index 75f1218..b8ddd7b 100644 --- a/packaging/org.tizen.data-provider-slave.spec +++ b/packaging/org.tizen.data-provider-slave.spec @@ -2,7 +2,7 @@ Name: org.tizen.data-provider-slave Summary: Plugin type livebox service provider -Version: 0.12.21 +Version: 0.12.22 Release: 1 Group: HomeTF/Livebox License: Flora diff --git a/src/client.c b/src/client.c index 9e31c30..c33e82f 100644 --- a/src/client.c +++ b/src/client.c @@ -259,10 +259,10 @@ static int method_update_content(struct event_arg *arg, void *data) if (!arg->id || !strlen(arg->id)) { DbgPrint("pkgname[%s] cluster[%s] category[%s]\n", arg->pkgname, arg->info.update_content.cluster, arg->info.update_content.category); - ret = lb_update_all(arg->pkgname, arg->info.update_content.cluster, arg->info.update_content.category); + ret = lb_update_all(arg->pkgname, arg->info.update_content.cluster, arg->info.update_content.category, arg->info.update_content.force); } else { DbgPrint("Update [%s]\n", arg->id); - ret = lb_update(arg->pkgname, arg->id); + ret = lb_update(arg->pkgname, arg->id, arg->info.update_content.force); } return ret; diff --git a/src/lb.c b/src/lb.c index 5c021d5..49aee55 100644 --- a/src/lb.c +++ b/src/lb.c @@ -52,6 +52,12 @@ int errno; #define UPDATE_INVOKED (-2) #define UPDATE_NOT_INVOKED (0) +enum pd_open_state { + PD_IS_OPENED_BUT_NOT_MINE = -1, + PD_IS_NOT_OPENED = 0, + PD_IS_OPENED = 1, +}; + struct item { Ecore_Timer *timer; struct instance *inst; @@ -84,6 +90,7 @@ static struct info { Eina_List *pd_list; int secured; int pending_timer_freezed; + int force_timer_freezed; } s_info = { .item_list = NULL, .force_update_list = NULL, @@ -98,15 +105,23 @@ static struct info { .pd_list = NULL, .secured = 0, .pending_timer_freezed = 0, + .force_timer_freezed = 0, }; static Eina_Bool updator_cb(void *data); static inline void update_monitor_del(const char *id, struct item *item); +static int append_force_update_list(struct item *item); +static void reset_lb_updated_flag(struct item *item); +static int append_pending_list(struct item *item); static void pending_timer_freeze(void) { DbgPrint("Freezed Count: %d\n", s_info.pending_timer_freezed); - if (s_info.pending_timer && !s_info.pending_timer_freezed) { + if (!s_info.pending_timer) { + return; + } + + if (!s_info.pending_timer_freezed) { DbgPrint("Freeze the pending timer\n"); ecore_timer_freeze(s_info.pending_timer); } @@ -121,19 +136,58 @@ static void pending_timer_thaw(void) return; } + if (!s_info.pending_timer) { + s_info.pending_timer_freezed = 0; + return; + } + s_info.pending_timer_freezed--; - if (s_info.pending_timer && !s_info.pending_timer_freezed) { + if (!s_info.pending_timer_freezed) { DbgPrint("Thaw the pending timer\n"); ecore_timer_thaw(s_info.pending_timer); } } +static void force_timer_freeze(void) +{ + DbgPrint("Freeze force timer: %d\n", s_info.force_timer_freezed); + if (!s_info.force_update_timer) { + return; + } + + if (!s_info.force_timer_freezed) { + DbgPrint("Force timer freezed\n"); + ecore_timer_freeze(s_info.force_update_timer); + } + + s_info.force_timer_freezed++; +} + +static void force_timer_thaw(void) +{ + DbgPrint("Freezed force count: %d\n", s_info.force_timer_freezed); + if (!s_info.force_timer_freezed) { + return; + } + + if (!s_info.force_update_timer) { + s_info.force_timer_freezed = 0; + return; + } + + s_info.force_timer_freezed--; + if (!s_info.force_timer_freezed) { + DbgPrint("Thaw the force timer\n"); + ecore_timer_thaw(s_info.force_update_timer); + } +} + /* * -1 : PD is opened, but not mine * 0 : PD is not opened * 1 : my PD is opened */ -static inline int pd_is_opened(const char *pkgname) +static inline enum pd_open_state pd_is_opened(const char *pkgname) { int i; Eina_List *l; @@ -142,13 +196,13 @@ static inline int pd_is_opened(const char *pkgname) i = 0; EINA_LIST_FOREACH(s_info.pd_list, l, inst) { if (pkgname && !strcmp(pkgname, inst->item->pkgname)) { - return 1; + return PD_IS_OPENED; } i++; } - return i > 0 ? -1 : 0; + return i > 0 ? PD_IS_OPENED_BUT_NOT_MINE : PD_IS_NOT_OPENED; } static Eina_Bool pd_open_pended_cmd_consumer_cb(void *data) @@ -182,6 +236,169 @@ cleanout: return ECORE_CALLBACK_CANCEL; } +static Eina_Bool update_timeout_cb(void *data) +{ + struct item *item; + + item = data; + + ErrPrint("UPDATE TIMEOUT ========> %s - %s\n", item->inst->item->pkgname, item->inst->id); + + if (!eina_list_data_find(s_info.update_list, item)) { + ErrPrint("Updating item is not matched\n"); + } + + fault_unmark_call(item->inst->item->pkgname, item->inst->id, "update,crashed", NO_ALARM); + fault_mark_call(item->inst->item->pkgname, item->inst->id, "update,timeout", NO_ALARM, DEFAULT_LIFE_TIMER); + s_info.update_list = eina_list_remove(s_info.update_list, item); + + exit(ETIME); + return ECORE_CALLBACK_CANCEL; +} + +static inline void update_monitor_cnt(struct item *item) +{ + double now; + double interval; + + now = util_timestamp(); + interval = now - item->update_interval; + + /*! + * \note + * If the content update is processed in too short time, + * don't increase the monitor counter, instead of it + * set the heavy updating flag. + * And handling this heavy updating from the + * file update callback. + */ + if (interval >= MINIMUM_UPDATE_INTERVAL) { + if (eina_list_data_find(s_info.update_list, item)) { + /*! + * \note + * If already in updating mode, + * reset the monitor_cnt to 1, + * all updated event will be merged into A inotify event + */ + DbgPrint("While waiting updated event, content is updated [%s]\n", item->inst->id); + item->monitor_cnt = 1; + } else { + item->monitor_cnt++; + } + } else { + item->heavy_updating = 1; + } + + item->update_interval = now; +} + +static inline void do_force_update(struct item *item) +{ + int ret; + + if (item->monitor) { /*!< If this item is already in update process */ + return; + } + + if (!IS_LB_SHOWN(item)) { + DbgPrint("%s is not shown yet. it will be added to normal pending list\n", item->inst->item->pkgname); + (void)append_force_update_list(item); + return; + } + + if (item->is_paused) { + DbgPrint("Item is paused. but it will be updated forcely(%s)\n", item->inst->item->pkgname); + } + + item->updated_in_pause = 0; + + ret = so_is_updated(item->inst); + if (ret <= 0) { + if (so_need_to_destroy(item->inst) == NEED_TO_DESTROY) { + provider_send_deleted(item->inst->item->pkgname, item->inst->id); + lb_destroy(item->inst->item->pkgname, item->inst->id); + /*! + * \CRITICAL + * Every caller of this, must not access the item from now. + */ + return; + } + + reset_lb_updated_flag(item); + return; + } + + /*! + * \note + * Check the update_list, if you want make serialized update + */ + if (/*s_info.update_list || */pd_is_opened(item->inst->item->pkgname) == PD_IS_OPENED_BUT_NOT_MINE) { + DbgPrint("%s is busy, migrate to normal pending list\n", item->inst->id); + (void)append_pending_list(item); + return; + } + + item->monitor = ecore_timer_add(item->inst->item->timeout, update_timeout_cb, item); + if (!item->monitor) { + ErrPrint("Failed to add update monitor %s(%s):%d\n", + item->inst->item->pkgname, item->inst->id, item->inst->item->timeout); + return; + } + + ret = so_update(item->inst); + if (ret < 0) { + ecore_timer_del(item->monitor); + item->monitor = NULL; + reset_lb_updated_flag(item); + return; + } + + /*! + * \note + * Counter of the event monitor is only used for asynchronous content updating, + * So reset it to 1 from here because the async updating is started now, + * even if it is accumulated by other event function before this. + */ + item->monitor_cnt = 1; + + /*! + * \note + * While waiting the Callback function call, + * Add this for finding the crash + */ + fault_mark_call(item->inst->item->pkgname, item->inst->id, "update,crashed", NO_ALARM, DEFAULT_LIFE_TIMER); + + if (ret & NEED_TO_SCHEDULE) { + (void)append_pending_list(item); + } + + if (ret & FORCE_TO_SCHEDULE) { + DbgPrint("%s Return NEED_TO_FORCE_SCHEDULE\n", item->inst->item->pkgname); + (void)append_force_update_list(item); + } + + if (ret & OUTPUT_UPDATED) { + /*! + * \NOTE + * In this case, there is potential issue + * 1. User added update CALLBACK -> Inotify event (Only once) + * > We have to detect this case. Is it possible to be a user callback called faster than inotify event handler? + * 2. Inotify event -> User added update CALLBACK -> Inotify event + * > Okay. What we want is this. + */ + update_monitor_cnt(item); + } + + /* + * \NOTE + * This should be updated after "update_monitor_cnt" function call, + * because the update_monitor_cnt function will see the s_info.update variable, + */ + s_info.update_list = eina_list_append(s_info.update_list, item); + + return; +} + static Eina_Bool force_update_cb(void *data) { struct item *item; @@ -191,13 +408,9 @@ static Eina_Bool force_update_cb(void *data) goto cleanout; } - if (eina_list_data_find(s_info.update_list, item) || pd_is_opened(item->inst->item->pkgname) < 0) { - return ECORE_CALLBACK_RENEW; - } - s_info.force_update_list = eina_list_remove(s_info.force_update_list, item); - if (updator_cb(item) == ECORE_CALLBACK_CANCEL) { - } + + do_force_update(item); if (s_info.force_update_list) { return ECORE_CALLBACK_RENEW; @@ -246,7 +459,7 @@ static Eina_Bool pended_cmd_consumer_cb(void *data) goto cleanout; } - if (eina_list_data_find(s_info.update_list, item) || pd_is_opened(item->inst->item->pkgname) < 0) { + if (eina_list_data_find(s_info.update_list, item) || pd_is_opened(item->inst->item->pkgname) == PD_IS_OPENED_BUT_NOT_MINE) { return ECORE_CALLBACK_RENEW; } @@ -345,6 +558,25 @@ static inline void migrate_to_pd_open_pending_list(const char *pkgname) cnt++; } + /*! + * These items will be moved to the pending list after the PD is closed. + * Force list -> pd open list -> pending list. + * So there is no way to go back to the foce update list again. + * + * \warning + * the ITEM must only exists in one list, pending list or force_update_list + * It is not accepted to exists in two list at same time. + */ + EINA_LIST_FOREACH_SAFE(s_info.force_update_list, l, n, item) { + if (strcmp(pkgname, item->inst->item->pkgname)) { + continue; + } + + s_info.force_update_list = eina_list_remove(s_info.force_update_list, item); + s_info.pd_open_pending_list = eina_list_append(s_info.pd_open_pending_list, item); + cnt++; + } + if (s_info.pd_open_pending_list) { activate_pd_open_pending_consumer(); } @@ -352,6 +584,10 @@ static inline void migrate_to_pd_open_pending_list(const char *pkgname) if (!s_info.pending_list) { deactivate_pending_consumer(); } + + if (!s_info.force_update_list) { + deactivate_force_update_consumer(); + } } static inline void migrate_to_pending_list(const char *pkgname) @@ -383,7 +619,7 @@ static inline void migrate_to_pending_list(const char *pkgname) static inline int is_pended_item(struct item *item) { struct item *in_item; - if (pd_is_opened(item->inst->item->pkgname) == 1) { + if (pd_is_opened(item->inst->item->pkgname) == PD_IS_OPENED) { in_item = eina_list_data_find(s_info.pd_open_pending_list, item); } else { in_item = eina_list_data_find(s_info.pending_list, item); @@ -399,7 +635,12 @@ static int append_pending_list(struct item *item) return LB_STATUS_ERROR_BUSY; } - if (pd_is_opened(item->inst->item->pkgname) == 1) { + if (eina_list_data_find(s_info.force_update_list, item)) { + DbgPrint("Already exists in force list\n"); + return LB_STATUS_SUCCESS; + } + + if (pd_is_opened(item->inst->item->pkgname) == PD_IS_OPENED) { if (eina_list_data_find(s_info.pd_open_pending_list, item) == item) { DbgPrint("Already pended - %s\n", item->inst->item->pkgname); return LB_STATUS_ERROR_EXIST; @@ -432,7 +673,28 @@ static int append_pending_list(struct item *item) s_info.hidden_list = eina_list_append(s_info.hidden_list, item); } } - return 0; + + return LB_STATUS_SUCCESS; +} + +static inline int clear_from_pending_list(struct item *item) +{ + Eina_List *l; + struct item *tmp; + + EINA_LIST_FOREACH(s_info.pending_list, l, tmp) { + if (tmp != item) { + continue; + } + + s_info.pending_list = eina_list_remove_list(s_info.pending_list, l); + if (!s_info.pending_list) { + deactivate_pending_consumer(); + } + return LB_STATUS_SUCCESS; + } + + return LB_STATUS_ERROR_NOT_EXIST; } static int append_force_update_list(struct item *item) @@ -442,28 +704,47 @@ static int append_force_update_list(struct item *item) return LB_STATUS_ERROR_BUSY; } - if (!IS_LB_SHOWN(item)) { - if (eina_list_data_find(s_info.hidden_list, item) == item) { - DbgPrint("Already in hidden list - %s\n", item->inst->id); + /*! + * If the item is already in pending list, remove it. + */ + clear_from_pending_list(item); + + if (pd_is_opened(item->inst->item->pkgname) == PD_IS_OPENED) { + if (eina_list_data_find(s_info.pd_open_pending_list, item) == item) { + DbgPrint("Already pended - %s\n", item->inst->item->pkgname); return LB_STATUS_ERROR_EXIST; } - s_info.hidden_list = eina_list_append(s_info.hidden_list, item); + if (activate_pd_open_pending_consumer() < 0) { + ErrPrint("Failed to activate PD open pending consumer\n"); + return LB_STATUS_ERROR_FAULT; + } - DbgPrint("forced item is moved to hidden_list - %s\n", item->inst->id); - return LB_STATUS_SUCCESS; - } + s_info.pd_open_pending_list = eina_list_append(s_info.pd_open_pending_list, item); + } else { + if (eina_list_data_find(s_info.force_update_list, item)) { + DbgPrint("Already in force update list\n"); + return LB_STATUS_SUCCESS; + } - if (eina_list_data_find(s_info.force_update_list, item)) { - DbgPrint("Already in force update list\n"); - return LB_STATUS_SUCCESS; - } + if (IS_LB_SHOWN(item)) { + if (activate_force_update_consumer() < 0) { + return LB_STATUS_ERROR_FAULT; + } - if (activate_force_update_consumer() < 0) { - return LB_STATUS_ERROR_FAULT; + s_info.force_update_list = eina_list_append(s_info.force_update_list, item); + } else { + if (eina_list_data_find(s_info.hidden_list, item) == item) { + DbgPrint("Already in hidden list - %s\n", item->inst->id); + return LB_STATUS_ERROR_EXIST; + } + + s_info.hidden_list = eina_list_append(s_info.hidden_list, item); + + DbgPrint("forced item is moved to hidden_list - %s\n", item->inst->id); + } } - s_info.force_update_list = eina_list_append(s_info.force_update_list, item); return LB_STATUS_SUCCESS; } @@ -498,26 +779,6 @@ static inline void migrate_to_pending_list_from_hidden_list(struct item *item) append_pending_list(item); } -static inline int clear_from_pending_list(struct item *item) -{ - Eina_List *l; - struct item *tmp; - - EINA_LIST_FOREACH(s_info.pending_list, l, tmp) { - if (tmp != item) { - continue; - } - - s_info.pending_list = eina_list_remove_list(s_info.pending_list, l); - if (!s_info.pending_list) { - deactivate_pending_consumer(); - } - return LB_STATUS_SUCCESS; - } - - return LB_STATUS_ERROR_NOT_EXIST; -} - /*! * \brief * This function can call the update callback @@ -593,42 +854,6 @@ static void timer_freeze(struct item *item) #endif } -static inline void update_monitor_cnt(struct item *item) -{ - double now; - double interval; - - now = util_timestamp(); - interval = now - item->update_interval; - - /*! - * \note - * If the content update is processed in too short time, - * don't increase the monitor counter, instead of it - * set the heavy updating flag. - * And handling this heavy updating from the - * file update callback. - */ - if (interval >= MINIMUM_UPDATE_INTERVAL) { - if (eina_list_data_find(s_info.update_list, item)) { - /*! - * \note - * If already in updating mode, - * reset the monitor_cnt to 1, - * all updated event will be merged into A inotify event - */ - DbgPrint("While waiting updated event, content is updated [%s]\n", item->inst->id); - item->monitor_cnt = 1; - } else { - item->monitor_cnt++; - } - } else { - item->heavy_updating = 1; - } - - item->update_interval = now; -} - static inline Eina_List *find_item(struct instance *inst) { Eina_List *l; @@ -778,26 +1003,6 @@ static inline int clear_from_pd_open_pending_list(struct item *item) return LB_STATUS_ERROR_NOT_EXIST; } -static Eina_Bool update_timeout_cb(void *data) -{ - struct item *item; - - item = data; - - ErrPrint("UPDATE TIMEOUT ========> %s - %s\n", item->inst->item->pkgname, item->inst->id); - - if (!eina_list_data_find(s_info.update_list, item)) { - ErrPrint("Updating item is not matched\n"); - } - - fault_unmark_call(item->inst->item->pkgname, item->inst->id, "update,crashed", NO_ALARM); - fault_mark_call(item->inst->item->pkgname, item->inst->id, "update,timeout", NO_ALARM, DEFAULT_LIFE_TIMER); - s_info.update_list = eina_list_remove(s_info.update_list, item); - - exit(ETIME); - return ECORE_CALLBACK_CANCEL; -} - /*! * \note * This must has to return ECORE_CALLBACK_CANCEL, only if the item is deleted. @@ -848,7 +1053,7 @@ static Eina_Bool updator_cb(void *data) * \note * Check the update_list, if you want make serialized update */ - if (/*s_info.update_list || */pd_is_opened(item->inst->item->pkgname) < 0) { + if (/*s_info.update_list || */pd_is_opened(item->inst->item->pkgname) == PD_IS_OPENED_BUT_NOT_MINE) { DbgPrint("%s is busy\n", item->inst->id); (void)append_pending_list(item); return ECORE_CALLBACK_RENEW; @@ -1098,6 +1303,12 @@ HAPI int lb_open_pd(const char *pkgname, const char *id) if (!s_info.pd_list) { pending_timer_freeze(); + + /*! + * \note + * Freeze the force timer only in this case. + */ + force_timer_freeze(); } s_info.pd_list = eina_list_append(s_info.pd_list, inst); @@ -1131,6 +1342,7 @@ HAPI int lb_close_pd(const char *pkgname, const char *id) s_info.pd_list = eina_list_remove(s_info.pd_list, tmp); if (!s_info.pd_list) { pending_timer_thaw(); + force_timer_thaw(); } /*! @@ -1290,6 +1502,7 @@ HAPI int lb_destroy(const char *pkgname, const char *id) s_info.pd_list = eina_list_remove(s_info.pd_list, tmp); if (!s_info.pd_list) { pending_timer_thaw(); + force_timer_thaw(); } /*! @@ -1675,7 +1888,7 @@ HAPI int lb_system_event(const char *pkgname, const char *id, int event) return lb_sys_event(inst, item, event); } -HAPI int lb_update(const char *pkgname, const char *id) +HAPI int lb_update(const char *pkgname, const char *id, int force) { Eina_List *l; struct instance *inst; @@ -1694,11 +1907,16 @@ HAPI int lb_update(const char *pkgname, const char *id) } item = eina_list_data_get(l); - (void)append_pending_list(item); + if (force && pd_is_opened(pkgname) != PD_IS_OPENED) { + (void)append_force_update_list(item); + } else { + (void)append_pending_list(item); + } + return LB_STATUS_SUCCESS; } -HAPI int lb_update_all(const char *pkgname, const char *cluster, const char *category) +HAPI int lb_update_all(const char *pkgname, const char *cluster, const char *category, int force) { Eina_List *l; Eina_List *n; @@ -1720,10 +1938,18 @@ HAPI int lb_update_all(const char *pkgname, const char *cluster, const char *cat if (pkgname && strlen(pkgname)) { if (!strcmp(item->inst->item->pkgname, pkgname)) { - (void)append_pending_list(item); + if (force && pd_is_opened(pkgname) != PD_IS_OPENED) { + (void)append_force_update_list(item); + } else { + (void)append_pending_list(item); + } } } else { - (void)append_pending_list(item); + if (force) { + DbgPrint("Update All function doesn't support force update to all liveboxes\n"); + } else { + (void)append_pending_list(item); + } } } @@ -1778,6 +2004,10 @@ HAPI void lb_pause_all(void) s_info.paused = 1; pending_timer_freeze(); + /*! + * \note + * force timer will not be freezed + */ EINA_LIST_FOREACH(s_info.item_list, l, item) { if (item->deleteme) { @@ -1805,6 +2035,11 @@ HAPI void lb_resume_all(void) pending_timer_thaw(); + /*! + * \note + * force timer will not affected by this + */ + EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) { if (item->deleteme) { DbgPrint("Instance %s skip timer resume (deleteme)\n", item->inst->item->pkgname); -- 2.7.4