library : remove idler function which frees noti callback 64/72564/5
authorJiwoong Im <jiwoong.im@samsung.com>
Wed, 1 Jun 2016 12:34:02 +0000 (21:34 +0900)
committerJiwoong Im <jiwoong.im@samsung.com>
Thu, 2 Jun 2016 08:57:56 +0000 (17:57 +0900)
- change deleted flag to refcnt in noti_cb structure to manage callback

Change-Id: Ib95d2e8f21522268751d9788061e95859af5b705
Signed-off-by: Jiwoong Im <jiwoong.im@samsung.com>
lib/buxton2.c
vconf-compat/vconf.c

index 7c35757..bc19df5 100644 (file)
@@ -56,7 +56,7 @@ struct bxt_req {
 };
 
 struct bxt_noti_cb {
-       gboolean deleted;
+       int ref_cnt;
        buxton_notify_callback callback;
        void *data;
 };
@@ -416,12 +416,52 @@ static int find_noti(struct buxton_client *client,
        return 0;
 }
 
+static GList *copy_noti_callbacks(GList *callbacks)
+{
+       GList *l;
+       GList *copy;
+
+       if (!callbacks)
+               return NULL;
+
+       for (l = callbacks; l; l = g_list_next(l)) {
+               struct bxt_noti_cb *noticb;
+               noticb = callbacks->data;
+               noticb->ref_cnt++;
+       }
+       copy = g_list_copy(callbacks);
+
+       return copy;
+}
+
+static GList *free_copy_callbacks(GList *callbacks, GList *copy_callbacks)
+{
+       GList *l;
+       GList *ll;
+
+       g_list_free(copy_callbacks);
+
+       for (l = callbacks, ll = g_list_next(l); l;
+                       l = ll, ll = g_list_next(ll)) {
+               struct bxt_noti_cb *noticb = l->data;
+
+               noticb->ref_cnt--;
+               if (noticb->ref_cnt == 0) {
+                       callbacks = g_list_delete_link(callbacks, l);
+                       free(noticb);
+               }
+       }
+
+       return callbacks;
+}
+
 static int proc_msg_noti(struct buxton_client *client, uint8_t *data, int len)
 {
        int r;
        struct request rqst;
        struct bxt_noti *noti;
        GList *l;
+       GList *copy_callbacks;
 
        assert(client);
        assert(data);
@@ -450,18 +490,17 @@ static int proc_msg_noti(struct buxton_client *client, uint8_t *data, int len)
        }
 
        pthread_mutex_lock(&noti->cbs_lock);
-       for (l = noti->callbacks; l; l = g_list_next(l)) {
-               struct bxt_noti_cb *noticb = l->data;
-
-               if (noticb->deleted)
-                       continue;
+       copy_callbacks = copy_noti_callbacks(noti->callbacks);
+       pthread_mutex_unlock(&noti->cbs_lock);
 
+       for (l = copy_callbacks; l; l = g_list_next(l)) {
+               struct bxt_noti_cb *noticb = l->data;
                assert(noticb->callback);
-               pthread_mutex_unlock(&noti->cbs_lock);
                noticb->callback(rqst.layer, rqst.key, rqst.val, noticb->data);
-               pthread_mutex_lock(&noti->cbs_lock);
        }
 
+       pthread_mutex_lock(&noti->cbs_lock);
+       noti->callbacks = free_copy_callbacks(noti->callbacks, copy_callbacks);
        pthread_mutex_unlock(&noti->cbs_lock);
        free_request(&rqst);
 
@@ -523,18 +562,9 @@ static int add_noticb(struct bxt_noti *noti, buxton_notify_callback notify,
                noticb = l->data;
 
                if (noticb->callback == notify) {
-                       if (noticb->deleted == FALSE) {
-                               errno = EEXIST;
-                               pthread_mutex_unlock(&noti->cbs_lock);
-                               return -1;
-                       }
-
-                       noticb->deleted = FALSE;
-                       noticb->callback = notify;
-                       noticb->data = notify_data;
-
+                       errno = EEXIST;
                        pthread_mutex_unlock(&noti->cbs_lock);
-                       return 0;
+                       return -1;
                }
        }
 
@@ -544,7 +574,7 @@ static int add_noticb(struct bxt_noti *noti, buxton_notify_callback notify,
                return -1;
        }
 
-       noticb->deleted = FALSE;
+       noticb->ref_cnt = 1;
        noticb->callback = notify;
        noticb->data = notify_data;
 
@@ -1315,37 +1345,11 @@ EXPORT int buxton_register_notification_sync(struct buxton_client *client,
        return 0;
 }
 
-static gboolean del_noticb_cb(gpointer data)
-{
-       struct bxt_noti *noti = data;
-       struct bxt_noti_cb *noticb;
-       GList *l;
-       GList *ll;
-
-       assert(noti);
-
-       pthread_mutex_lock(&noti->cbs_lock);
-       for (l = noti->callbacks, ll = g_list_next(l); l;
-                       l = ll, ll = g_list_next(ll)) {
-               noticb = l->data;
-
-               if (noticb->deleted) {
-                       noti->callbacks = g_list_delete_link(noti->callbacks,
-                                       l);
-                       free(noticb);
-               }
-       }
-       pthread_mutex_unlock(&noti->cbs_lock);
-
-       noti->id = 0;
-
-       return G_SOURCE_REMOVE;
-}
-
 static int del_noticb(struct bxt_noti *noti, buxton_notify_callback notify,
                int *count)
 {
        GList *l;
+       GList *ll;
        gboolean f;
        int cnt;
 
@@ -1356,18 +1360,20 @@ static int del_noticb(struct bxt_noti *noti, buxton_notify_callback notify,
        f = FALSE;
 
        pthread_mutex_lock(&noti->cbs_lock);
-       for (l = noti->callbacks; l; l = g_list_next(l)) {
+       for (l = noti->callbacks, ll = g_list_next(l); l;
+                       l = ll, ll = g_list_next(ll)) {
                struct bxt_noti_cb *noticb = l->data;
 
                if (noticb->callback == notify) {
                        f = TRUE;
-                       noticb->deleted = TRUE;
-                       if (!noti->id)
-                               noti->id = g_idle_add(del_noticb_cb, noti);
-               }
-
-               if (noticb->deleted == FALSE)
+                       noticb->ref_cnt--;
+                       if (noticb->ref_cnt == 0) {
+                               noti->callbacks = g_list_delete_link(noti->callbacks, l);
+                               free(noticb);
+                       }
+               } else {
                        cnt++;
+               }
        }
        pthread_mutex_unlock(&noti->cbs_lock);
 
index 22e5620..3de1328 100644 (file)
@@ -51,7 +51,7 @@ struct noti {
 struct noti_cb {
        vconf_callback_fn cb;
        void *user_data;
-       gboolean deleted;
+       int ref_cnt;
 };
 
 static bool last_result;
@@ -144,40 +144,22 @@ static struct buxton_layer *get_layer(const char *key)
        return system_layer;
 }
 
-static gboolean free_noti_cb(gpointer data)
-{
-       GList *list = data;
-       GList *l;
-       GList *n;
-
-       if (!list)
-               return G_SOURCE_REMOVE;
-
-       for (l = list, n = g_list_next(l); l; l = n, n = g_list_next(n)) {
-               struct noti_cb *noticb = l->data;
-
-               if (!noticb->deleted)
-                       continue;
-
-               list = g_list_delete_link(list, l);
-               free(noticb);
-       }
-
-       return G_SOURCE_REMOVE;
-}
-
 static void free_noti(struct noti *noti)
 {
        GList *l;
+       GList *n;
 
        assert(noti);
 
-       for (l = noti->noti_list; l; l = g_list_next(l)) {
+       for (l = noti->noti_list, n = g_list_next(l);
+                       l; l = n, n = g_list_next(n)) {
                struct noti_cb *noticb = l->data;
-
-               noticb->deleted = TRUE;
+               noticb->ref_cnt--;
+               if (noticb->ref_cnt == 0) {
+                       noti->noti_list = g_list_delete_link(noti->noti_list, l);
+                       free(noticb);
+               }
        }
-       g_idle_add(free_noti_cb, noti->noti_list);
 
        free(noti->key);
        free(noti);
@@ -315,12 +297,56 @@ static void to_vconf_t(const struct buxton_value *val, keynode_t *node)
        }
 }
 
+static GList *copy_noti_list(GList *noti_list)
+{
+       GList *l;
+       GList *copy;
+
+       if (!noti_list)
+               return NULL;
+
+       pthread_mutex_lock(&vconf_lock);
+       for (l = noti_list; l; l = g_list_next(l)) {
+               struct noti_cb *noticb;
+               noticb = noti_list->data;
+               noticb->ref_cnt++;
+       }
+       copy = g_list_copy(noti_list);
+       pthread_mutex_unlock(&vconf_lock);
+
+       return copy;
+}
+
+static GList *free_copy_list(GList *noti_list, GList *copy_list)
+{
+       GList *l;
+       GList *ll;
+
+       pthread_mutex_lock(&vconf_lock);
+       g_list_free(copy_list);
+
+       for (l = noti_list, ll = g_list_next(l); l;
+                       l = ll, ll = g_list_next(ll)) {
+               struct noti_cb *noticb = l->data;
+
+               noticb->ref_cnt--;
+               if (noticb->ref_cnt == 0) {
+                       noti_list = g_list_delete_link(noti_list, l);
+                       free(noticb);
+               }
+       }
+       pthread_mutex_unlock(&vconf_lock);
+
+       return noti_list;
+}
+
 static void notify_cb(const struct buxton_layer *layer, const char *key,
                const struct buxton_value *val, void *user_data)
 {
        struct noti *noti = user_data;
        keynode_t *node;
        GList *l;
+       GList *copy;
 
        assert(noti);
 
@@ -331,16 +357,17 @@ static void notify_cb(const struct buxton_layer *layer, const char *key,
        node->keyname = (char *)key;
        to_vconf_t(val, node);
 
-       for (l = noti->noti_list; l; l = g_list_next(l)) {
-               struct noti_cb *noticb = l->data;
+       copy = copy_noti_list(noti->noti_list);
 
-               if (noticb->deleted)
-                       continue;
+       for (l = copy; l; l = g_list_next(l)) {
+               struct noti_cb *noticb = l->data;
 
                assert(noticb->cb);
                noticb->cb(node, noticb->user_data);
        }
 
+       noti->noti_list = free_copy_list(noti->noti_list, copy);
+
        free(node);
 }
 
@@ -371,12 +398,6 @@ static int add_noti(struct noti *noti, vconf_callback_fn cb, void *user_data)
 
        noticb = find_noti_cb(noti, cb);
        if (noticb) {
-               if (noticb->deleted) { /* reuse */
-                       noticb->user_data = user_data;
-                       noticb->deleted = FALSE;
-                       return 0;
-               }
-
                errno = EEXIST;
                return -1;
        }
@@ -387,7 +408,7 @@ static int add_noti(struct noti *noti, vconf_callback_fn cb, void *user_data)
 
        noticb->cb = cb;
        noticb->user_data = user_data;
-       noticb->deleted = FALSE;
+       noticb->ref_cnt = 1;
 
        noti->noti_list = g_list_append(noti->noti_list, noticb);
 
@@ -484,10 +505,7 @@ static int unregister_noti(struct noti *noti)
 
        cnt = 0;
        for (l = noti->noti_list; l; l = g_list_next(l)) {
-               struct noti_cb *noticb = l->data;
-
-               if (!noticb->deleted)
-                       cnt++;
+               cnt++;
        }
 
        if (cnt > 0)
@@ -525,7 +543,11 @@ EXPORT int vconf_ignore_key_changed(const char *key, vconf_callback_fn cb)
                return -1;
        }
 
-       noticb->deleted = TRUE;
+       noticb->ref_cnt--;
+       if (noticb->ref_cnt == 0) {
+               noti->noti_list = g_list_remove(noti->noti_list, noticb);
+               free(noticb);
+       }
 
        cnt = unregister_noti(noti);
        pthread_mutex_unlock(&vconf_lock);