};
struct bxt_noti_cb {
- gboolean deleted;
+ int ref_cnt;
buxton_notify_callback callback;
void *data;
};
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);
}
pthread_mutex_lock(¬i->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(¬i->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(¬i->cbs_lock);
noticb->callback(rqst.layer, rqst.key, rqst.val, noticb->data);
- pthread_mutex_lock(¬i->cbs_lock);
}
+ pthread_mutex_lock(¬i->cbs_lock);
+ noti->callbacks = free_copy_callbacks(noti->callbacks, copy_callbacks);
pthread_mutex_unlock(¬i->cbs_lock);
free_request(&rqst);
noticb = l->data;
if (noticb->callback == notify) {
- if (noticb->deleted == FALSE) {
- errno = EEXIST;
- pthread_mutex_unlock(¬i->cbs_lock);
- return -1;
- }
-
- noticb->deleted = FALSE;
- noticb->callback = notify;
- noticb->data = notify_data;
-
+ errno = EEXIST;
pthread_mutex_unlock(¬i->cbs_lock);
- return 0;
+ return -1;
}
}
return -1;
}
- noticb->deleted = FALSE;
+ noticb->ref_cnt = 1;
noticb->callback = notify;
noticb->data = notify_data;
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(¬i->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(¬i->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;
f = FALSE;
pthread_mutex_lock(¬i->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(¬i->cbs_lock);
struct noti_cb {
vconf_callback_fn cb;
void *user_data;
- gboolean deleted;
+ int ref_cnt;
};
static bool last_result;
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);
}
}
+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);
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);
}
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;
}
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);
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)
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);