diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml index f1ad8a350..03dd28deb 100644 --- a/docs/reference/gio/gio-docs.xml +++ b/docs/reference/gio/gio-docs.xml @@ -40,9 +40,9 @@ Asynchronous I/O + - Data conversion diff --git a/gio/gasyncinitable.c b/gio/gasyncinitable.c index d5712a517..2508b9c03 100644 --- a/gio/gasyncinitable.c +++ b/gio/gasyncinitable.c @@ -64,13 +64,13 @@ * * for (l = self->priv->init_results; l != NULL; l = l->next) * { - * GSimpleAsyncResult *simple = l->data; + * GTask *task = l->data; * - * if (!self->priv->success) - * g_simple_async_result_set_error (simple, ...); - * - * g_simple_async_result_complete (simple); - * g_object_unref (simple); + * if (self->priv->success) + * g_task_return_boolean (task, TRUE); + * else + * g_task_return_new_error (task, ...); + * g_object_unref (task); * } * * g_list_free (self->priv->init_results); @@ -85,31 +85,28 @@ * gpointer user_data) * { * Foo *self = FOO (initable); - * GSimpleAsyncResult *simple; + * GTask *task; * - * simple = g_simple_async_result_new (G_OBJECT (initable) - * callback, - * user_data, - * foo_init_async); + * task = g_task_new (initable, cancellable, callback, user_data); * * switch (self->priv->state) * { * case NOT_INITIALIZED: * _foo_get_ready (self); * self->priv->init_results = g_list_append (self->priv->init_results, - * simple); + * task); * self->priv->state = INITIALIZING; * break; * case INITIALIZING: * self->priv->init_results = g_list_append (self->priv->init_results, - * simple); + * task); * break; * case INITIALIZED: * if (!self->priv->success) - * g_simple_async_result_set_error (simple, ...); - * - * g_simple_async_result_complete_in_idle (simple); - * g_object_unref (simple); + * g_task_return_new_error (task, ...); + * else + * g_task_return_boolean (task, TRUE); + * g_object_unref (task); * break; * } * } @@ -119,14 +116,9 @@ * GAsyncResult *result, * GError **error) * { - * g_return_val_if_fail (g_simple_async_result_is_valid (result, - * G_OBJECT (initable), foo_init_async), FALSE); + * g_return_val_if_fail (g_task_is_valid (result, initable), FALSE); * - * if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), - * error)) - * return FALSE; - * - * return TRUE; + * return g_task_propagate_boolean (G_TASK (result), error); * } * * static void diff --git a/gio/gasyncresult.c b/gio/gasyncresult.c index f4dbf32e8..c86b3dc59 100644 --- a/gio/gasyncresult.c +++ b/gio/gasyncresult.c @@ -30,7 +30,7 @@ * SECTION:gasyncresult * @short_description: Asynchronous Function Results * @include: gio/gio.h - * @see_also: #GSimpleAsyncResult + * @see_also: #GTask * * Provides a base class for implementing asynchronous function results. * @@ -103,6 +103,16 @@ * The callback for an asynchronous operation is called only once, and is * always called, even in the case of a cancelled operation. On cancellation * the result is a %G_IO_ERROR_CANCELLED error. + * + * I/O + * priority Many I/O-related asynchronous + * operations have a priority parameter, which is used in certain + * cases to determine the order in which operations are executed. They + * are not used to determine system-wide I/O + * scheduling. Priorities are integers, with lower numbers indicating + * higher priority. It is recommended to choose priorities between + * %G_PRIORITY_LOW and %G_PRIORITY_HIGH, with %G_PRIORITY_DEFAULT as a + * default. **/ typedef GAsyncResultIface GAsyncResultInterface; diff --git a/gio/gdbusinterfaceskeleton.c b/gio/gdbusinterfaceskeleton.c index e425f3fd9..5eb63d982 100644 --- a/gio/gdbusinterfaceskeleton.c +++ b/gio/gdbusinterfaceskeleton.c @@ -29,7 +29,7 @@ #include "gdbusprivate.h" #include "gdbusmethodinvocation.h" #include "gdbusconnection.h" -#include "gioscheduler.h" +#include "gtask.h" #include "gioerror.h" #include "glibintl.h" @@ -459,17 +459,13 @@ typedef struct GDBusInterfaceSkeleton *interface; GDBusInterfaceMethodCallFunc method_call_func; GDBusMethodInvocation *invocation; - GMainContext *context; } DispatchData; static void dispatch_data_unref (DispatchData *data) { if (g_atomic_int_dec_and_test (&data->ref_count)) - { - g_main_context_unref (data->context); - g_free (data); - } + g_slice_free (DispatchData, data); } static DispatchData * @@ -494,12 +490,13 @@ dispatch_invoke_in_context_func (gpointer user_data) return FALSE; } -static gboolean -dispatch_in_thread_func (GIOSchedulerJob *job, - GCancellable *cancellable, - gpointer user_data) +static void +dispatch_in_thread_func (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) { - DispatchData *data = user_data; + DispatchData *data = task_data; GDBusInterfaceSkeletonFlags flags; GDBusObject *object; gboolean authorized; @@ -549,8 +546,8 @@ dispatch_in_thread_func (GIOSchedulerJob *job, else { /* bah, back to original context */ - g_main_context_invoke_full (data->context, - G_PRIORITY_DEFAULT, + g_main_context_invoke_full (g_task_get_context (task), + g_task_get_priority (task), dispatch_invoke_in_context_func, dispatch_data_ref (data), (GDestroyNotify) dispatch_data_unref); @@ -563,8 +560,6 @@ dispatch_in_thread_func (GIOSchedulerJob *job, if (object != NULL) g_object_unref (object); - - return FALSE; } static void @@ -623,18 +618,19 @@ g_dbus_interface_method_dispatch_helper (GDBusInterfaceSkeleton *interface } else { + GTask *task; DispatchData *data; - data = g_new0 (DispatchData, 1); + + data = g_slice_new0 (DispatchData); data->interface = interface; data->method_call_func = method_call_func; data->invocation = invocation; - data->context = g_main_context_ref_thread_default (); data->ref_count = 1; - g_io_scheduler_push_job (dispatch_in_thread_func, - data, - (GDestroyNotify) dispatch_data_unref, - G_PRIORITY_DEFAULT, - NULL); /* GCancellable* */ + + task = g_task_new (interface, NULL, NULL, NULL); + g_task_set_task_data (task, data, (GDestroyNotify) dispatch_data_unref); + g_task_run_in_thread (task, dispatch_in_thread_func); + g_object_unref (task); } if (object != NULL) diff --git a/gio/gfile.c b/gio/gfile.c index 56fcf3ba7..18be0965c 100644 --- a/gio/gfile.c +++ b/gio/gfile.c @@ -5947,7 +5947,6 @@ typedef struct { GFileCopyFlags flags; GFileProgressCallback progress_cb; gpointer progress_cb_data; - GIOSchedulerJob *job; } CopyAsyncData; static void @@ -5955,7 +5954,7 @@ copy_async_data_free (CopyAsyncData *data) { g_object_unref (data->source); g_object_unref (data->destination); - g_free (data); + g_slice_free (CopyAsyncData, data); } typedef struct { @@ -5982,7 +5981,8 @@ copy_async_progress_callback (goffset current_num_bytes, goffset total_num_bytes, gpointer user_data) { - CopyAsyncData *data = user_data; + GTask *task = user_data; + CopyAsyncData *data = g_task_get_task_data (task); ProgressData *progress; progress = g_new (ProgressData, 1); @@ -5990,41 +5990,34 @@ copy_async_progress_callback (goffset current_num_bytes, progress->current_num_bytes = current_num_bytes; progress->total_num_bytes = total_num_bytes; - g_io_scheduler_job_send_to_mainloop_async (data->job, - copy_async_progress_in_main, - progress, - g_free); + g_main_context_invoke_full (g_task_get_context (task), + g_task_get_priority (task), + copy_async_progress_in_main, + progress, + g_free); } -static gboolean -copy_async_thread (GIOSchedulerJob *job, - GCancellable *cancellable, - gpointer user_data) +static void +copy_async_thread (GTask *task, + gpointer source, + gpointer task_data, + GCancellable *cancellable) { - GSimpleAsyncResult *res; - CopyAsyncData *data; + CopyAsyncData *data = task_data; gboolean result; - GError *error; + GError *error = NULL; - res = user_data; - data = g_simple_async_result_get_op_res_gpointer (res); - - error = NULL; - data->job = job; result = g_file_copy (data->source, data->destination, data->flags, cancellable, (data->progress_cb != NULL) ? copy_async_progress_callback : NULL, - data, + task, &error); - - if (!result) - g_simple_async_result_take_error (res, error); - - g_simple_async_result_complete_in_idle (res); - - return FALSE; + if (result) + g_task_return_boolean (task, TRUE); + else + g_task_return_error (task, error); } static void @@ -6038,20 +6031,21 @@ g_file_real_copy_async (GFile *source, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; + GTask *task; CopyAsyncData *data; - data = g_new0 (CopyAsyncData, 1); + data = g_slice_new (CopyAsyncData); data->source = g_object_ref (source); data->destination = g_object_ref (destination); data->flags = flags; data->progress_cb = progress_callback; data->progress_cb_data = progress_callback_data; - res = g_simple_async_result_new (G_OBJECT (source), callback, user_data, g_file_real_copy_async); - g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)copy_async_data_free); - - g_io_scheduler_push_job (copy_async_thread, res, g_object_unref, io_priority, cancellable); + task = g_task_new (source, cancellable, callback, user_data); + g_task_set_task_data (task, data, (GDestroyNotify)copy_async_data_free); + g_task_set_priority (task, io_priority); + g_task_run_in_thread (task, copy_async_thread); + g_object_unref (task); } static gboolean @@ -6059,12 +6053,7 @@ g_file_real_copy_finish (GFile *file, GAsyncResult *res, GError **error) { - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); - - if (g_simple_async_result_propagate_error (simple, error)) - return FALSE; - - return TRUE; + return g_task_propagate_boolean (G_TASK (res), error); } diff --git a/gio/gfileenumerator.c b/gio/gfileenumerator.c index a6db242fa..d8f622b39 100644 --- a/gio/gfileenumerator.c +++ b/gio/gfileenumerator.c @@ -303,7 +303,7 @@ next_async_callback_wrapper (GObject *source_object, * g_file_enumerator_next_files_async: * @enumerator: a #GFileEnumerator. * @num_files: the number of file info objects to request - * @io_priority: the io priority + * @io_priority: the io priority * of the request. * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied diff --git a/gio/gioscheduler.c b/gio/gioscheduler.c index f63996e8d..182931de8 100644 --- a/gio/gioscheduler.c +++ b/gio/gioscheduler.c @@ -24,34 +24,30 @@ #include "gioscheduler.h" #include "gcancellable.h" - +#include "gtask.h" /** * SECTION:gioscheduler * @short_description: I/O Scheduler * @include: gio/gio.h * + * + * As of GLib 2.36, the g_io_scheduler methods + * are deprecated in favor of #GThreadPool and #GTask. + * + * * Schedules asynchronous I/O operations. #GIOScheduler integrates * into the main event loop (#GMainLoop) and uses threads. - * - * I/O priority - * Each I/O operation has a priority, and the scheduler uses the priorities - * to determine the order in which operations are executed. They are - * not used to determine system-wide I/O scheduling. - * Priorities are integers, with lower numbers indicating higher priority. - * It is recommended to choose priorities between %G_PRIORITY_LOW and - * %G_PRIORITY_HIGH, with %G_PRIORITY_DEFAULT as a default. - * **/ struct _GIOSchedulerJob { GList *active_link; + GTask *task; + GIOSchedulerJobFunc job_func; - GSourceFunc cancel_func; /* Runs under job map lock */ gpointer data; GDestroyNotify destroy_notify; - gint io_priority; GCancellable *cancellable; gulong cancellable_id; GMainContext *context; @@ -60,98 +56,29 @@ struct _GIOSchedulerJob { G_LOCK_DEFINE_STATIC(active_jobs); static GList *active_jobs = NULL; -static GThreadPool *job_thread_pool = NULL; - -static void io_job_thread (gpointer data, - gpointer user_data); - static void g_io_job_free (GIOSchedulerJob *job) { - if (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); -} - -static gint -g_io_job_compare (gconstpointer a, - gconstpointer b, - gpointer user_data) -{ - const GIOSchedulerJob *aa = a; - const GIOSchedulerJob *bb = b; - - /* Cancelled jobs are set prio == -1, so that - they are executed as quickly as possible */ - - /* Lower value => higher priority */ - if (aa->io_priority < bb->io_priority) - return -1; - if (aa->io_priority == bb->io_priority) - return 0; - return 1; -} - -static gpointer -init_scheduler (gpointer arg) -{ - if (job_thread_pool == NULL) - { - /* TODO: thread_pool_new can fail */ - job_thread_pool = g_thread_pool_new (io_job_thread, - NULL, - 10, - FALSE, - NULL); - if (job_thread_pool != NULL) - { - g_thread_pool_set_sort_function (job_thread_pool, - g_io_job_compare, - NULL); - } - } - return NULL; -} - -static void -on_job_canceled (GCancellable *cancellable, - gpointer user_data) -{ - GIOSchedulerJob *job = user_data; - - /* This might be called more than once */ - job->io_priority = -1; - - if (job_thread_pool != NULL) - g_thread_pool_set_sort_function (job_thread_pool, - g_io_job_compare, - NULL); -} - -static void -job_destroy (gpointer data) -{ - GIOSchedulerJob *job = data; - if (job->destroy_notify) job->destroy_notify (job->data); G_LOCK (active_jobs); active_jobs = g_list_delete_link (active_jobs, job->active_link); G_UNLOCK (active_jobs); - g_io_job_free (job); + + if (job->cancellable) + g_object_unref (job->cancellable); + g_main_context_unref (job->context); + g_slice_free (GIOSchedulerJob, job); } static void -io_job_thread (gpointer data, - gpointer user_data) +io_job_thread (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) { - GIOSchedulerJob *job = data; + GIOSchedulerJob *job = task_data; gboolean result; if (job->cancellable) @@ -165,8 +92,6 @@ io_job_thread (gpointer data, if (job->cancellable) g_cancellable_pop_current (job->cancellable); - - job_destroy (job); } /** @@ -174,7 +99,7 @@ io_job_thread (gpointer data, * @job_func: a #GIOSchedulerJobFunc. * @user_data: data to pass to @job_func * @notify: (allow-none): a #GDestroyNotify for @user_data, or %NULL - * @io_priority: the I/O priority + * @io_priority: the I/O priority * of the request. * @cancellable: optional #GCancellable object, %NULL to ignore. * @@ -186,6 +111,8 @@ io_job_thread (gpointer data, * If @cancellable is not %NULL, it can be used to cancel the I/O job * by calling g_cancellable_cancel() or by calling * g_io_scheduler_cancel_all_jobs(). + * + * Deprecated: use #GThreadPool or g_task_run_in_thread() **/ void g_io_scheduler_push_job (GIOSchedulerJobFunc job_func, @@ -194,23 +121,18 @@ g_io_scheduler_push_job (GIOSchedulerJobFunc job_func, gint io_priority, GCancellable *cancellable) { - static GOnce once_init = G_ONCE_INIT; GIOSchedulerJob *job; + GTask *task; g_return_if_fail (job_func != NULL); - job = g_new0 (GIOSchedulerJob, 1); + job = g_slice_new0 (GIOSchedulerJob); job->job_func = job_func; job->data = user_data; job->destroy_notify = notify; - job->io_priority = io_priority; - + if (cancellable) - { - job->cancellable = g_object_ref (cancellable); - job->cancellable_id = g_cancellable_connect (job->cancellable, (GCallback)on_job_canceled, - job, NULL); - } + job->cancellable = g_object_ref (cancellable); job->context = g_main_context_ref_thread_default (); @@ -219,8 +141,11 @@ g_io_scheduler_push_job (GIOSchedulerJobFunc job_func, job->active_link = active_jobs; G_UNLOCK (active_jobs); - g_once (&once_init, init_scheduler, NULL); - g_thread_pool_push (job_thread_pool, job, NULL); + task = g_task_new (NULL, cancellable, NULL, NULL); + g_task_set_task_data (task, job, (GDestroyNotify)g_io_job_free); + g_task_set_priority (task, io_priority); + g_task_run_in_thread (task, io_job_thread); + g_object_unref (task); } /** @@ -230,6 +155,10 @@ g_io_scheduler_push_job (GIOSchedulerJobFunc job_func, * * A job is cancellable if a #GCancellable was passed into * g_io_scheduler_push_job(). + * + * Deprecated: You should never call this function, since you don't + * know how other libraries in your program might be making use of + * gioscheduler. **/ void g_io_scheduler_cancel_all_jobs (void) @@ -305,6 +234,8 @@ mainloop_proxy_free (MainLoopProxy *proxy) * blocking the I/O job). * * Returns: The return value of @func + * + * Deprecated: Use g_main_context_invoke(). **/ gboolean g_io_scheduler_job_send_to_mainloop (GIOSchedulerJob *job, @@ -361,6 +292,8 @@ g_io_scheduler_job_send_to_mainloop (GIOSchedulerJob *job, * on to this function you have to ensure that it is not freed before * @func is called, either by passing %NULL as @notify to * g_io_scheduler_push_job() or by using refcounting for @user_data. + * + * Deprecated: Use g_main_context_invoke(). **/ void g_io_scheduler_job_send_to_mainloop_async (GIOSchedulerJob *job, diff --git a/gio/gioscheduler.h b/gio/gioscheduler.h index 7d6b52738..431f06eb2 100644 --- a/gio/gioscheduler.h +++ b/gio/gioscheduler.h @@ -32,16 +32,20 @@ G_BEGIN_DECLS +GLIB_DEPRECATED_IN_2_36_FOR ("GThreadPool or g_task_run_in_thread") void g_io_scheduler_push_job (GIOSchedulerJobFunc job_func, gpointer user_data, GDestroyNotify notify, gint io_priority, GCancellable *cancellable); +GLIB_DEPRECATED_IN_2_36 void g_io_scheduler_cancel_all_jobs (void); +GLIB_DEPRECATED_IN_2_36_FOR (g_main_context_invoke) gboolean g_io_scheduler_job_send_to_mainloop (GIOSchedulerJob *job, GSourceFunc func, gpointer user_data, GDestroyNotify notify); +GLIB_DEPRECATED_IN_2_36_FOR (g_main_context_invoke) void g_io_scheduler_job_send_to_mainloop_async (GIOSchedulerJob *job, GSourceFunc func, gpointer user_data, diff --git a/gio/gsimpleasyncresult.c b/gio/gsimpleasyncresult.c index cd56b2a2c..c5d8103d5 100644 --- a/gio/gsimpleasyncresult.c +++ b/gio/gsimpleasyncresult.c @@ -45,10 +45,12 @@ * @include: gio/gio.h * @see_also: #GAsyncResult * - * Implements #GAsyncResult for simple cases. Most of the time, this - * will be all an application needs, and will be used transparently. - * Because of this, #GSimpleAsyncResult is used throughout GIO for - * handling asynchronous functions. + * + * As of GLib 2.36, #GSimpleAsyncResult is deprecated in favor of + * #GTask, which provides a simpler API. + * + * + * #GSimpleAsyncResult implements #GAsyncResult. * * GSimpleAsyncResult handles #GAsyncReadyCallbacks, error * reporting, operation cancellation and the final state of an operation, @@ -911,7 +913,9 @@ g_simple_async_result_run_in_thread (GSimpleAsyncResult *simple, data->cancellable = cancellable; if (cancellable) g_object_ref (cancellable); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; g_io_scheduler_push_job (run_in_thread, data, NULL, io_priority, cancellable); + G_GNUC_END_IGNORE_DEPRECATIONS; } /**