Code

gidle: added internal "destroyed" flag
authorMax Kellermann <max@duempel.org>
Fri, 16 Oct 2009 13:06:58 +0000 (15:06 +0200)
committerMax 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.

src/gidle.c
src/gidle.h

index 16901679e84bd9d822f5e558ed34cfd249bc5597..d4fd8074351806ea56f7827e43848e1146097589 100644 (file)
@@ -61,6 +61,13 @@ struct mpd_glib_source {
         * 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 *
@@ -81,6 +88,7 @@ mpd_glib_new(struct mpd_connection *connection,
        source->io_events = 0;
        source->id = 0;
        source->leaving = false;
+       source->destroyed = false;
 
        return source;
 }
@@ -88,19 +96,26 @@ mpd_glib_new(struct mpd_connection *connection,
 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,
@@ -113,6 +128,7 @@ mpd_glib_invoke_error(const struct mpd_glib_source *source,
                      const char *message)
 {
        assert(source->id == 0);
+       assert(!source->destroyed);
 
        source->callback(error, server_error, message,
                         0, source->callback_ctx);
@@ -328,6 +344,7 @@ mpd_glib_enter(struct mpd_glib_source *source)
 
        assert(source->io_events == 0);
        assert(source->id == 0);
+       assert(!source->destroyed);
 
        if (source->leaving)
                return;
@@ -343,14 +360,16 @@ mpd_glib_enter(struct mpd_glib_source *source)
        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;
@@ -373,12 +392,24 @@ mpd_glib_leave(struct mpd_glib_source *source)
 
                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;
 }
index 3b460e214d54b74651f3abac36ff80b2647ab135..6d17f76191b155f7073ac944a28a178fb36d7a97 100644 (file)
@@ -48,7 +48,13 @@ mpd_glib_free(struct mpd_glib_source *source);
 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