summaryrefslogtreecommitdiff
path: root/gatchat
diff options
context:
space:
mode:
authorDenis Kenzior <denkenz@gmail.com>2009-10-16 16:25:19 -0500
committerMarcel Holtmann <marcel@holtmann.org>2009-10-19 12:42:50 +0200
commit57ec42233cb80772563de634b6b22922112fbe76 (patch)
tree89770ef4e8530fab0c92115915c37e6d41fe6d7c /gatchat
parent98d3ef3a0c395916eac8acff3cdd085c9081be9b (diff)
downloadconnman-57ec42233cb80772563de634b6b22922112fbe76.tar.gz
connman-57ec42233cb80772563de634b6b22922112fbe76.tar.bz2
connman-57ec42233cb80772563de634b6b22922112fbe76.zip
Stop crashing when unrefing chat in callback
Diffstat (limited to 'gatchat')
-rw-r--r--gatchat/gatchat.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/gatchat/gatchat.c b/gatchat/gatchat.c
index c4de1471..66874e29 100644
--- a/gatchat/gatchat.c
+++ b/gatchat/gatchat.c
@@ -87,6 +87,7 @@ struct _GAtChat {
guint wakeup_timeout; /* How long to wait for resp */
GTimer *wakeup_timer; /* Keep track of elapsed time */
GAtSyntax *syntax;
+ gboolean destroyed; /* Re-entrancy guard */
};
static gint at_notify_node_compare_by_id(gconstpointer a, gconstpointer b)
@@ -259,6 +260,9 @@ static void read_watcher_destroy_notify(GAtChat *chat)
if (chat->user_disconnect)
chat->user_disconnect(chat->user_disconnect_data);
+
+ if (chat->destroyed)
+ g_free(chat);
}
static void write_watcher_destroy_notify(GAtChat *chat)
@@ -587,7 +591,9 @@ static void new_bytes(GAtChat *p)
GAtSyntaxResult result;
- while (p->read_so_far < len) {
+ g_at_chat_ref(p);
+
+ while (p->channel && (p->read_so_far < len)) {
gsize rbytes = MIN(len - p->read_so_far, wrap - p->read_so_far);
result = p->syntax->feed(p->syntax, (char *)buf, &rbytes);
@@ -628,8 +634,10 @@ static void new_bytes(GAtChat *p)
}
/* We're overflowing the buffer, shutdown the socket */
- if (ring_buffer_avail(p->buf) == 0)
+ if (p->buf && ring_buffer_avail(p->buf) == 0)
g_source_remove(p->read_watch);
+
+ g_at_chat_unref(p);
}
static void debug_chat(GAtChat *chat, gboolean in, const char *str, gsize len)
@@ -982,7 +990,16 @@ void g_at_chat_unref(GAtChat *chat)
return;
g_at_chat_shutdown(chat);
- g_free(chat);
+
+ /* glib delays the destruction of the watcher until it exits, this
+ * means we can't free the data just yet, even though we've been
+ * destroyed already. We have to wait until the read_watcher
+ * destroy function gets called
+ */
+ if (chat->read_watch != 0)
+ chat->destroyed = TRUE;
+ else
+ g_free(chat);
}
gboolean g_at_chat_shutdown(GAtChat *chat)