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;
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)
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)
{
if (!noticb->in_cb) {
noti->noti_list = g_list_delete_link(noti->noti_list, l);
- free(noticb);
+ _vconf_free_noti_cb(noticb);
}
}
}
}
-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;
}
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)
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);
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);