brasero r1219 - in trunk: . src
- From: philippr svn gnome org
- To: svn-commits-list gnome org
- Subject: brasero r1219 - in trunk: . src
- Date: Sun, 31 Aug 2008 11:42:10 +0000 (UTC)
Author: philippr
Date: Sun Aug 31 11:42:10 2008
New Revision: 1219
URL: http://svn.gnome.org/viewvc/brasero?rev=1219&view=rev
Log:
Fix race condition in brasero-io
* src/brasero-async-task-manager.c
(brasero_async_task_manager_thread),
(brasero_async_task_manager_foreach_active_remove),
(brasero_async_task_manager_foreach_unprocessed_remove):
* src/brasero-async-task-manager.h:
* src/brasero-io.c (brasero_io_unref_result_callback_data),
(brasero_io_return_result), (brasero_io_set_job),
(brasero_io_job_free), (brasero_io_job_destroy),
(brasero_io_get_file_count_destroy),
(brasero_io_load_directory_destroy),
(brasero_io_load_directory_thread), (brasero_io_xfer_destroy),
(brasero_io_free_async_queue):
Modified:
trunk/ChangeLog
trunk/src/brasero-async-task-manager.c
trunk/src/brasero-async-task-manager.h
trunk/src/brasero-io.c
Modified: trunk/src/brasero-async-task-manager.c
==============================================================================
--- trunk/src/brasero-async-task-manager.c (original)
+++ trunk/src/brasero-async-task-manager.c Sun Aug 31 11:42:10 2008
@@ -265,32 +265,31 @@
self->priv->active_tasks = g_slist_remove (self->priv->active_tasks, ctx);
g_cond_signal (self->priv->task_finished);
- if (g_cancellable_is_cancelled (cancel)) {
- if (ctx->type->destroy)
- ctx->type->destroy (self, ctx->data);
-
- g_free (ctx);
- }
- else if (res == BRASERO_ASYNC_TASK_RESCHEDULE) {
- if (self->priv->waiting_tasks) {
- BraseroAsyncTaskCtx *next;
-
- next = self->priv->waiting_tasks->data;
- if (next->priority > ctx->priority)
- brasero_async_task_manager_insert_task (self, ctx);
+ /* NOTE: when threads are cancelled then they are destroyed in
+ * the function that cancelled them to destroy callback_data in
+ * the active main loop */
+ if (!g_cancellable_is_cancelled (cancel)) {
+ if (res == BRASERO_ASYNC_TASK_RESCHEDULE) {
+ if (self->priv->waiting_tasks) {
+ BraseroAsyncTaskCtx *next;
+
+ next = self->priv->waiting_tasks->data;
+ if (next->priority > ctx->priority)
+ brasero_async_task_manager_insert_task (self, ctx);
+ else
+ self->priv->waiting_tasks = g_slist_prepend (self->priv->waiting_tasks, ctx);
+ }
else
self->priv->waiting_tasks = g_slist_prepend (self->priv->waiting_tasks, ctx);
}
- else
- self->priv->waiting_tasks = g_slist_prepend (self->priv->waiting_tasks, ctx);
- }
- else {
- if (ctx->type->destroy)
- ctx->type->destroy (self, ctx->data);
- g_free (ctx);
+ else {
+ if (ctx->type->destroy)
+ ctx->type->destroy (self, FALSE, ctx->data);
+ g_free (ctx);
+ }
}
-
- g_cancellable_reset (cancel);
+ else
+ g_cancellable_reset (cancel);
}
end:
@@ -423,8 +422,11 @@
tasks = g_slist_remove (tasks, ctx);
- /* NOTE: no need to call destroy callback here
- * since it was done in the thread loop. */
+ /* destroy it */
+ if (ctx->type->destroy)
+ ctx->type->destroy (self, TRUE, ctx->data);
+
+ g_free (ctx);
}
}
@@ -455,7 +457,7 @@
/* call the destroy callback */
if (ctx->type->destroy)
- ctx->type->destroy (self, ctx->data);
+ ctx->type->destroy (self, TRUE, ctx->data);
g_free (ctx);
}
Modified: trunk/src/brasero-async-task-manager.h
==============================================================================
--- trunk/src/brasero-async-task-manager.h (original)
+++ trunk/src/brasero-async-task-manager.h Sun Aug 31 11:42:10 2008
@@ -63,6 +63,7 @@
GCancellable *cancel,
gpointer user_data);
typedef void (*BraseroAsyncDestroy) (BraseroAsyncTaskManager *manager,
+ gboolean cancelled,
gpointer user_data);
typedef gboolean (*BraseroAsyncFindTask) (BraseroAsyncTaskManager *manager,
gpointer task,
Modified: trunk/src/brasero-io.c
==============================================================================
--- trunk/src/brasero-io.c (original)
+++ trunk/src/brasero-io.c Sun Aug 31 11:42:10 2008
@@ -77,7 +77,7 @@
struct _BraseroIOResultCallbackData {
gpointer callback_data;
- guint ref;
+ gint ref;
};
typedef struct _BraseroIOResultCallbackData BraseroIOResultCallbackData;
@@ -251,8 +251,8 @@
if (!data)
return;
- data->ref --;
- if (data->ref > 0)
+ /* see atomically if we are the last to hold a lock */
+ if (!g_atomic_int_dec_and_test (&data->ref))
return;
if (destroy)
@@ -277,41 +277,6 @@
g_free (result);
}
-static void
-brasero_io_job_free (BraseroIOJob *job)
-{
- /* NOTE: the callback_data member is never destroyed here since it would
- * be destroyed in a thread different from the main loop.
- * Either it's destroyed in the thread that called brasero_io_cancel ()
- * or after all results are returned (and therefore in main loop).
- * As a special case, some jobs like read directory contents have to
- * return a dummy result to destroy the callback_data if the directory
- * is empty. */
-
- if (job->callback_data)
- job->callback_data->ref --;
-
- g_free (job->uri);
- g_free (job);
-}
-
-static void
-brasero_io_job_destroy (BraseroAsyncTaskManager *self,
- gpointer callback_data)
-{
- BraseroIOJob *job = callback_data;
-
- /* If a job is destroyed we don't call the destroy callback since it
- * otherwise it would be called in a different thread. All object that
- * cancel io ops are doing it either in destroy () and therefore handle
- * all destruction for callback_data or if they don't they usually don't
- * pass any callback data anyway. */
- /* NOTE: usually threads are cancelled from the main thread/loop and
- * block until the active task is removed which means that if we called
- * the destroy () then the destruction would be done in the main loop */
- brasero_io_job_free (job);
-}
-
/**
* Used to return the results
*/
@@ -392,8 +357,8 @@
result->uri = g_strdup (uri);
if (callback_data) {
+ g_atomic_int_inc (&callback_data->ref);
result->callback_data = callback_data;
- callback_data->ref ++;
}
brasero_io_queue_result (self, result);
@@ -416,7 +381,7 @@
job->callback_data = callback_data;
if (callback_data)
- job->callback_data->ref ++;
+ g_atomic_int_inc (&job->callback_data->ref);
}
static void
@@ -442,6 +407,72 @@
}
/**
+ * Job destruction
+ */
+
+static void
+brasero_io_job_free (BraseroIO *self,
+ gboolean cancelled,
+ BraseroIOJob *job)
+{
+ /* NOTE: the callback_data member is never destroyed here since it would
+ * be destroyed in a thread different from the main loop.
+ * Either it's destroyed in the thread that called brasero_io_cancel ()
+ * or after all results are returned (and therefore in main loop).
+ * As a special case, some jobs like read directory contents have to
+ * return a dummy result to destroy the callback_data if the directory
+ * is empty.
+ * If the job happens to be the last to carry a reference then destroy
+ * it but do it in the main loop by sending a dummy result. */
+
+ /* NOTE2: that's also used for directory loading when there aren't any
+ * result to notify the caller that the operation has finished but that
+ * there weren't any result to report. */
+ if (job->callback_data) {
+ /* see atomically if we are the last to hold a lock:
+ * If so, and if cancelled is TRUE destroy it now since we are
+ * always cancelled (and destroyed in the main loop). Otherwise
+ * add a dummy result to destroy callback_data. */
+ if (g_atomic_int_dec_and_test (&job->callback_data->ref)) {
+ if (cancelled) {
+ job->base->destroy (job->base->object,
+ TRUE,
+ job->callback_data);
+ g_free (job->callback_data);
+ }
+ else
+ brasero_io_return_result (self,
+ job->base,
+ NULL,
+ NULL,
+ NULL,
+ job->callback_data);
+ }
+ }
+
+ g_free (job->uri);
+ g_free (job);
+}
+
+static void
+brasero_io_job_destroy (BraseroAsyncTaskManager *manager,
+ gboolean cancelled,
+ gpointer callback_data)
+{
+ BraseroIOJob *job = callback_data;
+
+ /* If a job is destroyed we don't call the destroy callback since it
+ * otherwise it would be called in a different thread. All object that
+ * cancel io ops are doing it either in destroy () and therefore handle
+ * all destruction for callback_data or if they don't they usually don't
+ * pass any callback data anyway. */
+ /* NOTE: usually threads are cancelled from the main thread/loop and
+ * block until the active task is removed which means that if we called
+ * the destroy () then the destruction would be done in the main loop */
+ brasero_io_job_free (BRASERO_IO (manager), cancelled, job);
+}
+
+/**
* This part deals with symlinks, that allows to get unique filenames by
* replacing any parent symlink by its target and check for recursive
* symlinks
@@ -1197,6 +1228,7 @@
static void
brasero_io_get_file_count_destroy (BraseroAsyncTaskManager *manager,
+ gboolean cancelled,
gpointer callback_data)
{
BraseroIOCountData *data = callback_data;
@@ -1209,7 +1241,7 @@
brasero_io_job_progress_report_stop (BRASERO_IO (manager), callback_data);
- brasero_io_job_free (callback_data);
+ brasero_io_job_free (BRASERO_IO (manager), cancelled, callback_data);
}
#ifdef BUILD_PLAYLIST
@@ -1528,6 +1560,7 @@
static void
brasero_io_load_directory_destroy (BraseroAsyncTaskManager *manager,
+ gboolean cancelled,
gpointer callback_data)
{
BraseroIOContentsData *data = callback_data;
@@ -1535,7 +1568,7 @@
g_slist_foreach (data->children, (GFunc) g_object_unref, NULL);
g_slist_free (data->children);
- brasero_io_job_free (BRASERO_IO_JOB (data));
+ brasero_io_job_free (BRASERO_IO (manager), cancelled, BRASERO_IO_JOB (data));
}
#ifdef BUILD_PLAYLIST
@@ -1778,17 +1811,6 @@
g_object_unref (child);
}
- if (data->job.callback_data && data->job.callback_data->ref < 2) {
- /* No result was returned so we need to return a dummy one to
- * clean the callback_data in the main loop. */
- brasero_io_return_result (BRASERO_IO (manager),
- data->job.base,
- NULL,
- NULL,
- NULL,
- data->job.callback_data);
- }
-
g_file_enumerator_close (enumerator, NULL, NULL);
g_object_unref (enumerator);
g_object_unref (file);
@@ -1868,6 +1890,7 @@
static void
brasero_io_xfer_destroy (BraseroAsyncTaskManager *manager,
+ gboolean cancelled,
gpointer callback_data)
{
BraseroIOXferData *data = callback_data;
@@ -1879,7 +1902,7 @@
g_mutex_free (data->current_lock);
/* no need to stop progress report as the following function will do it */
- brasero_io_get_file_count_destroy (manager, callback_data);
+ brasero_io_get_file_count_destroy (manager, cancelled, callback_data);
}
static void
@@ -2384,8 +2407,7 @@
TRUE,
job->callback_data);
- brasero_io_job_free (job);
-
+ brasero_io_job_free (BRASERO_IO (manager), TRUE, job);
return TRUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]