diff options
author | Denis Kenzior <denkenz@gmail.com> | 2010-10-14 09:41:09 -0500 |
---|---|---|
committer | Denis Kenzior <denkenz@gmail.com> | 2010-10-14 09:42:42 -0500 |
commit | 1e1ddfcf1bd5f8b6097ee3cfff99beb1eab6ad53 (patch) | |
tree | 643a11eabd33ec9a4a61e77d7c3532ffa3e906c2 /gatchat/gatchat.c | |
parent | 167c72e58808271ed568772ae892a38c079681a0 (diff) | |
download | ofono-1e1ddfcf1bd5f8b6097ee3cfff99beb1eab6ad53.tar.bz2 |
gatchat: Fix calling unregister from callbacks
This fixes the issues with SIM hotswap on infineon
Diffstat (limited to 'gatchat/gatchat.c')
-rw-r--r-- | gatchat/gatchat.c | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/gatchat/gatchat.c b/gatchat/gatchat.c index e69cd4e2..d05f4668 100644 --- a/gatchat/gatchat.c +++ b/gatchat/gatchat.c @@ -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)); } |