gtask: Return cancelled tasks asynchronously

Once cancelled, a GTask's callback should not only be invoked
asynchronously with respect to the creation of the task, but also with
respect to the GCancellable::cancelled handler. This is particularly
relevant in cases where the cancellation happened in the same thread
where the task is running.

Spotted by Dan Winship and Michael Catanzaro.

Closes https://gitlab.gnome.org/GNOME/glib/issues/1608
This commit is contained in:
Debarshi Ray 2018-12-03 20:10:41 +01:00 committed by Philip Withnall
parent 0f8a4f61b0
commit 6f3d57d2ee

View File

@ -1,6 +1,6 @@
/* GIO - GLib Input, Output and Streaming Library /* GIO - GLib Input, Output and Streaming Library
* *
* Copyright 2011 Red Hat, Inc. * Copyright 2011-2018 Red Hat, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -1259,12 +1259,21 @@ g_task_return (GTask *task,
* same iteration of the main loop that the task was created in. * same iteration of the main loop that the task was created in.
*/ */
if (g_source_get_time (source) > task->creation_time) if (g_source_get_time (source) > task->creation_time)
{
/* Finally, if the task has been cancelled, we shouldn't
* return synchronously from inside the
* GCancellable::cancelled handler. It's easier to run
* another iteration of the main loop than tracking how the
* cancellation was handled.
*/
if (!g_cancellable_is_cancelled (task->cancellable))
{ {
g_task_return_now (task); g_task_return_now (task);
g_object_unref (task); g_object_unref (task);
return; return;
} }
} }
}
/* Otherwise, complete in the next iteration */ /* Otherwise, complete in the next iteration */
source = g_idle_source_new (); source = g_idle_source_new ();