summaryrefslogtreecommitdiffstats
path: root/gatchat/gatchat.c
diff options
context:
space:
mode:
authorDenis Kenzior <denkenz@gmail.com>2010-10-14 09:41:09 -0500
committerDenis Kenzior <denkenz@gmail.com>2010-10-14 09:42:42 -0500
commit1e1ddfcf1bd5f8b6097ee3cfff99beb1eab6ad53 (patch)
tree643a11eabd33ec9a4a61e77d7c3532ffa3e906c2 /gatchat/gatchat.c
parent167c72e58808271ed568772ae892a38c079681a0 (diff)
downloadofono-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.c42
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));
}