[brasero/gnome-2-28] Fix #599655 - brasero crashed with SIGSEGV in g_main_context_dispatch()



commit 6a6f3424fafb12fc582252d075b4fe13feb98568
Author: Philippe Rouquier <bonfire-app wanadoo fr>
Date:   Wed Nov 4 15:00:24 2009 +0100

    Fix #599655 -  brasero crashed with SIGSEGV in g_main_context_dispatch()
    Prevent brasero from returning concurent errors for video and audio projects.

 libbrasero-burn/brasero-data-session.c     |    2 +-
 libbrasero-burn/brasero-data-vfs.c         |    4 +-
 libbrasero-burn/brasero-track-stream-cfg.c |   21 ++++--
 libbrasero-utils/brasero-io.c              |  125 +++++++++++++++++++---------
 libbrasero-utils/brasero-io.h              |   29 ++++++-
 src/brasero-audio-disc.c                   |    4 +-
 src/brasero-player.c                       |    2 +-
 src/brasero-playlist.c                     |    2 +-
 src/brasero-project-manager.c              |    2 +-
 src/brasero-video-disc.c                   |    3 +-
 10 files changed, 137 insertions(+), 57 deletions(-)
---
diff --git a/libbrasero-burn/brasero-data-session.c b/libbrasero-burn/brasero-data-session.c
index c2d6b95..eeebaa4 100644
--- a/libbrasero-burn/brasero-data-session.c
+++ b/libbrasero-burn/brasero-data-session.c
@@ -530,7 +530,7 @@ brasero_data_session_stop_io (BraseroDataSession *self)
 
 	if (priv->load_dir) {
 		brasero_io_cancel_by_base (priv->load_dir);
-		g_free (priv->load_dir);
+		brasero_io_job_base_free (priv->load_dir);
 		priv->load_dir = NULL;
 	}
 }
diff --git a/libbrasero-burn/brasero-data-vfs.c b/libbrasero-burn/brasero-data-vfs.c
index f2c58f1..29564c0 100644
--- a/libbrasero-burn/brasero-data-vfs.c
+++ b/libbrasero-burn/brasero-data-vfs.c
@@ -983,13 +983,13 @@ brasero_data_vfs_clear (BraseroDataVFS *self)
 	/* Stop all VFS operations */
 	if (priv->load_uri) {
 		brasero_io_cancel_by_base (priv->load_uri);
-		g_free (priv->load_uri);
+		brasero_io_job_base_free (priv->load_uri);
 		priv->load_uri = NULL;
 	}
 
 	if (priv->load_contents) {
 		brasero_io_cancel_by_base (priv->load_contents);
-		g_free (priv->load_contents);
+		brasero_io_job_base_free (priv->load_contents);
 		priv->load_contents = NULL;
 	}
 
diff --git a/libbrasero-burn/brasero-track-stream-cfg.c b/libbrasero-burn/brasero-track-stream-cfg.c
index f66c1f4..7e1527e 100644
--- a/libbrasero-burn/brasero-track-stream-cfg.c
+++ b/libbrasero-burn/brasero-track-stream-cfg.c
@@ -43,6 +43,8 @@
 #include "brasero-io.h"
 #include "brasero-tags.h"
 
+static BraseroIOJobCallbacks *io_methods = NULL;
+
 typedef struct _BraseroTrackStreamCfgPrivate BraseroTrackStreamCfgPrivate;
 struct _BraseroTrackStreamCfgPrivate
 {
@@ -295,11 +297,14 @@ brasero_track_stream_cfg_get_info (BraseroTrackStreamCfg *track)
 	}
 
 	/* get info async for the file */
-	if (!priv->load_uri)
-		priv->load_uri = brasero_io_register (G_OBJECT (track),
-						      brasero_track_stream_cfg_results_cb,
-						      NULL,
-						      NULL);
+	if (!priv->load_uri) {
+		if (!io_methods)
+			io_methods = brasero_io_register_job_methods (brasero_track_stream_cfg_results_cb,
+			                                              NULL,
+			                                              NULL);
+
+		priv->load_uri = brasero_io_register_with_methods (G_OBJECT (track), io_methods);
+	}
 
 	priv->loading = TRUE;
 	uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), TRUE);
@@ -379,7 +384,11 @@ brasero_track_stream_cfg_finalize (GObject *object)
 
 	if (priv->load_uri) {
 		brasero_io_cancel_by_base (priv->load_uri);
-		g_free (priv->load_uri);
+
+		if (io_methods->ref == 1)
+			io_methods = NULL;
+
+		brasero_io_job_base_free (priv->load_uri);
 		priv->load_uri = NULL;
 	}
 
diff --git a/libbrasero-utils/brasero-io.c b/libbrasero-utils/brasero-io.c
index a2c0ec4..ebeb4bb 100644
--- a/libbrasero-utils/brasero-io.c
+++ b/libbrasero-utils/brasero-io.c
@@ -182,9 +182,9 @@ brasero_io_job_progress_report_cb (gpointer callback_data)
 
 		/* update our progress */
 		progress->progress (progress->job, progress);
-		progress->job->base->progress (progress->job->base->object,
-					       progress,
-					       callback_data);
+		progress->job->base->methods->progress (progress->job->base->object,
+		                                        progress,
+		                                        callback_data);
 	}
 	g_mutex_unlock (priv->lock);
 
@@ -201,7 +201,7 @@ brasero_io_job_progress_report_start (BraseroIO *self,
 
 	priv = BRASERO_IO_PRIVATE (self);
 
-	if (!job->base->progress)
+	if (!job->base->methods->progress)
 		return;
 
 	progress = g_new0 (BraseroIOJobProgress, 1);
@@ -327,8 +327,6 @@ brasero_io_return_result_idle (gpointer callback_data)
 	BraseroIOJobResult *result;
 	BraseroIOPrivate *priv;
 	guint results_id;
-	GSList *iter;
-	GSList *next;
 	int i;
 
 	priv = BRASERO_IO_PRIVATE (self);
@@ -337,62 +335,72 @@ brasero_io_return_result_idle (gpointer callback_data)
 
 	/* Put that to 0 for now so that a new idle call will be scheduled while
 	 * we are in the loop. That way if we block the other one will be able 
-	 * to deliver the results. */
+	 * to deliver results. */
 	results_id = priv->results_id;
 	priv->results_id = 0;
 
 	/* Return several results at a time that can be a huge speed gain.
 	 * What should be the value that provides speed and responsiveness? */
-	for (i = 0, iter = priv->results; iter && i < NUMBER_OF_RESULTS; iter = next) {
+	for (i = 0; priv->results && i < NUMBER_OF_RESULTS;) {
 		BraseroIOJobBase *base;
+		GSList *iter;
 
-		result = iter->data;
-		next = iter->next;
+		/* Find the next result that can be returned */
+		result = NULL;
+		for (iter = priv->results; iter; iter = iter->next) {
+			BraseroIOJobResult *tmp_result;
+
+			tmp_result = iter->data;
+			if (!tmp_result->base->methods->in_use) {
+				result = tmp_result;
+				break;
+			}
+		}
+
+		if (!result)
+			break;
 
 		/* Make sure another result is not returned for this base. This 
 		 * is to avoid BraseroDataDisc showing multiple dialogs for 
 		 * various problems; like one dialog for joliet, one for deep,
 		 * and one for name collision. */
-		if (result->base->in_use)
-			continue;
+		base = (BraseroIOJobBase *) result->base;
+		base->methods->in_use = TRUE;
 
 		priv->results = g_slist_remove (priv->results, result);
 
-		base = (BraseroIOJobBase *) result->base;
-		base->in_use = TRUE;
+		/* This is to make sure the object
+		 *  lives as long as we need it. */
+		g_object_ref (base->object);
 
 		g_mutex_unlock (priv->lock);
 
 		data = result->callback_data;
 
-		/* This is to make sure the object lives
-		 * as long as we need it. */
-		g_object_ref (base->object);
-
 		if (result->uri || result->info || result->error)
-			result->base->callback (base->object,
-						result->error,
-						result->uri,
-						result->info,
-						data? data->callback_data:NULL);
+			base->methods->callback (base->object,
+			                          result->error,
+			                          result->uri,
+			                          result->info,
+			                          data? data->callback_data:NULL);
 
 		/* call destroy () for callback data */
 		brasero_io_unref_result_callback_data (data,
 						       base->object,
-						       base->destroy,
+						       base->methods->destroy,
 						       FALSE);
 
-		g_object_unref (base->object);
-
 		brasero_io_job_result_free (result);
 
 		g_mutex_lock (priv->lock);
 
 		i ++;
-		base->in_use = FALSE;
+
+		g_object_unref (base->object);
+		base->methods->in_use = FALSE;
 	}
 
-	if (!priv->results_id && iter && i >= NUMBER_OF_RESULTS) {
+	if (!priv->results_id && priv->results && i >= NUMBER_OF_RESULTS) {
 		/* There are still results and no idle call is scheduled so we
 		 * have to restart ourselves to make sure we empty the queue */
 		priv->results_id = results_id;
@@ -520,10 +528,10 @@ brasero_io_job_free (gboolean cancelled,
 		 * add a dummy result to destroy callback_data. */
 		if (g_atomic_int_dec_and_test (&job->callback_data->ref)) {
 			if (cancelled) {
-				if (job->base->destroy)
-					job->base->destroy (job->base->object,
-							    TRUE,
-							    job->callback_data->callback_data);
+				if (job->base->methods->destroy)
+					job->base->methods->destroy (job->base->object,
+					                              TRUE,
+					                              job->callback_data->callback_data);
 
 				g_free (job->callback_data);
 			}
@@ -2151,7 +2159,7 @@ brasero_io_cancel_result (BraseroIO *self,
 	data = result->callback_data;
 	brasero_io_unref_result_callback_data (data,
 					       result->base->object,
-					       result->base->destroy,
+					       result->base->methods->destroy,
 					       TRUE);
 	brasero_io_job_result_free (result);
 }
@@ -2294,23 +2302,60 @@ brasero_io_find_urgent (const BraseroIOJobBase *base,
 						     
 }
 
+BraseroIOJobCallbacks *
+brasero_io_register_job_methods (BraseroIOResultCallback callback,
+                                 BraseroIODestroyCallback destroy,
+                                 BraseroIOProgressCallback progress)
+{
+	BraseroIOJobCallbacks *methods;
+
+	methods = g_new0 (BraseroIOJobCallbacks, 1);
+	methods->callback = callback;
+	methods->destroy = destroy;
+	methods->progress = progress;
+
+	return methods;
+}
+
 BraseroIOJobBase *
-brasero_io_register (GObject *object,
-		     BraseroIOResultCallback callback,
-		     BraseroIODestroyCallback destroy,
-		     BraseroIOProgressCallback progress)
+brasero_io_register_with_methods (GObject *object,
+                                  BraseroIOJobCallbacks *methods)
 {
 	BraseroIOJobBase *base;
 
 	base = g_new0 (BraseroIOJobBase, 1);
 	base->object = object;
-	base->callback = callback;
-	base->destroy = destroy;
-	base->progress = progress;
+	base->methods = methods;
+	methods->ref ++;
 
 	return base;
 }
 
+BraseroIOJobBase *
+brasero_io_register (GObject *object,
+		     BraseroIOResultCallback callback,
+		     BraseroIODestroyCallback destroy,
+		     BraseroIOProgressCallback progress)
+{
+	return brasero_io_register_with_methods (object, brasero_io_register_job_methods (callback, destroy, progress));
+}
+
+void
+brasero_io_job_base_free (BraseroIOJobBase *base)
+{
+	BraseroIOJobCallbacks *methods;
+
+	if (!base)
+		return;
+
+	methods = base->methods;
+	g_free (base);
+
+	methods->ref --;
+	if (methods->ref <= 0)
+		g_free (methods);
+}
+
 static void
 brasero_io_init (BraseroIO *object)
 {
diff --git a/libbrasero-utils/brasero-io.h b/libbrasero-utils/brasero-io.h
index e536bcc..62fe468 100644
--- a/libbrasero-utils/brasero-io.h
+++ b/libbrasero-utils/brasero-io.h
@@ -106,15 +106,22 @@ typedef gboolean	(*BraseroIOCompareCallback)	(gpointer data,
 							 gpointer user_data);
 
 
-struct _BraseroIOJobBase {
-	GObject *object;
+struct _BraseroIOJobCallbacks {
 	BraseroIOResultCallback callback;
 	BraseroIODestroyCallback destroy;
 	BraseroIOProgressCallback progress;
 
+	guint ref;
+
 	/* Whether we are returning something for this base */
 	guint in_use:1;
 };
+typedef struct _BraseroIOJobCallbacks BraseroIOJobCallbacks;
+
+struct _BraseroIOJobBase {
+	GObject *object;
+	BraseroIOJobCallbacks *methods;
+};
 typedef struct _BraseroIOJobBase BraseroIOJobBase;
 
 struct _BraseroIOResultCallbackData {
@@ -159,12 +166,30 @@ brasero_io_return_result (const BraseroIOJobBase *base,
 void
 brasero_io_shutdown (void);
 
+/* NOTE: The split in methods and objects was
+ * done to prevent jobs sharing the same methods
+ * to return their results concurently. In other
+ * words only one job among those sharing the
+ * same methods can return its results. */
+ 
 BraseroIOJobBase *
 brasero_io_register (GObject *object,
 		     BraseroIOResultCallback callback,
 		     BraseroIODestroyCallback destroy,
 		     BraseroIOProgressCallback progress);
 
+BraseroIOJobBase *
+brasero_io_register_with_methods (GObject *object,
+                                  BraseroIOJobCallbacks *methods);
+
+BraseroIOJobCallbacks *
+brasero_io_register_job_methods (BraseroIOResultCallback callback,
+                                 BraseroIODestroyCallback destroy,
+                                 BraseroIOProgressCallback progress);
+
+void
+brasero_io_job_base_free (BraseroIOJobBase *base);
+
 void
 brasero_io_cancel_by_data (gpointer callback_data);
 
diff --git a/src/brasero-audio-disc.c b/src/brasero-audio-disc.c
index 8163184..3458375 100644
--- a/src/brasero-audio-disc.c
+++ b/src/brasero-audio-disc.c
@@ -527,8 +527,8 @@ brasero_audio_disc_finalize (GObject *object)
 	
 	brasero_audio_disc_reset_real (cobj);
 
-	g_free (cobj->priv->add_dir);
-	g_free (cobj->priv->add_playlist);
+	brasero_io_job_base_free (cobj->priv->add_dir);
+	brasero_io_job_base_free (cobj->priv->add_playlist);
 	cobj->priv->add_dir = NULL;
 	cobj->priv->add_playlist = NULL;
 
diff --git a/src/brasero-player.c b/src/brasero-player.c
index ee3e292..ad47dd6 100644
--- a/src/brasero-player.c
+++ b/src/brasero-player.c
@@ -1302,7 +1302,7 @@ brasero_player_destroy (GtkObject *obj)
 
 	if (player->priv->meta_task){
 		brasero_io_cancel_by_base (player->priv->meta_task);
-		g_free (player->priv->meta_task);
+		brasero_io_job_base_free (player->priv->meta_task);
 		player->priv->meta_task = 0;
 	}
 
diff --git a/src/brasero-playlist.c b/src/brasero-playlist.c
index 848e614..9593ade 100644
--- a/src/brasero-playlist.c
+++ b/src/brasero-playlist.c
@@ -437,7 +437,7 @@ brasero_playlist_destroy (GtkObject *object)
 	 * raise problems since the GdkWindow has been destroyed */
 	if (playlist->priv->parse_type) {
 		brasero_io_cancel_by_base (playlist->priv->parse_type);
-		g_free (playlist->priv->parse_type);
+		brasero_io_job_base_free (playlist->priv->parse_type);
 		playlist->priv->parse_type = NULL;
 	}
 
diff --git a/src/brasero-project-manager.c b/src/brasero-project-manager.c
index 4c4b420..5f5d5da 100644
--- a/src/brasero-project-manager.c
+++ b/src/brasero-project-manager.c
@@ -1017,7 +1017,7 @@ brasero_project_manager_finalize (GObject *object)
 
 	if (cobj->priv->size_preview) {
 		brasero_io_cancel_by_base (cobj->priv->size_preview);
-		g_free (cobj->priv->size_preview);
+		brasero_io_job_base_free (cobj->priv->size_preview);
 		cobj->priv->size_preview = NULL;
 	}
 
diff --git a/src/brasero-video-disc.c b/src/brasero-video-disc.c
index c1e2fdc..ff399a2 100644
--- a/src/brasero-video-disc.c
+++ b/src/brasero-video-disc.c
@@ -1272,7 +1272,8 @@ brasero_video_disc_finalize (GObject *object)
 	priv = BRASERO_VIDEO_DISC_PRIVATE (object);
 
 	if (priv->load_dir) {
-		g_free (priv->load_dir);
+		brasero_io_cancel_by_base (priv->load_dir);
+		brasero_io_job_base_free (priv->load_dir);
 		priv->load_dir = NULL;
 	}	
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]