From 6144d32a30486eca8d9a1ef587734622d06a8e3a Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Tue, 8 Feb 2022 16:20:06 +0900 Subject: [PATCH] Use thread default context 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 --- vconf-compat/vconf.c | 225 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 148 insertions(+), 77 deletions(-) diff --git a/vconf-compat/vconf.c b/vconf-compat/vconf.c index b9e4032..f81a762 100644 --- a/vconf-compat/vconf.c +++ b/vconf-compat/vconf.c @@ -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); -- 2.7.4