#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;
Eina_List *pd_list;
int secured;
int pending_timer_freezed;
+ int force_timer_freezed;
} s_info = {
.item_list = NULL,
.force_update_list = NULL,
.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);
}
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;
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)
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;
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;
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;
}
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();
}
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)
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);
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;
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)
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;
}
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
#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;
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.
* \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;
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);
s_info.pd_list = eina_list_remove(s_info.pd_list, tmp);
if (!s_info.pd_list) {
pending_timer_thaw();
+ force_timer_thaw();
}
/*!
s_info.pd_list = eina_list_remove(s_info.pd_list, tmp);
if (!s_info.pd_list) {
pending_timer_thaw();
+ force_timer_thaw();
}
/*!
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;
}
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;
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);
+ }
}
}
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) {
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);