gboolean thread_cancelled;
gboolean synchronous;
gboolean thread_complete;
+ gboolean blocking_other_task;
GError *error;
union {
g_task_thread_pool_init ();)
static GThreadPool *task_pool;
+static GMutex task_pool_mutex;
+static GPrivate task_private = G_PRIVATE_INIT (NULL);
static void
g_task_init (GTask *task)
if (task->result_destroy && task->result.pointer)
task->result_destroy (task->result.pointer);
+ if (task->error)
+ g_error_free (task->error);
+
if (G_TASK_IS_THREADED (task))
{
g_mutex_clear (&task->lock);
/**
* g_task_new:
- * @source_object: (allow-none): the #GObject that owns this task, or %NULL.
+ * @source_object: (allow-none) (type GObject): the #GObject that owns
+ * this task, or %NULL.
* @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
* @callback: (scope async): a #GAsyncReadyCallback.
* @callback_data: (closure): user data passed to @callback.
/**
* g_task_report_error:
- * @source_object: (allow-none): the #GObject that owns this task, or %NULL.
+ * @source_object: (allow-none) (type GObject): the #GObject that owns
+ * this task, or %NULL.
* @callback: (scope async): a #GAsyncReadyCallback.
* @callback_data: (closure): user data passed to @callback.
* @source_tag: an opaque pointer indicating the source of this task
/**
* g_task_report_new_error:
- * @source_object: (allow-none): the #GObject that owns this task, or %NULL.
+ * @source_object: (allow-none) (type GObject): the #GObject that owns
+ * this task, or %NULL.
* @callback: (scope async): a #GAsyncReadyCallback.
* @callback_data: (closure): user data passed to @callback.
* @source_tag: an opaque pointer indicating the source of this task
* Gets the source object from @task. Like
* g_async_result_get_source_object(), but does not ref the object.
*
- * Returns: (transfer none): @task's source object, or %NULL
+ * Returns: (transfer none) (type GObject): @task's source object, or %NULL
*
* Since: 2.36
*/
/**
* GTaskThreadFunc:
* @task: the #GTask
- * @source_object: @task's source object
+ * @source_object: (type GObject): @task's source object
* @task_data: @task's task data
* @cancellable: @task's #GCancellable, or %NULL
*
}
task->thread_complete = TRUE;
+
+ if (task->blocking_other_task)
+ {
+ g_mutex_lock (&task_pool_mutex);
+ g_thread_pool_set_max_threads (task_pool,
+ g_thread_pool_get_max_threads (task_pool) - 1,
+ NULL);
+ g_mutex_unlock (&task_pool_mutex);
+ }
g_mutex_unlock (&task->lock);
if (task->cancellable)
{
GTask *task = thread_data;
+ g_private_set (&task_private, task);
+
task->task_func (task, task->source_object, task->task_data,
task->cancellable);
g_task_thread_complete (task);
+
+ g_private_set (&task_private, NULL);
g_object_unref (task);
}
g_thread_pool_push (task_pool, g_object_ref (task), &task->error);
if (task->error)
task->thread_complete = TRUE;
+ else if (g_private_get (&task_private))
+ {
+ /* This thread is being spawned from another GTask thread, so
+ * bump up max-threads so we don't starve.
+ */
+ g_mutex_lock (&task_pool_mutex);
+ if (g_thread_pool_set_max_threads (task_pool,
+ g_thread_pool_get_max_threads (task_pool) + 1,
+ NULL))
+ task->blocking_other_task = TRUE;
+ g_mutex_unlock (&task_pool_mutex);
+ }
}
/**
/**
* g_task_is_valid:
* @result: (type Gio.AsyncResult): A #GAsyncResult
- * @source_object: (allow-none): the source object expected to be
- * associated with the task
+ * @source_object: (allow-none) (type GObject): the source object
+ * expected to be associated with the task
*
* Checks that @result is a #GTask, and that @source_object is its
* source object (or that @source_object is %NULL and @result has no
const GTask *tb = b;
gboolean a_cancelled, b_cancelled;
+ /* Tasks that are causing other tasks to block have higher
+ * priority.
+ */
+ if (ta->blocking_other_task && !tb->blocking_other_task)
+ return -1;
+ else if (tb->blocking_other_task && !ta->blocking_other_task)
+ return 1;
+
+ /* Let already-cancelled tasks finish right away */
a_cancelled = (ta->check_cancellable &&
g_cancellable_is_cancelled (ta->cancellable));
b_cancelled = (tb->check_cancellable &&
g_cancellable_is_cancelled (tb->cancellable));
-
- /* Let already-cancelled tasks finish right away */
if (a_cancelled && !b_cancelled)
return -1;
else if (b_cancelled && !a_cancelled)