Merge branch 'tizen_2.2' of ssh://review.tizendev.org:29418/apps/livebox/data-provide...
[platform/framework/web/data-provider-slave.git] / src / lb.c
index de95745..1d82a88 100644 (file)
--- a/src/lb.c
+++ b/src/lb.c
@@ -17,6 +17,7 @@
 #include <stdio.h>
 #include <stdlib.h> /* exit */
 #include <errno.h>
+#include <unistd.h> /* access */
 
 #include <Ecore.h>
 #include <Eina.h>
 #include "fault.h"
 #include "util.h"
 
+#define IS_LB_SHOWN(itm) (!(itm)->inst->item->has_livebox_script || ((itm)->inst->item->has_livebox_script && (itm)->is_lb_show))
+
 int errno;
 
+#define UPDATE_ITEM_DELETED    (-1)
+#define UPDATE_INVOKED         (-2)
+#define UPDATE_NOT_INVOKED     (0)
+
 struct item {
        Ecore_Timer *timer;
        struct instance *inst;
@@ -48,6 +55,8 @@ struct item {
        int is_paused; /* 1 is paused, 0 is resumed */
        double sleep_at;
 
+       unsigned int updated_in_pause;
+
        int is_lb_show;
        int is_pd_show;
        int is_lb_updated;
@@ -55,7 +64,7 @@ struct item {
 
 static struct info {
        Eina_List *item_list;
-       struct item *update;
+       Eina_List *update_list;
        Eina_List *pending_list;
        Ecore_Timer *pending_timer;
        Eina_List *pd_open_pending_list;
@@ -66,7 +75,7 @@ static struct info {
        int pending_timer_freezed;
 } s_info  = {
        .item_list = NULL,
-       .update = NULL,
+       .update_list = NULL,
        .pending_list = NULL,
        .pending_timer = NULL,
        .pd_open_pending_list = NULL,
@@ -93,8 +102,9 @@ static void pending_timer_freeze(void)
 static void pending_timer_thaw(void)
 {
        DbgPrint("Freezed Count: %d\n", s_info.pending_timer_freezed);
-       if (!s_info.pending_timer_freezed)
+       if (!s_info.pending_timer_freezed) {
                return;
+       }
 
        s_info.pending_timer_freezed--;
        if (s_info.pending_timer && !s_info.pending_timer_freezed) {
@@ -117,7 +127,6 @@ static inline int pd_is_opened(const char *pkgname)
        i = 0;
        EINA_LIST_FOREACH(s_info.pd_list, l, tmp) {
                if (pkgname && !strcmp(pkgname, tmp)) {
-                       DbgPrint("PD(%s) is opened\n", pkgname);
                        return 1;
                }
 
@@ -132,25 +141,29 @@ static Eina_Bool pd_open_pended_cmd_consumer_cb(void *data)
        struct item *item;
 
        item = eina_list_nth(s_info.pd_open_pending_list, 0);
-       if (!item)
+       if (!item) {
                goto cleanout;
+       }
 
-       if (s_info.update)
+       if (eina_list_data_find(s_info.update_list, item)) {
                return ECORE_CALLBACK_RENEW;
+       }
 
        s_info.pd_open_pending_list = eina_list_remove(s_info.pd_open_pending_list, item);
-       DbgPrint("Consuming pended item: %s\n", item->inst->id);
        /*!
         * \note
         * To prevent from checking the is_updated function
         */
-       (void)updator_cb(item);
-       if (s_info.pd_open_pending_list)
+       if (updator_cb(item) == ECORE_CALLBACK_CANCEL) {
+               /* Item is destroyed */
+       }
+
+       if (s_info.pd_open_pending_list) {
                return ECORE_CALLBACK_RENEW;
+       }
 
 cleanout:
        s_info.pd_open_pending_timer = NULL;
-       DbgPrint("open pd pending list exhausted\n");
        return ECORE_CALLBACK_CANCEL;
 }
 
@@ -159,33 +172,38 @@ static Eina_Bool pended_cmd_consumer_cb(void *data)
        struct item *item;
 
        item = eina_list_nth(s_info.pending_list, 0);
-       if (!item)
+       if (!item) {
                goto cleanout;
+       }
 
-       if (s_info.update || 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) < 0) {
                return ECORE_CALLBACK_RENEW;
+       }
 
        s_info.pending_list = eina_list_remove(s_info.pending_list, item);
-       DbgPrint("Consuming pended item: %s\n", item->inst->id);
        /*!
         * \note
         * To prevent from checking the is_updated function
         */
-       (void)updator_cb(item);
-       if (s_info.pending_list)
+       if (updator_cb(item) == ECORE_CALLBACK_CANCEL) {
+               /* item is destroyed */
+       }
+
+       if (s_info.pending_list) {
                return ECORE_CALLBACK_RENEW;
+       }
 
 cleanout:
        s_info.pending_timer = NULL;
        s_info.pending_timer_freezed = 0;
-       DbgPrint("pending list exhausted\n");
        return ECORE_CALLBACK_CANCEL;
 }
 
 static inline __attribute__((always_inline)) int activate_pending_consumer(void)
 {
-       if (s_info.pending_timer)
+       if (s_info.pending_timer) {
                return 0;
+       }
 
        s_info.pending_timer = ecore_timer_add(0.000001f, pended_cmd_consumer_cb, NULL);
        if (!s_info.pending_timer) {
@@ -198,7 +216,6 @@ static inline __attribute__((always_inline)) int activate_pending_consumer(void)
         * Just freeze the timer.
         */
        if (s_info.pending_timer_freezed) {
-               DbgPrint("Pending timer created and freezed\n");
                ecore_timer_freeze(s_info.pending_timer);
        }
 
@@ -207,29 +224,30 @@ static inline __attribute__((always_inline)) int activate_pending_consumer(void)
 
 static inline void deactivate_pending_consumer(void)
 {
-       if (!s_info.pending_timer)
+       if (!s_info.pending_timer) {
                return;
+       }
 
        ecore_timer_del(s_info.pending_timer);
        s_info.pending_timer = NULL;
        s_info.pending_timer_freezed = 0;
-       DbgPrint("Clear the pending timer\n");
 }
 
 static inline void deactivate_pd_open_pending_consumer(void)
 {
-       if (!s_info.pd_open_pending_timer)
+       if (!s_info.pd_open_pending_timer) {
                return;
+       }
 
        ecore_timer_del(s_info.pd_open_pending_timer);
        s_info.pd_open_pending_timer = NULL;
-       DbgPrint("Clear the open_pd_pending timer\n");
 }
 
 static inline int __attribute__((always_inline)) activate_pd_open_pending_consumer(void)
 {
-       if (s_info.pd_open_pending_timer)
+       if (s_info.pd_open_pending_timer) {
                return 0;
+       }
 
        s_info.pd_open_pending_timer = ecore_timer_add(0.000001f, pd_open_pended_cmd_consumer_cb, NULL);
        if (!s_info.pd_open_pending_timer) {
@@ -248,8 +266,9 @@ static inline void migrate_to_pd_open_pending_list(const char *pkgname)
        int cnt = 0;
 
        EINA_LIST_FOREACH_SAFE(s_info.pending_list, l, n, item) {
-               if (strcmp(pkgname, item->inst->item->pkgname))
+               if (strcmp(pkgname, item->inst->item->pkgname)) {
                        continue;
+               }
 
                s_info.pending_list = eina_list_remove(s_info.pending_list, item);
                s_info.pd_open_pending_list = eina_list_append(s_info.pd_open_pending_list, item);
@@ -257,14 +276,12 @@ static inline void migrate_to_pd_open_pending_list(const char *pkgname)
        }
 
        if (s_info.pd_open_pending_list) {
-               DbgPrint("Activate PD open pending consumer (%s)\n", pkgname);
                activate_pd_open_pending_consumer();
        }
 
-       if (!s_info.pending_list)
+       if (!s_info.pending_list) {
                deactivate_pending_consumer();
-
-       DbgPrint("%d items are migrated\n", cnt);
+       }
 }
 
 static inline void migrate_to_pending_list(const char *pkgname)
@@ -275,24 +292,37 @@ static inline void migrate_to_pending_list(const char *pkgname)
        int cnt = 0;
 
        EINA_LIST_FOREACH_SAFE(s_info.pd_open_pending_list, l, n, item) {
-               if (strcmp(pkgname, item->inst->item->pkgname))
+               if (strcmp(pkgname, item->inst->item->pkgname)) {
                        continue;
+               }
 
                s_info.pd_open_pending_list = eina_list_remove(s_info.pd_open_pending_list, item);
                s_info.pending_list = eina_list_append(s_info.pending_list, item);
                cnt++;
        }
 
-       if (s_info.pending_list)
+       if (s_info.pending_list) {
                activate_pending_consumer();
+       }
 
-       if (!s_info.pd_open_pending_list)
+       if (!s_info.pd_open_pending_list) {
                deactivate_pd_open_pending_consumer();
+       }
+}
+
+static inline int is_pended_item(struct item *item)
+{
+       struct item *in_item;
+       if (pd_is_opened(item->inst->item->pkgname) == 1) {
+               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);
+       }
 
-       DbgPrint("%d items are migrated\n", cnt);
+       return (in_item == item);
 }
 
-static inline int append_pending_list(struct item *item)
+static int append_pending_list(struct item *item)
 {
        if (pd_is_opened(item->inst->item->pkgname) == 1) {
                if (eina_list_data_find(s_info.pd_open_pending_list, item) == item) {
@@ -300,7 +330,6 @@ static inline int append_pending_list(struct item *item)
                        return LB_STATUS_ERROR_EXIST;
                }
 
-               DbgPrint("Activate PD open pending consumer (%s)\n", item->inst->item->pkgname);
                if (activate_pd_open_pending_consumer() < 0) {
                        ErrPrint("Failed to activate PD open pending consumer\n");
                        return LB_STATUS_ERROR_FAULT;
@@ -313,55 +342,73 @@ static inline int append_pending_list(struct item *item)
                        return LB_STATUS_ERROR_EXIST;
                }
 
-               if (activate_pending_consumer() < 0)
+               if (activate_pending_consumer() < 0) {
                        return LB_STATUS_ERROR_FAULT;
+               }
 
                s_info.pending_list = eina_list_append(s_info.pending_list, item);
        }
        return 0;
 }
 
-static inline void timer_thaw(struct item *item)
+/*!
+ * \brief
+ *   This function can call the update callback
+ * return 0 if there is no changes
+ * return -1 the item is deleted
+ */
+static inline int timer_thaw(struct item *item)
 {
        double pending;
        double period;
        double delay;
        double sleep_time;
 
-       if (!item->timer)
-               return;
+       if (!item->timer) {
+               return 0;
+       }
 
        ecore_timer_thaw(item->timer);
        period = ecore_timer_interval_get(item->timer);
        pending = ecore_timer_pending_get(item->timer);
        delay = util_time_delay_for_compensation(period) - pending;
        ecore_timer_delay(item->timer, delay);
-       DbgPrint("Compensated: %lf, Instance %s resume timer\n", delay, item->inst->item->pkgname);
 
-       if (item->sleep_at == 0.0f)
-               return;
+       if (item->sleep_at == 0.0f) {
+               return 0;
+       }
 
        sleep_time = util_timestamp() - item->sleep_at;
+       item->sleep_at = 0.0f;
+
        if (sleep_time > pending) {
-               DbgPrint("Update time elapsed\n");
-               (void)updator_cb(item);
+               if (updator_cb(item) == ECORE_CALLBACK_CANCEL) {
+                       /* item is destroyed */
+                       return UPDATE_ITEM_DELETED;
+               } else {
+                       return UPDATE_INVOKED;
+               }
        }
 
-       item->sleep_at = 0.0f;
+       return UPDATE_NOT_INVOKED;
 }
 
-static inline void timer_freeze(struct item *item)
+static void timer_freeze(struct item *item)
 {
-       struct timeval tv;
-
-       if (!item->timer)
+       if (!item->timer) {
                return;
+       }
 
        ecore_timer_freeze(item->timer);
 
-       if (ecore_timer_interval_get(item->timer) <= 1.0f)
+       if (ecore_timer_interval_get(item->timer) <= 1.0f) {
                return;
+       }
 
+#if defined(_USE_ECORE_TIME_GET)
+       item->sleep_at = ecore_time_get();
+#else
+       struct timeval tv;
        if (gettimeofday(&tv, NULL) < 0) {
                ErrPrint("gettimeofday: %s\n", strerror(errno));
                tv.tv_sec = 0;
@@ -369,7 +416,7 @@ static inline void timer_freeze(struct item *item)
        }
 
        item->sleep_at = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f;
-       DbgPrint("Instance %s freeze timer\n", item->inst->item->pkgname);
+#endif
 }
 
 static inline void update_monitor_cnt(struct item *item)
@@ -388,10 +435,22 @@ static inline void update_monitor_cnt(struct item *item)
         * And handling this heavy updating from the
         * file update callback.
         */
-       if (interval >= MINIMUM_UPDATE_INTERVAL)
-               item->monitor_cnt++;
-       else
+       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;
 }
@@ -402,8 +461,9 @@ static inline Eina_List *find_item(struct instance *inst)
        struct item *item;
        
        EINA_LIST_FOREACH(s_info.item_list, l, item) {
-               if (item->inst == inst)
+               if (item->inst == inst) {
                        return l;
+               }
        }
 
        return NULL;
@@ -426,16 +486,16 @@ static inline int output_handler(struct item *item)
        }
 
        if (item->monitor_cnt == 0) {
-               if (!invalid)
+               if (!invalid) {
                        fault_unmark_call(item->inst->item->pkgname, item->inst->id, "update,crashed", NO_ALARM);
+               }
 
                if (item->monitor) {
                        ecore_timer_del(item->monitor);
                        item->monitor = NULL;
                }
 
-               if (s_info.update == item)
-                       s_info.update = NULL;
+               s_info.update_list = eina_list_remove(s_info.update_list, item);
 
                if (item->deleteme) {
                        provider_send_deleted(item->inst->item->pkgname, item->inst->id);
@@ -452,8 +512,9 @@ static int desc_updated_cb(const char *filename, void *data, int over)
 {
        struct item *item;
 
-       if (over)
+       if (over) {
                WarnPrint("Event Q overflow\n");
+       }
 
        item = data;
 
@@ -476,8 +537,9 @@ static int file_updated_cb(const char *filename, void *data, int over)
        char *title = NULL;
        int ret;
 
-       if (over)
+       if (over) {
                WarnPrint("Event Q overflow\n");
+       }
 
        item = data;
 
@@ -493,29 +555,48 @@ static int file_updated_cb(const char *filename, void *data, int over)
                return EXIT_SUCCESS; /*!< To keep the callback */
        }
 
-       if (!item->inst->item->has_livebox_script || (item->inst->item->has_livebox_script && item->is_lb_show)) {
+       if (IS_LB_SHOWN(item)) {
                provider_send_updated(item->inst->item->pkgname, item->inst->id,
-                                       item->inst->w, item->inst->h, item->inst->priority, content, title);
+                                       item->inst->w, item->inst->h, item->inst->priority,
+                                       content, title);
        } else {
-               DbgPrint("Livebox script is not ready yet\n");
                item->is_lb_updated++;
        }
 
        return output_handler(item);
 }
 
+static void reset_lb_updated_flag(struct item *item)
+{
+       if (!item->is_lb_updated) {
+               return;
+       }
+
+       DbgPrint("[%s] Updated %d times, (content: %s), (title: %s)\n",
+                       item->inst->id, item->is_lb_updated,
+                       item->inst->content, item->inst->title);
+
+       provider_send_updated(item->inst->item->pkgname, item->inst->id,
+                       item->inst->w, item->inst->h, item->inst->priority,
+                       item->inst->content, item->inst->title);
+
+       item->is_lb_updated = 0;
+}
+
 static inline int clear_from_pd_open_pending_list(struct item *item)
 {
        Eina_List *l;
        struct item *tmp;
 
        EINA_LIST_FOREACH(s_info.pd_open_pending_list, l, tmp) {
-               if (tmp != item)
+               if (tmp != item) {
                        continue;
+               }
 
                s_info.pd_open_pending_list = eina_list_remove_list(s_info.pd_open_pending_list, l);
-               if (!s_info.pd_open_pending_list)
+               if (!s_info.pd_open_pending_list) {
                        deactivate_pd_open_pending_consumer();
+               }
                return LB_STATUS_SUCCESS;
        }
 
@@ -528,12 +609,14 @@ static inline int clear_from_pending_list(struct item *item)
        struct item *tmp;
 
        EINA_LIST_FOREACH(s_info.pending_list, l, tmp) {
-               if (tmp != item)
+               if (tmp != item) {
                        continue;
+               }
 
                s_info.pending_list = eina_list_remove_list(s_info.pending_list, l);
-               if (!s_info.pending_list)
+               if (!s_info.pending_list) {
                        deactivate_pending_consumer();
+               }
                return LB_STATUS_SUCCESS;
        }
 
@@ -546,19 +629,25 @@ static Eina_Bool update_timeout_cb(void *data)
 
        item = data;
 
-       DbgPrint("UPDATE TIMEOUT ========> %s - %s\n", item->inst->item->pkgname, item->inst->id);
+       ErrPrint("UPDATE TIMEOUT ========> %s - %s\n", item->inst->item->pkgname, item->inst->id);
 
-       if (s_info.update != item)
+       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 = NULL;
+       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.
+ * So every caller, should manage the deleted item correctly.
+ */
 static Eina_Bool updator_cb(void *data)
 {
        struct item *item;
@@ -566,26 +655,46 @@ static Eina_Bool updator_cb(void *data)
 
        item = data;
 
-       if (item->monitor) {/*!< If this item is already in update process */
+       if (item->monitor) { /*!< If this item is already in update process */
                return ECORE_CALLBACK_RENEW;
        }
 
+       if (!IS_LB_SHOWN(item)) {
+               DbgPrint("%s is not shown yet. make delay for updates\n", item->inst->item->pkgname);
+               (void)append_pending_list(item);
+               return ECORE_CALLBACK_RENEW;
+       }
+
+       if (item->is_paused) {
+               item->updated_in_pause++;
+               DbgPrint("%s is paused[%d]. make delay for updating\n", item->inst->item->pkgname, item->updated_in_pause);
+               return ECORE_CALLBACK_RENEW;
+       }
+
+       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);
-
-                       ecore_timer_del(item->timer);
-                       item->timer = NULL;
+                       /*!
+                        * \CRITICAL
+                        * Every caller of this, must not access the item from now.
+                        */
                        return ECORE_CALLBACK_CANCEL;
                }
 
+               reset_lb_updated_flag(item);
                return ECORE_CALLBACK_RENEW;
        }
 
-       if (s_info.update || pd_is_opened(item->inst->item->pkgname) < 0) {
-               DbgPrint("%s is busy\n", s_info.update ? s_info.update->inst->id : item->inst->id);
+       /*!
+        * \note
+        * Check the update_list, if you want make serialized update
+        */
+       if (/*s_info.update_list || */pd_is_opened(item->inst->item->pkgname) < 0) {
+               DbgPrint("%s is busy\n", item->inst->id);
                (void)append_pending_list(item);
                return ECORE_CALLBACK_RENEW;
        }
@@ -597,6 +706,14 @@ static Eina_Bool updator_cb(void *data)
                return ECORE_CALLBACK_RENEW;
        }
 
+       ret = so_update(item->inst);
+       if (ret < 0) {
+               ecore_timer_del(item->monitor);
+               item->monitor = NULL;
+               reset_lb_updated_flag(item);
+               return ECORE_CALLBACK_RENEW;
+       }
+
        /*!
         * \note
         * Counter of the event monitor is only used for asynchronous content updating,
@@ -605,18 +722,6 @@ static Eina_Bool updator_cb(void *data)
         */
        item->monitor_cnt = 1;
 
-       s_info.update = item;
-
-       ret = so_update(item->inst);
-       if (ret < 0) {
-               item->monitor_cnt--;
-
-               ecore_timer_del(item->monitor);
-               item->monitor = NULL;
-               s_info.update = NULL;
-               return ECORE_CALLBACK_RENEW;
-       }
-
        /*!
         * \note
         * While waiting the Callback function call,
@@ -628,8 +733,24 @@ static Eina_Bool updator_cb(void *data)
                (void)append_pending_list(item);
        }
 
-       if (ret & OUTPUT_UPDATED)
+       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 ECORE_CALLBACK_RENEW;
 }
@@ -657,6 +778,7 @@ static inline int add_desc_update_monitor(const char *id, struct item *item)
 {
        char *filename;
        int len;
+       int ret;
 
        len = strlen(util_uri_to_path(id)) + strlen(".desc") + 1;
        filename = malloc(len);
@@ -666,21 +788,14 @@ static inline int add_desc_update_monitor(const char *id, struct item *item)
        }
 
        snprintf(filename, len, "%s.desc", util_uri_to_path(id));
-       DbgPrint("Add DESC monitor: %s\n", filename);
-       return update_monitor_add_update_cb(filename, desc_updated_cb, item);
+       ret = update_monitor_add_update_cb(filename, desc_updated_cb, item);
+       free(filename);
+       return ret;
 }
 
 static inline int add_file_update_monitor(const char *id, struct item *item)
 {
-       char *filename;
-
-       filename = strdup(util_uri_to_path(id));
-       if (!filename) {
-               ErrPrint("Heap: %s (%s)\n", strerror(errno), id);
-               return LB_STATUS_ERROR_MEMORY;
-       }
-
-       return update_monitor_add_update_cb(filename, file_updated_cb, item);
+       return update_monitor_add_update_cb(util_uri_to_path(id), file_updated_cb, item);
 }
 
 static inline int update_monitor_add(const char *id, struct item *item)
@@ -729,8 +844,9 @@ const char *livebox_find_pkgname(const char *filename)
        struct item *item;
 
        EINA_LIST_FOREACH(s_info.item_list, l, item) {
-               if (!strcmp(item->inst->id, filename))
+               if (!strcmp(item->inst->id, filename)) {
                        return item->inst->item->pkgname;
+               }
        }
 
        return NULL;
@@ -741,6 +857,18 @@ int livebox_request_update_by_id(const char *filename)
        Eina_List *l;
        struct item *item;
 
+       if (so_current_op() != LIVEBOX_OP_UNKNOWN) {
+               ErrPrint("Current operation: %d\n", so_current_op());
+               /*!
+                * \note
+                * Some case requires to update the content of other box from livebox_XXX ABI.
+                * In that case this function can be used so we have not to filter it from here.
+                * ex) Setting accessibility.
+                * Press the assistive light, turned on, need to update other instances too.
+                * Then the box will use this function from livebox_clicked function.
+                */
+       }
+
        EINA_LIST_FOREACH(s_info.item_list, l, item) {
                if (!strcmp(item->inst->id, filename)) {
                        return append_pending_list(item);
@@ -750,14 +878,55 @@ int livebox_request_update_by_id(const char *filename)
        return LB_STATUS_ERROR_NOT_EXIST;
 }
 
+int livebox_trigger_update_monitor(const char *filename, int is_pd)
+{
+       char *fname;
+       int ret;
+
+       if (so_current_op() != LIVEBOX_OP_UNKNOWN) {
+               ErrPrint("Current operation: %d\n", so_current_op());
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       if (is_pd) {
+               int len;
+               len = strlen(filename) + strlen(".desc");
+
+               fname = malloc(len + 1);
+               if (!fname) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+                       return LB_STATUS_ERROR_MEMORY;
+               }
+
+               snprintf(fname, len, "%s.desc", filename);
+       } else {
+               fname = strdup(filename);
+               if (!fname) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+                       return LB_STATUS_ERROR_MEMORY;
+               }
+       }
+
+       if (access(fname, R_OK | W_OK) != 0) {
+               ErrPrint("access: %s (%s)\n", fname, strerror(errno));
+               ret = LB_STATUS_ERROR_IO;
+       } else {
+               ret = update_monitor_trigger_update_cb(fname, 0);
+       }
+
+       free(fname);
+       return ret;
+}
+
 HAPI int lb_open_pd(const char *pkgname)
 {
        Eina_List *l;
        char *tmp;
 
        EINA_LIST_FOREACH(s_info.pd_list, l, tmp) {
-               if (!strcmp(pkgname, tmp))
+               if (!strcmp(pkgname, tmp)) {
                        return 0;
+               }
        }
 
        tmp = strdup(pkgname);
@@ -766,8 +935,9 @@ HAPI int lb_open_pd(const char *pkgname)
                return LB_STATUS_ERROR_MEMORY;
        }
 
-       if (!s_info.pd_list)
+       if (!s_info.pd_list) {
                pending_timer_freeze();
+       }
 
        s_info.pd_list = eina_list_append(s_info.pd_list, tmp);
 
@@ -786,14 +956,16 @@ HAPI int lb_close_pd(const char *pkgname)
        char *tmp;
 
        EINA_LIST_FOREACH_SAFE(s_info.pd_list, l, n, tmp) {
-               if (strcmp(tmp, pkgname))
+               if (strcmp(tmp, pkgname)) {
                        continue;
+               }
 
                s_info.pd_list = eina_list_remove(s_info.pd_list, tmp);
                free(tmp);
 
-               if (!s_info.pd_list)
+               if (!s_info.pd_list) {
                        pending_timer_thaw();
+               }
 
                /*!
                 * Move all items in pd_open_pending_list
@@ -826,8 +998,9 @@ HAPI int lb_create(const char *pkgname, const char *id, const char *content_info
 
        if (!skip_need_to_create) {
                ret = so_create_needed(pkgname, cluster, category, abi);
-               if (ret != NEED_TO_CREATE)
+               if (ret != NEED_TO_CREATE) {
                        return LB_STATUS_ERROR_PERMISSION;
+               }
 
                need_to_create = 1;
        }
@@ -844,7 +1017,6 @@ HAPI int lb_create(const char *pkgname, const char *id, const char *content_info
                return ret;
        }
 
-       DbgPrint("Content: [%s]\n", content_info);
        create_ret = so_create(pkgname, id, content_info, timeout, has_livebox_script, cluster, category, abi, &inst);
        if (create_ret < 0) {
                update_monitor_del(id,  item);
@@ -868,8 +1040,9 @@ HAPI int lb_create(const char *pkgname, const char *id, const char *content_info
                        return LB_STATUS_ERROR_FAULT;
                }
 
-               if (s_info.paused)
+               if (s_info.paused) {
                        timer_freeze(item);
+               }
        } else {
                DbgPrint("Local update timer is disabled: %lf (%d)\n", period, s_info.secured);
                item->timer = NULL;
@@ -898,8 +1071,9 @@ HAPI int lb_create(const char *pkgname, const char *id, const char *content_info
                                char *tmp;
 
                                tmp = strdup(*out_content);
-                               if (!tmp)
+                               if (!tmp) {
                                        ErrPrint("Memory: %s\n", strerror(errno));
+                               }
 
                                *out_content = tmp;
                        }
@@ -908,8 +1082,9 @@ HAPI int lb_create(const char *pkgname, const char *id, const char *content_info
                                char *tmp;
 
                                tmp = strdup(*out_title);
-                               if (!tmp)
+                               if (!tmp) {
                                        ErrPrint("Memory: %s\n", strerror(errno));
+                               }
 
                                *out_title = tmp;
                        }
@@ -943,8 +1118,7 @@ HAPI int lb_destroy(const char *pkgname, const char *id)
        item = eina_list_data_get(l);
        s_info.item_list = eina_list_remove_list(s_info.item_list, l);
 
-       if (s_info.update == item)
-               s_info.update = NULL;
+       s_info.update_list = eina_list_remove(s_info.update_list, item);
 
        if (item->timer) {
                clear_from_pd_open_pending_list(item);
@@ -952,10 +1126,11 @@ HAPI int lb_destroy(const char *pkgname, const char *id)
                ecore_timer_del(item->timer);
                item->timer = NULL;
 
-               if (item->monitor)
+               if (item->monitor) {
                        item->deleteme = 1;
-               else
+               } else {
                        update_monitor_del(id, item);
+               }
        }
 
        if (!item->monitor) {
@@ -988,16 +1163,18 @@ HAPI int lb_resize(const char *pkgname, const char *id, int w, int h)
        item = eina_list_data_get(l);
 
        ret = so_resize(inst, w, h);
-       if (ret < 0)
+       if (ret < 0) {
                return ret;
+       }
 
        if (ret & NEED_TO_SCHEDULE) {
                DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
                (void)append_pending_list(item);
        }
 
-       if (ret & OUTPUT_UPDATED)
+       if (ret & OUTPUT_UPDATED) {
                update_monitor_cnt(item);
+       }
 
        return LB_STATUS_SUCCESS;
 }
@@ -1052,8 +1229,9 @@ HAPI int lb_set_period(const char *pkgname, const char *id, double period)
                                return LB_STATUS_ERROR_FAULT;
                        }
 
-                       if (s_info.paused)
+                       if (s_info.paused) {
                                timer_freeze(item);
+                       }
                }
        }
 
@@ -1082,16 +1260,18 @@ HAPI int lb_clicked(const char *pkgname, const char *id, const char *event, doub
        item = eina_list_data_get(l);
 
        ret = so_clicked(inst, event, timestamp, x, y);
-       if (ret < 0)
+       if (ret < 0) {
                return ret;
+       }
 
        if (ret & NEED_TO_SCHEDULE) {
                DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
                (void)append_pending_list(item);
        }
 
-       if (ret & OUTPUT_UPDATED)
+       if (ret & OUTPUT_UPDATED) {
                update_monitor_cnt(item);
+       }
 
        return LB_STATUS_SUCCESS;
 }
@@ -1117,43 +1297,46 @@ HAPI int lb_script_event(const char *pkgname, const char *id, const char *emissi
 
        item = eina_list_data_get(l);
 
-       DbgPrint("source(%s) emission(%s) %d\n", source, emission, item->inst->item->has_livebox_script);
-       if (emission && source && !strcmp(source, util_uri_to_path(id))) {
+       if (emission && source && !strcmp(source, id)) {
                if (item->inst->item->has_livebox_script) {
                        if (!strcmp(emission, "lb,show")) {
-                               DbgPrint("Livebox(%s) script is ready now\n", id);
                                item->is_lb_show = 1;
 
-                               DbgPrint("Updated %d times, (content: %s), (title: %s)\n", item->is_lb_updated, item->inst->content, item->inst->title);
-                               if (item->is_lb_updated) {
-                                       provider_send_updated(item->inst->item->pkgname, item->inst->id,
-                                                               item->inst->w, item->inst->h, item->inst->priority, item->inst->content, item->inst->title);
-                                       item->is_lb_updated = 0;
+                               if (item->is_lb_updated && !is_pended_item(item)) {
+                                       reset_lb_updated_flag(item);
                                }
+
+                               source = util_uri_to_path(source);
                        } else if (!strcmp(emission, "lb,hide")) {
                                DbgPrint("Livebox(%s) script is hide now\n", id);
                                item->is_lb_show = 0;
+
+                               source = util_uri_to_path(source);
                        }
                }
 
                if (!strcmp(emission, "pd,show")) {
                        item->is_pd_show = 1;
+                       source = util_uri_to_path(source);
                } else if (!strcmp(emission, "pd,hide")) {
                        item->is_pd_show = 0;
+                       source = util_uri_to_path(source);
                }
        }
 
        ret = so_script_event(inst, emission, source, event_info);
-       if (ret < 0)
+       if (ret < 0) {
                return ret;
+       }
 
        if (ret & NEED_TO_SCHEDULE) {
                DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
                (void)append_pending_list(item);
        }
 
-       if (ret & OUTPUT_UPDATED)
+       if (ret & OUTPUT_UPDATED) {
                update_monitor_cnt(item);
+       }
 
        return LB_STATUS_SUCCESS;
 }
@@ -1211,33 +1394,38 @@ HAPI int lb_change_group(const char *pkgname, const char *id, const char *cluste
        item = eina_list_data_get(l);
 
        ret = so_change_group(inst, cluster, category);
-       if (ret < 0)
+       if (ret < 0) {
                return ret;
+       }
 
        if (ret & NEED_TO_SCHEDULE) {
                DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
                (void)append_pending_list(item);
        }
 
-       if (ret & OUTPUT_UPDATED)
+       if (ret & OUTPUT_UPDATED) {
                update_monitor_cnt(item);
+       }
 
        return LB_STATUS_SUCCESS;
 }
 
-static inline int lb_sys_event(struct instance *inst, struct item *item, int event)
+static int lb_sys_event(struct instance *inst, struct item *item, int event)
 {
        int ret;
 
        ret = so_sys_event(inst, event);
-       if (ret < 0)
+       if (ret < 0) {
                return ret;
+       }
 
-       if (ret & NEED_TO_SCHEDULE)
+       if (ret & NEED_TO_SCHEDULE) {
                (void)append_pending_list(item);
+       }
 
-       if (ret & OUTPUT_UPDATED)
+       if (ret & OUTPUT_UPDATED) {
                update_monitor_cnt(item);
+       }
 
        return LB_STATUS_SUCCESS;
 }
@@ -1295,14 +1483,17 @@ HAPI int lb_update_all(const char *pkgname, const char *cluster, const char *cat
 
        DbgPrint("Update content for %s\n", pkgname ? pkgname : "(all)");
        EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) {
-               if (item->deleteme)
+               if (item->deleteme) {
                        continue;
+               }
 
-               if (cluster && strcasecmp(item->inst->cluster, cluster))
+               if (cluster && strcasecmp(item->inst->cluster, cluster)) {
                        continue;
+               }
 
-               if (category && strcasecmp(item->inst->category, category))
+               if (category && strcasecmp(item->inst->category, category)) {
                        continue;
+               }
 
                if (pkgname && strlen(pkgname)) {
                        if (!strcmp(item->inst->item->pkgname, pkgname)) {
@@ -1323,12 +1514,10 @@ HAPI int lb_delete_all_deleteme(void)
        struct item *item;
        int cnt = 0;
 
-       DbgPrint("Delete all deleteme\n");
        EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) {
-               if (!item->deleteme)
+               if (!item->deleteme) {
                        continue;
-
-               s_info.item_list = eina_list_remove(s_info.item_list, item);
+               }
 
                update_monitor_del(item->inst->id, item);
                (void)so_destroy(item->inst);
@@ -1336,7 +1525,7 @@ HAPI int lb_delete_all_deleteme(void)
                cnt++;
        }
 
-       DbgPrint("Deleteme: %d\n", cnt);
+       DbgPrint("Delete all deleteme: %d\n", cnt);
        return LB_STATUS_SUCCESS;
 }
 
@@ -1347,8 +1536,9 @@ HAPI int lb_system_event_all(int event)
        struct item *item;
 
        EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) {
-               if (item->deleteme)
+               if (item->deleteme) {
                        continue;
+               }
 
                DbgPrint("System event for %s (%d)\n", item->inst->id, event);
                lb_sys_event(item->inst, item, event);
@@ -1373,7 +1563,6 @@ HAPI void lb_pause_all(void)
                }
 
                if (item->is_paused) {
-                       DbgPrint("Instance %s is already paused\n", item->inst->id);
                        continue;
                }
 
@@ -1386,26 +1575,40 @@ HAPI void lb_pause_all(void)
 HAPI void lb_resume_all(void)
 {
        Eina_List *l;
+       Eina_List *n;
        struct item *item;
 
        s_info.paused = 0;
 
        pending_timer_thaw();
 
-       EINA_LIST_FOREACH(s_info.item_list, l, item) {
+       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);
                        continue;
                }
 
                if (item->is_paused) {
-                       DbgPrint("Instance %s is still paused\n", item->inst->id);
                        continue;
                }
 
-               timer_thaw(item);
-
                lb_sys_event(item->inst, item, LB_SYS_EVENT_RESUMED);
+
+               if (item->updated_in_pause) {
+                       (void)append_pending_list(item);
+                       item->updated_in_pause = 0;
+               }
+
+               /*!
+                * \note
+                * After send the resume callback, call this function.
+                * Because the timer_thaw can call the update function.
+                * Before resumed event is notified to the livebox,
+                * Do not call update function
+                */
+               if (timer_thaw(item) == UPDATE_ITEM_DELETED) {
+                       /* item is deleted */
+               }
        }
 }
 
@@ -1416,8 +1619,9 @@ HAPI int lb_pause(const char *pkgname, const char *id)
        struct item *item;
 
        inst = so_find_instance(pkgname, id);
-       if (!inst)
+       if (!inst) {
                return LB_STATUS_ERROR_INVALID;
+       }
 
        l = find_item(inst);
        if (!l) {
@@ -1426,8 +1630,9 @@ HAPI int lb_pause(const char *pkgname, const char *id)
        }
 
        item = eina_list_data_get(l);
-       if (!item)
+       if (!item) {
                return LB_STATUS_ERROR_FAULT;
+       }
 
        if (item->deleteme) {
                DbgPrint("Instance %s will be deleted (%s)\n", item->inst->item->pkgname, item->inst->id);
@@ -1437,7 +1642,6 @@ HAPI int lb_pause(const char *pkgname, const char *id)
        item->is_paused = 1;
 
        if (s_info.paused) {
-               DbgPrint("Already paused: %s\n", item->inst->id);
                return LB_STATUS_SUCCESS;
        }
 
@@ -1453,10 +1657,12 @@ HAPI int lb_resume(const char *pkgname, const char *id)
        struct instance *inst;
        Eina_List *l;
        struct item *item;
+       int ret;
 
        inst = so_find_instance(pkgname, id);
-       if (!inst)
+       if (!inst) {
                return LB_STATUS_ERROR_INVALID;
+       }
 
        l = find_item(inst);
        if (!l) {
@@ -1465,8 +1671,9 @@ HAPI int lb_resume(const char *pkgname, const char *id)
        }
 
        item = eina_list_data_get(l);
-       if (!item)
+       if (!item) {
                return LB_STATUS_ERROR_FAULT;
+       }
 
        if (item->deleteme) {
                DbgPrint("Instance %s will be deleted (%s)\n", item->inst->item->pkgname, item->inst->id);
@@ -1476,13 +1683,31 @@ HAPI int lb_resume(const char *pkgname, const char *id)
        item->is_paused = 0;
 
        if (s_info.paused) {
-               DbgPrint("Instance %s is still paused\n", item->inst->id);
                return LB_STATUS_SUCCESS;
        }
 
-       timer_thaw(item);
-
        lb_sys_event(inst, item, LB_SYS_EVENT_RESUMED);
+
+       ret = timer_thaw(item);
+       if (ret == UPDATE_ITEM_DELETED) {
+               /*!
+                * \note
+                * ITEM is deleted
+                */
+               return LB_STATUS_SUCCESS;
+       } else if (ret == UPDATE_INVOKED) {
+               /*!
+                * \note
+                * if the update is successfully done, the updated_in_pause will be reset'd.
+                * or append it to the pending list
+                */
+       }
+
+       if (item->updated_in_pause) {
+               (void)append_pending_list(item);
+               item->updated_in_pause = 0;
+       }
+
        return LB_STATUS_SUCCESS;
 }