Use thread default context 87/270587/5
authorHwankyu Jhun <h.jhun@samsung.com>
Tue, 8 Feb 2022 07:20:06 +0000 (16:20 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Thu, 24 Feb 2022 06:48:54 +0000 (15:48 +0900)
When calling the _vconf_add_noti() function, the function gets the current
-thread default context. While calling the registered callback function,
the context will be used to attach the source. The callback function of
vconf_notify_key_changed() will be invoked to the caller thread.

Change-Id: I2718ae07cb0e116322cae403547fa43bd71686d5
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
vconf-compat/vconf.c

index b9e4032..f81a762 100644 (file)
@@ -54,6 +54,7 @@ static int last_errno;
 
 static void _vconf_restore_noti_cb(gpointer key, gpointer value, gpointer user_data);
 static void _vconf_con_close(void);
+static gboolean _vconf_call_noti_cb(gpointer data);
 
 static pthread_mutex_t vconf_lock = PTHREAD_MUTEX_INITIALIZER;
 static int _refcnt;
@@ -73,13 +74,36 @@ struct noti_cb {
        void *user_data;
        bool active;
        bool in_cb;
+       GMainContext *thread_ctx;
 };
 
 struct callback_info {
        keynode_t *key_node;
-       int source_id;           /**< GSource id for call_noti_cb*/
+       struct noti_cb *noticb;
+       gint id;
+       GSource *source;
 };
 
+static struct noti_cb *_vconf_find_noti_cb(struct noti *noti, vconf_callback_fn cb);
+static void _vconf_to_vconf_t(const struct buxton_value *val, keynode_t *node);
+
+static GSource *_vconf_idle_add_full(GMainContext *context, guint priority, GSourceFunc func,
+               gpointer data)
+{
+       GSource *source;
+
+       source = g_idle_source_new();
+       if (!source)
+               return 0;
+
+       g_source_set_callback(source, func, data, NULL);
+       g_source_set_priority(source, priority);
+       g_source_attach(source, context);
+       g_source_unref(source);
+
+       return source;
+}
+
 static void _vconf_free_keynode(struct _keynode_t *keynode)
 {
        if (!keynode)
@@ -92,16 +116,100 @@ static void _vconf_free_keynode(struct _keynode_t *keynode)
        free(keynode);
 }
 
+static keynode_t *_vconf_create_keynode(const char *key,
+               const struct buxton_value *val)
+{
+       keynode_t *node;
+
+       node = calloc(1, sizeof(keynode_t));
+       if (!node)
+               return NULL;
+
+       node->keyname = strdup(key);
+       _vconf_to_vconf_t(val, node);
+
+       return node;
+}
+
+static struct noti_cb *_vconf_copy_noti_cb(struct noti_cb *noticb)
+{
+       struct noti_cb *clone;
+
+       if (!noticb)
+               return NULL;
+
+       clone = calloc(1, sizeof(struct noti_cb));
+       if (!clone)
+               return NULL;
+
+       clone->cb = noticb->cb;
+       clone->user_data = noticb->user_data;
+       clone->active = noticb->active;
+       clone->in_cb = noticb->in_cb;
+       clone->thread_ctx = g_main_context_ref(noticb->thread_ctx);
+
+       return clone;
+}
+
+static void _vconf_free_noti_cb(struct noti_cb *noticb)
+{
+       if (!noticb)
+               return;
+
+       if (noticb->thread_ctx)
+               g_main_context_unref(noticb->thread_ctx);
+
+       free(noticb);
+}
+
 static void _vconf_free_callback_info(struct callback_info *cb_info)
 {
        if (!cb_info)
                return;
 
+       if (cb_info->source && !g_source_is_destroyed(cb_info->source))
+               g_source_destroy(cb_info->source);
+
+       _vconf_free_noti_cb(cb_info->noticb);
        _vconf_free_keynode(cb_info->key_node);
-       g_source_remove(cb_info->source_id);
        free(cb_info);
 }
 
+static struct callback_info *_vconf_create_callback_info(const char *key,
+               const struct buxton_value *val, struct noti_cb *noticb)
+{
+       static gint id;
+       struct callback_info *cb_info;
+
+       cb_info = calloc(1, sizeof(struct callback_info));
+       if (!cb_info)
+               return NULL;
+
+       cb_info->key_node = _vconf_create_keynode(key, val);
+       if (!cb_info->key_node) {
+               _vconf_free_callback_info(cb_info);
+               return NULL;
+       }
+
+       cb_info->noticb = _vconf_copy_noti_cb(noticb);
+       if (!cb_info->noticb) {
+               _vconf_free_callback_info(cb_info);
+               return NULL;
+       }
+
+       g_atomic_int_inc(&id);
+       cb_info->id = id;
+
+       cb_info->source = _vconf_idle_add_full(cb_info->noticb->thread_ctx, G_PRIORITY_HIGH,
+                       _vconf_call_noti_cb, cb_info);
+       if (!cb_info->source) {
+               _vconf_free_callback_info(cb_info);
+               return NULL;
+       }
+
+       return cb_info;
+}
+
 __attribute__((destructor))
 static void _vconf_finish(void)
 {
@@ -240,7 +348,7 @@ static void _vconf_free_noti(struct noti *noti)
 
                if (!noticb->in_cb) {
                        noti->noti_list = g_list_delete_link(noti->noti_list, l);
-                       free(noticb);
+                       _vconf_free_noti_cb(noticb);
                }
        }
 
@@ -385,76 +493,35 @@ static void _vconf_to_vconf_t(const struct buxton_value *val, keynode_t *node)
        }
 }
 
-static GList *_vconf_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 = l->data;
-               noticb->in_cb = true;
-       }
-       copy = g_list_copy(noti_list);
-       pthread_mutex_unlock(&vconf_lock);
-
-       return copy;
-}
-
-static GList *_vconf_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->in_cb = false;
-
-               if (!noticb->active) {
-                       noti_list = g_list_delete_link(noti_list, l);
-                       free(noticb);
-               }
-       }
-       pthread_mutex_unlock(&vconf_lock);
-
-       return noti_list;
-}
-
 static gboolean _vconf_call_noti_cb(gpointer data)
 {
        struct callback_info *cb_info = (struct callback_info *)data;
        keynode_t *node = cb_info->key_node;
+       struct noti_cb *noticb = cb_info->noticb;
        struct noti *noti;
-       GList *l;
-       GList *copy;
+
+       cb_info->source = NULL;
 
        pthread_mutex_lock(&vconf_lock);
        noti = g_hash_table_lookup(noti_tbl, node->keyname);
        if (!noti) {
                pthread_mutex_unlock(&vconf_lock);
+               g_hash_table_remove(gsource_tbl, GINT_TO_POINTER(cb_info->id));
                return G_SOURCE_REMOVE;
        }
-       pthread_mutex_unlock(&vconf_lock);
-
-       copy = _vconf_copy_noti_list(noti->noti_list);
 
-       for (l = copy; l; l = g_list_next(l)) {
-               struct noti_cb *noticb = l->data;
-
-               assert(noticb->cb);
-               noticb->cb(node, noticb->user_data);
+       if (!_vconf_find_noti_cb(noti, noticb->cb)) {
+               pthread_mutex_unlock(&vconf_lock);
+               g_hash_table_remove(gsource_tbl, GINT_TO_POINTER(cb_info->id));
+               return G_SOURCE_REMOVE;
        }
+       pthread_mutex_unlock(&vconf_lock);
 
-       noti->noti_list = _vconf_free_copy_list(noti->noti_list, copy);
+       noticb->cb(node, noticb->user_data);
 
-       g_hash_table_remove(gsource_tbl, GINT_TO_POINTER(cb_info->source_id));
+       pthread_mutex_lock(&vconf_lock);
+       g_hash_table_remove(gsource_tbl, GINT_TO_POINTER(cb_info->id));
+       pthread_mutex_unlock(&vconf_lock);
 
        return G_SOURCE_REMOVE;
 }
@@ -462,33 +529,36 @@ static gboolean _vconf_call_noti_cb(gpointer data)
 static void _vconf_notify_cb(const struct buxton_layer *layer, const char *key,
                const struct buxton_value *val, void *user_data)
 {
-       keynode_t *node;
        struct callback_info *cb_info;
+       struct noti_cb *noticb;
+       struct noti* noti;
+       GList *iter;
 
-       node = calloc(1, sizeof(*node));
-       if (!node) {
-               LOGE("Failed to create keynode_t");
+       pthread_mutex_lock(&vconf_lock);
+       noti = g_hash_table_lookup(noti_tbl, key);
+       if (!noti) {
+               pthread_mutex_unlock(&vconf_lock);
                return;
        }
 
-       node->keyname = strdup(key);
-       _vconf_to_vconf_t(val, node);
-
-       cb_info = calloc(1, sizeof(*cb_info));
-       if (!cb_info) {
-               _vconf_free_keynode(node);
-               LOGE("Failed to create callback_info_s");
-               return;
+       if (gsource_tbl) {
+               gsource_tbl = g_hash_table_new_full(g_direct_hash,
+                               g_direct_equal, NULL,
+                               (GDestroyNotify)_vconf_free_callback_info);
        }
 
-       cb_info->key_node = node;
-       cb_info->source_id = g_idle_add_full(G_PRIORITY_HIGH, _vconf_call_noti_cb, cb_info, NULL);
-
-       if (gsource_tbl == NULL)
-               gsource_tbl = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-                               NULL, (GDestroyNotify)_vconf_free_callback_info);
+       for (iter = noti->noti_list; iter; iter = g_list_next(iter)) {
+               noticb = iter->data;
+               cb_info = _vconf_create_callback_info(key, val, noticb);
+               if (!cb_info) {
+                       pthread_mutex_unlock(&vconf_lock);
+                       return;
+               }
 
-       g_hash_table_insert(gsource_tbl, GINT_TO_POINTER(cb_info->source_id), cb_info);
+               g_hash_table_insert(gsource_tbl, GINT_TO_POINTER(cb_info->id),
+                               cb_info);
+       }
+       pthread_mutex_unlock(&vconf_lock);
 }
 
 static struct noti_cb *_vconf_find_noti_cb(struct noti *noti, vconf_callback_fn cb)
@@ -541,6 +611,7 @@ static int _vconf_add_noti(struct noti *noti, vconf_callback_fn cb, void *user_d
        noticb->user_data = user_data;
        noticb->active = true;
        noticb->in_cb = false;
+       noticb->thread_ctx = g_main_context_ref_thread_default();
 
        noti->noti_list = g_list_append(noti->noti_list, noticb);
 
@@ -711,7 +782,7 @@ EXPORT int vconf_ignore_key_changed(const char *key, vconf_callback_fn cb)
        noticb->active = false;
        if (!noticb->in_cb) {
                noti->noti_list = g_list_remove(noti->noti_list, noticb);
-               free(noticb);
+               _vconf_free_noti_cb(noticb);
        }
 
        cnt = _vconf_unregister_noti(noti);