From b65194e8dfd3d9c3fabb16a189c0b326c175f9d5 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 25 Jun 2012 17:05:45 -0400 Subject: [PATCH] GIOScheduler: Disconnect from cancellable after job completes This was causing crashes when a cancellable was canceled after the job had completed. https://bugzilla.gnome.org/show_bug.cgi?id=678576 --- gio/gioscheduler.c | 49 +++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/gio/gioscheduler.c b/gio/gioscheduler.c index b94d8dd12..856e4b9df 100644 --- a/gio/gioscheduler.c +++ b/gio/gioscheduler.c @@ -53,6 +53,7 @@ struct _GIOSchedulerJob { gint io_priority; GCancellable *cancellable; + gulong cancellable_id; GMainContext *context; }; @@ -68,7 +69,11 @@ static void g_io_job_free (GIOSchedulerJob *job) { if (job->cancellable) - g_object_unref (job->cancellable); + { + if (job->cancellable_id) + g_cancellable_disconnect (job->cancellable, job->cancellable_id); + g_object_unref (job->cancellable); + } g_main_context_unref (job->context); g_free (job); } @@ -120,34 +125,18 @@ init_scheduler (gpointer arg) } static void -remove_active_job (GIOSchedulerJob *job) +on_job_canceled (GCancellable *cancellable, + gpointer user_data) { - GIOSchedulerJob *other_job; - GList *l; - gboolean resort_jobs; - - G_LOCK (active_jobs); - active_jobs = g_list_delete_link (active_jobs, job->active_link); - - resort_jobs = FALSE; - for (l = active_jobs; l != NULL; l = l->next) - { - other_job = l->data; - if (other_job->io_priority >= 0 && - g_cancellable_is_cancelled (other_job->cancellable)) - { - other_job->io_priority = -1; - resort_jobs = TRUE; - } - } - G_UNLOCK (active_jobs); - - if (resort_jobs && - job_thread_pool != NULL) + GIOSchedulerJob *job = user_data; + + job->io_priority = -1; + job->cancellable_id = 0; + + if (job_thread_pool != NULL) g_thread_pool_set_sort_function (job_thread_pool, g_io_job_compare, NULL); - } static void @@ -158,7 +147,9 @@ job_destroy (gpointer data) if (job->destroy_notify) job->destroy_notify (job->data); - remove_active_job (job); + G_LOCK (active_jobs); + active_jobs = g_list_delete_link (active_jobs, job->active_link); + G_UNLOCK (active_jobs); g_io_job_free (job); } @@ -221,7 +212,11 @@ g_io_scheduler_push_job (GIOSchedulerJobFunc job_func, job->io_priority = io_priority; if (cancellable) - job->cancellable = g_object_ref (cancellable); + { + job->cancellable = g_object_ref (cancellable); + job->cancellable_id = g_cancellable_connect (job->cancellable, (GCallback)on_job_canceled, + job, NULL); + } job->context = g_main_context_ref_thread_default ();