summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: b14c223)
raw | patch | inline | side by side (parent: b14c223)
author | Max Kellermann <max@duempel.org> | |
Fri, 16 Oct 2009 13:06:58 +0000 (15:06 +0200) | ||
committer | Max Kellermann <max@duempel.org> | |
Fri, 16 Oct 2009 13:06:58 +0000 (15:06 +0200) |
If mpd_glib_leave() invokes the callback, and the callback destroys
the mpd_glib_source object, mpd_glib_leave() is unable to reset the
"leaving" flag. This patch adds the flag "destroyed" which lets
mpd_glib_leave() do the g_free() when it's ready.
the mpd_glib_source object, mpd_glib_leave() is unable to reset the
"leaving" flag. This patch adds the flag "destroyed" which lets
mpd_glib_leave() do the g_free() when it's ready.
src/gidle.c | patch | blob | history | |
src/gidle.h | patch | blob | history |
diff --git a/src/gidle.c b/src/gidle.c
index 16901679e84bd9d822f5e558ed34cfd249bc5597..d4fd8074351806ea56f7827e43848e1146097589 100644 (file)
--- a/src/gidle.c
+++ b/src/gidle.c
* flag is set, mpd_glib_enter() is a no-op to prevent this.
*/
bool leaving;
+
+ /**
+ * This flag is true when mpd_glib_free() has been called
+ * during a callback invoked from mpd_glib_leave().
+ * mpd_glib_leave() will do the real g_free() call then.
+ */
+ bool destroyed;
};
struct mpd_glib_source *
source->io_events = 0;
source->id = 0;
source->leaving = false;
+ source->destroyed = false;
return source;
}
void
mpd_glib_free(struct mpd_glib_source *source)
{
+ assert(!source->destroyed);
+
if (source->id != 0)
g_source_remove(source->id);
g_io_channel_unref(source->channel);
mpd_parser_free(source->parser);
- g_free(source);
+
+ if (source->leaving)
+ source->destroyed = true;
+ else
+ g_free(source);
}
static void
mpd_glib_invoke(const struct mpd_glib_source *source)
{
assert(source->id == 0);
+ assert(!source->destroyed);
if (source->idle_events != 0)
source->callback(MPD_ERROR_SUCCESS, 0, NULL,
const char *message)
{
assert(source->id == 0);
+ assert(!source->destroyed);
source->callback(error, server_error, message,
0, source->callback_ctx);
assert(source->io_events == 0);
assert(source->id == 0);
+ assert(!source->destroyed);
if (source->leaving)
return;
mpd_glib_add_watch(source);
}
-void
+bool
mpd_glib_leave(struct mpd_glib_source *source)
{
enum mpd_idle events;
+ assert(!source->destroyed);
+
if (source->id == 0)
/* already left, callback was invoked */
- return;
+ return true;
g_source_remove(source->id);
source->id = 0;
mpd_glib_invoke_error(source, error, server_error,
mpd_connection_get_error_message(source->connection));
+
+ if (source->destroyed) {
+ g_free(source);
+ return false;
+ }
+
source->leaving = false;
- return;
+ return true;
}
source->idle_events |= events;
mpd_glib_invoke(source);
+ if (source->destroyed) {
+ g_free(source);
+ return false;
+ }
+
source->leaving = false;
+ return true;
}
diff --git a/src/gidle.h b/src/gidle.h
index 3b460e214d54b74651f3abac36ff80b2647ab135..6d17f76191b155f7073ac944a28a178fb36d7a97 100644 (file)
--- a/src/gidle.h
+++ b/src/gidle.h
void
mpd_glib_enter(struct mpd_glib_source *source);
-void
+/**
+ * Leaves idle mode and invokes the callback if there were events.
+ *
+ * @return true on success, false if this object was deleted by the
+ * callback
+ */
+bool
mpd_glib_leave(struct mpd_glib_source *source);
#endif