gatchat: Fix calling unregister from callbacks

This fixes the issues with SIM hotswap on infineon
This commit is contained in:
Denis Kenzior 2010-10-14 09:41:09 -05:00
parent 167c72e588
commit 1e1ddfcf1b
1 changed files with 40 additions and 2 deletions

View File

@ -61,6 +61,7 @@ struct at_notify_node {
GAtNotifyFunc callback;
gpointer user_data;
GDestroyNotify notify;
gboolean destroyed;
};
typedef gboolean (*node_remove_func)(struct at_notify_node *node,
@ -96,6 +97,7 @@ struct at_chat {
GAtSyntax *syntax;
gboolean destroyed; /* Re-entrancy guard */
gboolean in_read_handler; /* Re-entrancy guard */
gboolean in_notify;
GSList *terminator_list; /* Non-standard terminator */
};
@ -111,6 +113,11 @@ struct terminator_info {
gboolean success;
};
static gboolean node_is_destroyed(struct at_notify_node *node, gpointer user)
{
return node->destroyed;
}
static gint at_notify_node_compare_by_id(gconstpointer a, gconstpointer b)
{
const struct at_notify_node *node = a;
@ -158,6 +165,7 @@ static gint at_command_compare_by_id(gconstpointer a, gconstpointer b)
}
static gboolean at_chat_unregister_all(struct at_chat *chat,
gboolean mark_only,
node_remove_func func,
gpointer userdata)
{
@ -189,6 +197,13 @@ static gboolean at_chat_unregister_all(struct at_chat *chat,
continue;
}
if (mark_only) {
node->destroyed = TRUE;
p = c;
c = c->next;
continue;
}
if (p)
p->next = c->next;
else
@ -375,6 +390,8 @@ static gboolean at_chat_match_notify(struct at_chat *chat, char *line)
result.lines = 0;
result.final_or_pdu = 0;
chat->in_notify = TRUE;
while (g_hash_table_iter_next(&iter, &key, &value)) {
notify = value;
@ -398,9 +415,13 @@ static gboolean at_chat_match_notify(struct at_chat *chat, char *line)
ret = TRUE;
}
chat->in_notify = FALSE;
if (ret) {
g_slist_free(result.lines);
g_free(line);
at_chat_unregister_all(chat, FALSE, node_is_destroyed, NULL);
}
return ret;
@ -584,6 +605,9 @@ static void have_notify_pdu(struct at_chat *p, char *pdu, GAtResult *result)
struct at_notify *notify;
char *prefix;
gpointer key, value;
gboolean called = FALSE;
p->in_notify = TRUE;
g_hash_table_iter_init(&iter, p->notify_list);
@ -598,7 +622,13 @@ static void have_notify_pdu(struct at_chat *p, char *pdu, GAtResult *result)
continue;
g_slist_foreach(notify->nodes, at_notify_call_callback, result);
called = TRUE;
}
p->in_notify = FALSE;
if (called)
at_chat_unregister_all(p, FALSE, node_is_destroyed, NULL);
}
static void have_pdu(struct at_chat *p, char *pdu)
@ -1114,7 +1144,8 @@ static guint at_chat_register(struct at_chat *chat, guint group,
return node->id;
}
static gboolean at_chat_unregister(struct at_chat *chat, guint group, guint id)
static gboolean at_chat_unregister(struct at_chat *chat, gboolean mark_only,
guint group, guint id)
{
GHashTableIter iter;
struct at_notify *notify;
@ -1141,6 +1172,11 @@ static gboolean at_chat_unregister(struct at_chat *chat, guint group, guint id)
if (node->gid != group)
return FALSE;
if (mark_only) {
node->destroyed = TRUE;
return TRUE;
}
at_notify_node_destroy(node, NULL);
notify->nodes = g_slist_remove(notify->nodes, node);
@ -1439,7 +1475,8 @@ gboolean g_at_chat_unregister(GAtChat *chat, guint id)
if (chat == NULL)
return FALSE;
return at_chat_unregister(chat->parent, chat->group, id);
return at_chat_unregister(chat->parent, chat->parent->in_notify,
chat->group, id);
}
gboolean g_at_chat_unregister_all(GAtChat *chat)
@ -1448,6 +1485,7 @@ gboolean g_at_chat_unregister_all(GAtChat *chat)
return FALSE;
return at_chat_unregister_all(chat->parent,
chat->parent->in_notify,
node_compare_by_group,
GUINT_TO_POINTER(chat->group));
}