Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright 2011-2018 Red Hat, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : */
20 : :
21 : : #include "config.h"
22 : : #include "gio_trace.h"
23 : :
24 : : #include "gtask.h"
25 : :
26 : : #include "gasyncresult.h"
27 : : #include "gcancellable.h"
28 : : #include "glib-private.h"
29 : : #include "gtrace-private.h"
30 : :
31 : : #include "glibintl.h"
32 : :
33 : : #include <string.h>
34 : :
35 : : /**
36 : : * GTask:
37 : : *
38 : : * A `GTask` represents and manages a cancellable ‘task’.
39 : : *
40 : : * ## Asynchronous operations
41 : : *
42 : : * The most common usage of `GTask` is as a [iface@Gio.AsyncResult], to
43 : : * manage data during an asynchronous operation. You call
44 : : * [ctor@Gio.Task.new] in the ‘start’ method, followed by
45 : : * [method@Gio.Task.set_task_data] and the like if you need to keep some
46 : : * additional data associated with the task, and then pass the
47 : : * task object around through your asynchronous operation.
48 : : * Eventually, you will call a method such as
49 : : * [method@Gio.Task.return_pointer] or [method@Gio.Task.return_error], which
50 : : * will save the value you give it and then invoke the task’s callback
51 : : * function in the thread-default main context (see
52 : : * [method@GLib.MainContext.push_thread_default])
53 : : * where it was created (waiting until the next iteration of the main
54 : : * loop first, if necessary). The caller will pass the `GTask` back to
55 : : * the operation’s finish function (as a [iface@Gio.AsyncResult]), and you can
56 : : * use [method@Gio.Task.propagate_pointer] or the like to extract the
57 : : * return value.
58 : : *
59 : : * Using `GTask` requires the thread-default [struct@GLib.MainContext] from when
60 : : * the `GTask` was constructed to be running at least until the task has
61 : : * completed and its data has been freed.
62 : : *
63 : : * If a `GTask` has been constructed and its callback set, it is an error to
64 : : * not call `g_task_return_*()` on it. GLib will warn at runtime if this happens
65 : : * (since 2.76).
66 : : *
67 : : * Here is an example for using `GTask` as a [iface@Gio.AsyncResult]:
68 : : * ```c
69 : : * typedef struct {
70 : : * CakeFrostingType frosting;
71 : : * char *message;
72 : : * } DecorationData;
73 : : *
74 : : * static void
75 : : * decoration_data_free (DecorationData *decoration)
76 : : * {
77 : : * g_free (decoration->message);
78 : : * g_slice_free (DecorationData, decoration);
79 : : * }
80 : : *
81 : : * static void
82 : : * baked_cb (Cake *cake,
83 : : * gpointer user_data)
84 : : * {
85 : : * GTask *task = user_data;
86 : : * DecorationData *decoration = g_task_get_task_data (task);
87 : : * GError *error = NULL;
88 : : *
89 : : * if (cake == NULL)
90 : : * {
91 : : * g_task_return_new_error (task, BAKER_ERROR, BAKER_ERROR_NO_FLOUR,
92 : : * "Go to the supermarket");
93 : : * g_object_unref (task);
94 : : * return;
95 : : * }
96 : : *
97 : : * if (!cake_decorate (cake, decoration->frosting, decoration->message, &error))
98 : : * {
99 : : * g_object_unref (cake);
100 : : * // g_task_return_error() takes ownership of error
101 : : * g_task_return_error (task, error);
102 : : * g_object_unref (task);
103 : : * return;
104 : : * }
105 : : *
106 : : * g_task_return_pointer (task, cake, g_object_unref);
107 : : * g_object_unref (task);
108 : : * }
109 : : *
110 : : * void
111 : : * baker_bake_cake_async (Baker *self,
112 : : * guint radius,
113 : : * CakeFlavor flavor,
114 : : * CakeFrostingType frosting,
115 : : * const char *message,
116 : : * GCancellable *cancellable,
117 : : * GAsyncReadyCallback callback,
118 : : * gpointer user_data)
119 : : * {
120 : : * GTask *task;
121 : : * DecorationData *decoration;
122 : : * Cake *cake;
123 : : *
124 : : * task = g_task_new (self, cancellable, callback, user_data);
125 : : * if (radius < 3)
126 : : * {
127 : : * g_task_return_new_error (task, BAKER_ERROR, BAKER_ERROR_TOO_SMALL,
128 : : * "%ucm radius cakes are silly",
129 : : * radius);
130 : : * g_object_unref (task);
131 : : * return;
132 : : * }
133 : : *
134 : : * cake = _baker_get_cached_cake (self, radius, flavor, frosting, message);
135 : : * if (cake != NULL)
136 : : * {
137 : : * // _baker_get_cached_cake() returns a reffed cake
138 : : * g_task_return_pointer (task, cake, g_object_unref);
139 : : * g_object_unref (task);
140 : : * return;
141 : : * }
142 : : *
143 : : * decoration = g_slice_new (DecorationData);
144 : : * decoration->frosting = frosting;
145 : : * decoration->message = g_strdup (message);
146 : : * g_task_set_task_data (task, decoration, (GDestroyNotify) decoration_data_free);
147 : : *
148 : : * _baker_begin_cake (self, radius, flavor, cancellable, baked_cb, task);
149 : : * }
150 : : *
151 : : * Cake *
152 : : * baker_bake_cake_finish (Baker *self,
153 : : * GAsyncResult *result,
154 : : * GError **error)
155 : : * {
156 : : * g_return_val_if_fail (g_task_is_valid (result, self), NULL);
157 : : *
158 : : * return g_task_propagate_pointer (G_TASK (result), error);
159 : : * }
160 : : * ```
161 : : *
162 : : * ## Chained asynchronous operations
163 : : *
164 : : * `GTask` also tries to simplify asynchronous operations that
165 : : * internally chain together several smaller asynchronous
166 : : * operations. [method@Gio.Task.get_cancellable], [method@Gio.Task.get_context],
167 : : * and [method@Gio.Task.get_priority] allow you to get back the task’s
168 : : * [class@Gio.Cancellable], [struct@GLib.MainContext], and
169 : : * [I/O priority](iface.AsyncResult.html#io-priority)
170 : : * when starting a new subtask, so you don’t have to keep track
171 : : * of them yourself. [method@Gio.Task.attach_source] simplifies the case
172 : : * of waiting for a source to fire (automatically using the correct
173 : : * [struct@GLib.MainContext] and priority).
174 : : *
175 : : * Here is an example for chained asynchronous operations:
176 : : * ```c
177 : : * typedef struct {
178 : : * Cake *cake;
179 : : * CakeFrostingType frosting;
180 : : * char *message;
181 : : * } BakingData;
182 : : *
183 : : * static void
184 : : * decoration_data_free (BakingData *bd)
185 : : * {
186 : : * if (bd->cake)
187 : : * g_object_unref (bd->cake);
188 : : * g_free (bd->message);
189 : : * g_slice_free (BakingData, bd);
190 : : * }
191 : : *
192 : : * static void
193 : : * decorated_cb (Cake *cake,
194 : : * GAsyncResult *result,
195 : : * gpointer user_data)
196 : : * {
197 : : * GTask *task = user_data;
198 : : * GError *error = NULL;
199 : : *
200 : : * if (!cake_decorate_finish (cake, result, &error))
201 : : * {
202 : : * g_object_unref (cake);
203 : : * g_task_return_error (task, error);
204 : : * g_object_unref (task);
205 : : * return;
206 : : * }
207 : : *
208 : : * // baking_data_free() will drop its ref on the cake, so we have to
209 : : * // take another here to give to the caller.
210 : : * g_task_return_pointer (task, g_object_ref (cake), g_object_unref);
211 : : * g_object_unref (task);
212 : : * }
213 : : *
214 : : * static gboolean
215 : : * decorator_ready (gpointer user_data)
216 : : * {
217 : : * GTask *task = user_data;
218 : : * BakingData *bd = g_task_get_task_data (task);
219 : : *
220 : : * cake_decorate_async (bd->cake, bd->frosting, bd->message,
221 : : * g_task_get_cancellable (task),
222 : : * decorated_cb, task);
223 : : *
224 : : * return G_SOURCE_REMOVE;
225 : : * }
226 : : *
227 : : * static void
228 : : * baked_cb (Cake *cake,
229 : : * gpointer user_data)
230 : : * {
231 : : * GTask *task = user_data;
232 : : * BakingData *bd = g_task_get_task_data (task);
233 : : * GError *error = NULL;
234 : : *
235 : : * if (cake == NULL)
236 : : * {
237 : : * g_task_return_new_error (task, BAKER_ERROR, BAKER_ERROR_NO_FLOUR,
238 : : * "Go to the supermarket");
239 : : * g_object_unref (task);
240 : : * return;
241 : : * }
242 : : *
243 : : * bd->cake = cake;
244 : : *
245 : : * // Bail out now if the user has already cancelled
246 : : * if (g_task_return_error_if_cancelled (task))
247 : : * {
248 : : * g_object_unref (task);
249 : : * return;
250 : : * }
251 : : *
252 : : * if (cake_decorator_available (cake))
253 : : * decorator_ready (task);
254 : : * else
255 : : * {
256 : : * GSource *source;
257 : : *
258 : : * source = cake_decorator_wait_source_new (cake);
259 : : * // Attach @source to @task’s GMainContext and have it call
260 : : * // decorator_ready() when it is ready.
261 : : * g_task_attach_source (task, source, decorator_ready);
262 : : * g_source_unref (source);
263 : : * }
264 : : * }
265 : : *
266 : : * void
267 : : * baker_bake_cake_async (Baker *self,
268 : : * guint radius,
269 : : * CakeFlavor flavor,
270 : : * CakeFrostingType frosting,
271 : : * const char *message,
272 : : * gint priority,
273 : : * GCancellable *cancellable,
274 : : * GAsyncReadyCallback callback,
275 : : * gpointer user_data)
276 : : * {
277 : : * GTask *task;
278 : : * BakingData *bd;
279 : : *
280 : : * task = g_task_new (self, cancellable, callback, user_data);
281 : : * g_task_set_priority (task, priority);
282 : : *
283 : : * bd = g_slice_new0 (BakingData);
284 : : * bd->frosting = frosting;
285 : : * bd->message = g_strdup (message);
286 : : * g_task_set_task_data (task, bd, (GDestroyNotify) baking_data_free);
287 : : *
288 : : * _baker_begin_cake (self, radius, flavor, cancellable, baked_cb, task);
289 : : * }
290 : : *
291 : : * Cake *
292 : : * baker_bake_cake_finish (Baker *self,
293 : : * GAsyncResult *result,
294 : : * GError **error)
295 : : * {
296 : : * g_return_val_if_fail (g_task_is_valid (result, self), NULL);
297 : : *
298 : : * return g_task_propagate_pointer (G_TASK (result), error);
299 : : * }
300 : : * ```
301 : : *
302 : : * ## Asynchronous operations from synchronous ones
303 : : *
304 : : * You can use [method@Gio.Task.run_in_thread] to turn a synchronous
305 : : * operation into an asynchronous one, by running it in a thread.
306 : : * When it completes, the result will be dispatched to the thread-default main
307 : : * context (see [method@GLib.MainContext.push_thread_default]) where the `GTask`
308 : : * was created.
309 : : *
310 : : * Running a task in a thread:
311 : : * ```c
312 : : * typedef struct {
313 : : * guint radius;
314 : : * CakeFlavor flavor;
315 : : * CakeFrostingType frosting;
316 : : * char *message;
317 : : * } CakeData;
318 : : *
319 : : * static void
320 : : * cake_data_free (CakeData *cake_data)
321 : : * {
322 : : * g_free (cake_data->message);
323 : : * g_slice_free (CakeData, cake_data);
324 : : * }
325 : : *
326 : : * static void
327 : : * bake_cake_thread (GTask *task,
328 : : * gpointer source_object,
329 : : * gpointer task_data,
330 : : * GCancellable *cancellable)
331 : : * {
332 : : * Baker *self = source_object;
333 : : * CakeData *cake_data = task_data;
334 : : * Cake *cake;
335 : : * GError *error = NULL;
336 : : *
337 : : * cake = bake_cake (baker, cake_data->radius, cake_data->flavor,
338 : : * cake_data->frosting, cake_data->message,
339 : : * cancellable, &error);
340 : : * if (cake)
341 : : * g_task_return_pointer (task, cake, g_object_unref);
342 : : * else
343 : : * g_task_return_error (task, error);
344 : : * }
345 : : *
346 : : * void
347 : : * baker_bake_cake_async (Baker *self,
348 : : * guint radius,
349 : : * CakeFlavor flavor,
350 : : * CakeFrostingType frosting,
351 : : * const char *message,
352 : : * GCancellable *cancellable,
353 : : * GAsyncReadyCallback callback,
354 : : * gpointer user_data)
355 : : * {
356 : : * CakeData *cake_data;
357 : : * GTask *task;
358 : : *
359 : : * cake_data = g_slice_new (CakeData);
360 : : * cake_data->radius = radius;
361 : : * cake_data->flavor = flavor;
362 : : * cake_data->frosting = frosting;
363 : : * cake_data->message = g_strdup (message);
364 : : * task = g_task_new (self, cancellable, callback, user_data);
365 : : * g_task_set_task_data (task, cake_data, (GDestroyNotify) cake_data_free);
366 : : * g_task_run_in_thread (task, bake_cake_thread);
367 : : * g_object_unref (task);
368 : : * }
369 : : *
370 : : * Cake *
371 : : * baker_bake_cake_finish (Baker *self,
372 : : * GAsyncResult *result,
373 : : * GError **error)
374 : : * {
375 : : * g_return_val_if_fail (g_task_is_valid (result, self), NULL);
376 : : *
377 : : * return g_task_propagate_pointer (G_TASK (result), error);
378 : : * }
379 : : * ```
380 : : *
381 : : * ## Adding cancellability to uncancellable tasks
382 : : *
383 : : * Finally, [method@Gio.Task.run_in_thread] and
384 : : * [method@Gio.Task.run_in_thread_sync] can be used to turn an uncancellable
385 : : * operation into a cancellable one. If you call
386 : : * [method@Gio.Task.set_return_on_cancel], passing `TRUE`, then if the task’s
387 : : * [class@Gio.Cancellable] is cancelled, it will return control back to the
388 : : * caller immediately, while allowing the task thread to continue running in the
389 : : * background (and simply discarding its result when it finally does finish).
390 : : * Provided that the task thread is careful about how it uses
391 : : * locks and other externally-visible resources, this allows you
392 : : * to make ‘GLib-friendly’ asynchronous and cancellable
393 : : * synchronous variants of blocking APIs.
394 : : *
395 : : * Cancelling a task:
396 : : * ```c
397 : : * static void
398 : : * bake_cake_thread (GTask *task,
399 : : * gpointer source_object,
400 : : * gpointer task_data,
401 : : * GCancellable *cancellable)
402 : : * {
403 : : * Baker *self = source_object;
404 : : * CakeData *cake_data = task_data;
405 : : * Cake *cake;
406 : : * GError *error = NULL;
407 : : *
408 : : * cake = bake_cake (baker, cake_data->radius, cake_data->flavor,
409 : : * cake_data->frosting, cake_data->message,
410 : : * &error);
411 : : * if (error)
412 : : * {
413 : : * g_task_return_error (task, error);
414 : : * return;
415 : : * }
416 : : *
417 : : * // If the task has already been cancelled, then we don’t want to add
418 : : * // the cake to the cake cache. Likewise, we don’t want to have the
419 : : * // task get cancelled in the middle of updating the cache.
420 : : * // g_task_set_return_on_cancel() will return %TRUE here if it managed
421 : : * // to disable return-on-cancel, or %FALSE if the task was cancelled
422 : : * // before it could.
423 : : * if (g_task_set_return_on_cancel (task, FALSE))
424 : : * {
425 : : * // If the caller cancels at this point, their
426 : : * // GAsyncReadyCallback won’t be invoked until we return,
427 : : * // so we don’t have to worry that this code will run at
428 : : * // the same time as that code does. But if there were
429 : : * // other functions that might look at the cake cache,
430 : : * // then we’d probably need a GMutex here as well.
431 : : * baker_add_cake_to_cache (baker, cake);
432 : : * g_task_return_pointer (task, cake, g_object_unref);
433 : : * }
434 : : * }
435 : : *
436 : : * void
437 : : * baker_bake_cake_async (Baker *self,
438 : : * guint radius,
439 : : * CakeFlavor flavor,
440 : : * CakeFrostingType frosting,
441 : : * const char *message,
442 : : * GCancellable *cancellable,
443 : : * GAsyncReadyCallback callback,
444 : : * gpointer user_data)
445 : : * {
446 : : * CakeData *cake_data;
447 : : * GTask *task;
448 : : *
449 : : * cake_data = g_slice_new (CakeData);
450 : : *
451 : : * ...
452 : : *
453 : : * task = g_task_new (self, cancellable, callback, user_data);
454 : : * g_task_set_task_data (task, cake_data, (GDestroyNotify) cake_data_free);
455 : : * g_task_set_return_on_cancel (task, TRUE);
456 : : * g_task_run_in_thread (task, bake_cake_thread);
457 : : * }
458 : : *
459 : : * Cake *
460 : : * baker_bake_cake_sync (Baker *self,
461 : : * guint radius,
462 : : * CakeFlavor flavor,
463 : : * CakeFrostingType frosting,
464 : : * const char *message,
465 : : * GCancellable *cancellable,
466 : : * GError **error)
467 : : * {
468 : : * CakeData *cake_data;
469 : : * GTask *task;
470 : : * Cake *cake;
471 : : *
472 : : * cake_data = g_slice_new (CakeData);
473 : : *
474 : : * ...
475 : : *
476 : : * task = g_task_new (self, cancellable, NULL, NULL);
477 : : * g_task_set_task_data (task, cake_data, (GDestroyNotify) cake_data_free);
478 : : * g_task_set_return_on_cancel (task, TRUE);
479 : : * g_task_run_in_thread_sync (task, bake_cake_thread);
480 : : *
481 : : * cake = g_task_propagate_pointer (task, error);
482 : : * g_object_unref (task);
483 : : * return cake;
484 : : * }
485 : : * ```
486 : : *
487 : : * ## Porting from [class@Gio.SimpleAsyncResult]
488 : : *
489 : : * `GTask`’s API attempts to be simpler than [class@Gio.SimpleAsyncResult]’s
490 : : * in several ways:
491 : : *
492 : : * - You can save task-specific data with [method@Gio.Task.set_task_data], and
493 : : * retrieve it later with [method@Gio.Task.get_task_data]. This replaces the
494 : : * abuse of [method@Gio.SimpleAsyncResult.set_op_res_gpointer] for the same
495 : : * purpose with [class@Gio.SimpleAsyncResult].
496 : : * - In addition to the task data, `GTask` also keeps track of the
497 : : * [priority](iface.AsyncResult.html#io-priority), [class@Gio.Cancellable],
498 : : * and [struct@GLib.MainContext] associated with the task, so tasks that
499 : : * consist of a chain of simpler asynchronous operations will have easy access
500 : : * to those values when starting each sub-task.
501 : : * - [method@Gio.Task.return_error_if_cancelled] provides simplified
502 : : * handling for cancellation. In addition, cancellation
503 : : * overrides any other `GTask` return value by default, like
504 : : * [class@Gio.SimpleAsyncResult] does when
505 : : * [method@Gio.SimpleAsyncResult.set_check_cancellable] is called.
506 : : * (You can use [method@Gio.Task.set_check_cancellable] to turn off that
507 : : * behavior.) On the other hand, [method@Gio.Task.run_in_thread]
508 : : * guarantees that it will always run your
509 : : * `task_func`, even if the task’s [class@Gio.Cancellable]
510 : : * is already cancelled before the task gets a chance to run;
511 : : * you can start your `task_func` with a
512 : : * [method@Gio.Task.return_error_if_cancelled] check if you need the
513 : : * old behavior.
514 : : * - The ‘return’ methods (eg, [method@Gio.Task.return_pointer])
515 : : * automatically cause the task to be ‘completed’ as well, and
516 : : * there is no need to worry about the ‘complete’ vs ‘complete in idle’
517 : : * distinction. (`GTask` automatically figures out
518 : : * whether the task’s callback can be invoked directly, or
519 : : * if it needs to be sent to another [struct@GLib.MainContext], or delayed
520 : : * until the next iteration of the current [struct@GLib.MainContext].)
521 : : * - The ‘finish’ functions for `GTask` based operations are generally
522 : : * much simpler than [class@Gio.SimpleAsyncResult] ones, normally consisting
523 : : * of only a single call to [method@Gio.Task.propagate_pointer] or the like.
524 : : * Since [method@Gio.Task.propagate_pointer] ‘steals’ the return value from
525 : : * the `GTask`, it is not necessary to juggle pointers around to
526 : : * prevent it from being freed twice.
527 : : * - With [class@Gio.SimpleAsyncResult], it was common to call
528 : : * [method@Gio.SimpleAsyncResult.propagate_error] from the
529 : : * `_finish()` wrapper function, and have
530 : : * virtual method implementations only deal with successful
531 : : * returns. This behavior is deprecated, because it makes it
532 : : * difficult for a subclass to chain to a parent class’s async
533 : : * methods. Instead, the wrapper function should just be a
534 : : * simple wrapper, and the virtual method should call an
535 : : * appropriate `g_task_propagate_` function.
536 : : * Note that wrapper methods can now use
537 : : * [method@Gio.AsyncResult.legacy_propagate_error] to do old-style
538 : : * [class@Gio.SimpleAsyncResult] error-returning behavior, and
539 : : * [method@Gio.AsyncResult.is_tagged] to check if a result is tagged as
540 : : * having come from the `_async()` wrapper
541 : : * function (for ‘short-circuit’ results, such as when passing
542 : : * `0` to [method@Gio.InputStream.read_async]).
543 : : *
544 : : * ## Thread-safety considerations
545 : : *
546 : : * Due to some infelicities in the API design, there is a
547 : : * thread-safety concern that users of `GTask` have to be aware of:
548 : : *
549 : : * If the `main` thread drops its last reference to the source object
550 : : * or the task data before the task is finalized, then the finalizers
551 : : * of these objects may be called on the worker thread.
552 : : *
553 : : * This is a problem if the finalizers use non-threadsafe API, and
554 : : * can lead to hard-to-debug crashes. Possible workarounds include:
555 : : *
556 : : * - Clear task data in a signal handler for `notify::completed`
557 : : * - Keep iterating a main context in the main thread and defer
558 : : * dropping the reference to the source object to that main
559 : : * context when the task is finalized
560 : : */
561 : :
562 : : struct _GTask {
563 : : GObject parent_instance;
564 : :
565 : : gpointer source_object;
566 : : gpointer source_tag;
567 : : gchar *name; /* (owned); may only be modified before the #GTask is threaded */
568 : :
569 : : gpointer task_data;
570 : : GDestroyNotify task_data_destroy;
571 : :
572 : : GMainContext *context;
573 : : gint64 creation_time;
574 : : gint priority;
575 : : GCancellable *cancellable;
576 : :
577 : : GAsyncReadyCallback callback;
578 : : gpointer callback_data;
579 : :
580 : : GTaskThreadFunc task_func;
581 : : GMutex lock;
582 : : GCond cond;
583 : :
584 : : /* This can’t be in the bit field because we access it from TRACE(). */
585 : : gboolean thread_cancelled;
586 : :
587 : : /* Protected by the lock when task is threaded: */
588 : : guint thread_complete : 1;
589 : : guint return_on_cancel : 1;
590 : : guint : 0;
591 : :
592 : : /* Unprotected, but written to when task runs in thread: */
593 : : guint completed : 1;
594 : : guint had_error : 1;
595 : : guint result_set : 1;
596 : : guint ever_returned : 1;
597 : : guint : 0;
598 : :
599 : : /* Read-only once task runs in thread: */
600 : : guint check_cancellable : 1;
601 : : guint synchronous : 1;
602 : : guint blocking_other_task : 1;
603 : : guint name_is_static : 1;
604 : :
605 : : GError *error;
606 : : union {
607 : : gpointer pointer;
608 : : gssize size;
609 : : gboolean boolean;
610 : : } result;
611 : : GDestroyNotify result_destroy;
612 : : };
613 : :
614 : : #define G_TASK_IS_THREADED(task) ((task)->task_func != NULL)
615 : :
616 : : struct _GTaskClass
617 : : {
618 : : GObjectClass parent_class;
619 : : };
620 : :
621 : : typedef enum
622 : : {
623 : : PROP_COMPLETED = 1,
624 : : } GTaskProperty;
625 : :
626 : : static void g_task_async_result_iface_init (GAsyncResultIface *iface);
627 : : static void g_task_thread_pool_init (void);
628 : :
629 : 2101442 : G_DEFINE_TYPE_WITH_CODE (GTask, g_task, G_TYPE_OBJECT,
630 : : G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT,
631 : : g_task_async_result_iface_init);
632 : : g_task_thread_pool_init ();)
633 : :
634 : : static GThreadPool *task_pool;
635 : : static GMutex task_pool_mutex;
636 : : static GPrivate task_private = G_PRIVATE_INIT (NULL);
637 : : static GSource *task_pool_manager;
638 : : static guint64 task_wait_time;
639 : : static gint tasks_running;
640 : :
641 : : static guint task_pool_max_counter;
642 : : static guint tasks_running_counter;
643 : :
644 : : /* When the task pool fills up and blocks, and the program keeps
645 : : * queueing more tasks, we will slowly add more threads to the pool
646 : : * (in case the existing tasks are trying to queue subtasks of their
647 : : * own) until tasks start completing again. These "overflow" threads
648 : : * will only run one task apiece, and then exit, so the pool will
649 : : * eventually get back down to its base size.
650 : : *
651 : : * The base and multiplier below gives us 10 extra threads after about
652 : : * a second of blocking, 30 after 5 seconds, 100 after a minute, and
653 : : * 200 after 20 minutes.
654 : : *
655 : : * We specify maximum pool size of 330 to increase the waiting time up
656 : : * to around 30 minutes.
657 : : */
658 : : #define G_TASK_POOL_SIZE 10
659 : : #define G_TASK_WAIT_TIME_BASE 100000
660 : : #define G_TASK_WAIT_TIME_MULTIPLIER 1.03
661 : : #define G_TASK_WAIT_TIME_MAX_POOL_SIZE 330
662 : :
663 : : static void
664 : 127390 : g_task_init (GTask *task)
665 : : {
666 : 127390 : task->check_cancellable = TRUE;
667 : 127390 : }
668 : :
669 : : #ifdef G_ENABLE_DEBUG
670 : : G_LOCK_DEFINE_STATIC (task_list);
671 : : static GPtrArray *task_list = NULL;
672 : :
673 : : void
674 : 0 : g_task_print_alive_tasks (void)
675 : : {
676 : 0 : GString *message_str = g_string_new ("");
677 : :
678 : 0 : G_LOCK (task_list);
679 : :
680 : 0 : if (task_list != NULL)
681 : : {
682 : 0 : g_string_append_printf (message_str, "%u GTasks still alive:", task_list->len);
683 : 0 : for (guint i = 0; i < task_list->len; i++)
684 : : {
685 : 0 : GTask *task = g_ptr_array_index (task_list, i);
686 : 0 : const gchar *name = g_task_get_name (task);
687 : 0 : g_string_append_printf (message_str,
688 : : "\n • GTask %p, %s, ref count: %u, ever_returned: %u, completed: %u",
689 : : task, (name != NULL) ? name : "(no name set)",
690 : : ((GObject *) task)->ref_count,
691 : 0 : task->ever_returned, task->completed);
692 : : }
693 : : }
694 : : else
695 : : {
696 : 0 : g_string_append (message_str, "No GTasks still alive");
697 : : }
698 : :
699 : 0 : G_UNLOCK (task_list);
700 : :
701 : 0 : g_message ("%s", message_str->str);
702 : 0 : g_string_free (message_str, TRUE);
703 : 0 : }
704 : :
705 : : static void
706 : 127390 : g_task_constructed (GObject *object)
707 : : {
708 : 127390 : GTask *task = G_TASK (object);
709 : :
710 : 127390 : G_OBJECT_CLASS (g_task_parent_class)->constructed (object);
711 : :
712 : : /* Track pending tasks for debugging purposes */
713 : 127390 : G_LOCK (task_list);
714 : 127390 : if (G_UNLIKELY (task_list == NULL))
715 : 2717 : task_list = g_ptr_array_new ();
716 : 127390 : g_ptr_array_add (task_list, task);
717 : 127390 : G_UNLOCK (task_list);
718 : 127390 : }
719 : : #endif /* G_ENABLE_DEBUG */
720 : :
721 : : static void
722 : 127231 : g_task_finalize (GObject *object)
723 : : {
724 : 127231 : GTask *task = G_TASK (object);
725 : :
726 : : /* Warn if a #GTask is finalised without g_task_return() ever having been
727 : : * called on it.
728 : : *
729 : : * Tasks without a callback or which are run in g_task_run_in_thread{,_sync}()
730 : : * only trigger a debug message as that’s sometimes used as a pattern for
731 : : * running work in a worker thread without caring about the result. */
732 : 127231 : if (!task->ever_returned)
733 : : {
734 : 25 : gchar *owned_task_name = NULL;
735 : 25 : const gchar *task_name = g_task_get_name (task);
736 : :
737 : 25 : if (task_name == NULL)
738 : 8 : task_name = owned_task_name = g_strdup_printf ("%p", task);
739 : :
740 : 25 : if (task->callback != NULL && !G_TASK_IS_THREADED (task))
741 : 2 : g_critical ("GTask %s (source object: %p, source tag: %p) finalized without "
742 : : "ever returning (using g_task_return_*()). This potentially "
743 : : "indicates a bug in the program.",
744 : : task_name, task->source_object, task->source_tag);
745 : : else
746 : 23 : g_debug ("GTask %s (source object: %p, source tag: %p) finalized without "
747 : : "ever returning (using g_task_return_*()). This potentially "
748 : : "indicates a bug in the program.",
749 : : task_name, task->source_object, task->source_tag);
750 : :
751 : 25 : g_free (owned_task_name);
752 : : }
753 : :
754 : 127231 : g_clear_object (&task->source_object);
755 : 127231 : g_clear_object (&task->cancellable);
756 : 127231 : if (!task->name_is_static)
757 : 10177 : g_free (task->name);
758 : :
759 : 127231 : if (task->context)
760 : 127230 : g_main_context_unref (task->context);
761 : :
762 : 127231 : if (task->task_data_destroy)
763 : 94448 : task->task_data_destroy (task->task_data);
764 : :
765 : 127231 : if (task->result_destroy && task->result.pointer)
766 : 9 : task->result_destroy (task->result.pointer);
767 : :
768 : 127231 : if (task->error)
769 : 2980 : g_error_free (task->error);
770 : :
771 : 127231 : if (G_TASK_IS_THREADED (task))
772 : : {
773 : 3496 : g_mutex_clear (&task->lock);
774 : 3496 : g_cond_clear (&task->cond);
775 : : }
776 : :
777 : : /* Track pending tasks for debugging purposes */
778 : : #ifdef G_ENABLE_DEBUG
779 : 127231 : G_LOCK (task_list);
780 : 127231 : g_assert (task_list != NULL);
781 : 127231 : g_ptr_array_remove_fast (task_list, task);
782 : 127231 : if (G_UNLIKELY (task_list->len == 0))
783 : 2652 : g_clear_pointer (&task_list, g_ptr_array_unref);
784 : 127231 : G_UNLOCK (task_list);
785 : : #endif /* G_ENABLE_DEBUG */
786 : :
787 : 127231 : G_OBJECT_CLASS (g_task_parent_class)->finalize (object);
788 : 127231 : }
789 : :
790 : : /**
791 : : * g_task_new:
792 : : * @source_object: (nullable) (type GObject): the #GObject that owns
793 : : * this task, or %NULL.
794 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
795 : : * @callback: (scope async): a #GAsyncReadyCallback.
796 : : * @callback_data: user data passed to @callback.
797 : : *
798 : : * Creates a #GTask acting on @source_object, which will eventually be
799 : : * used to invoke @callback in the current
800 : : * [thread-default main context][g-main-context-push-thread-default].
801 : : *
802 : : * Call this in the "start" method of your asynchronous method, and
803 : : * pass the #GTask around throughout the asynchronous operation. You
804 : : * can use g_task_set_task_data() to attach task-specific data to the
805 : : * object, which you can retrieve later via g_task_get_task_data().
806 : : *
807 : : * By default, if @cancellable is cancelled, then the return value of
808 : : * the task will always be %G_IO_ERROR_CANCELLED, even if the task had
809 : : * already completed before the cancellation. This allows for
810 : : * simplified handling in cases where cancellation may imply that
811 : : * other objects that the task depends on have been destroyed. If you
812 : : * do not want this behavior, you can use
813 : : * g_task_set_check_cancellable() to change it.
814 : : *
815 : : * Returns: a #GTask.
816 : : *
817 : : * Since: 2.36
818 : : */
819 : : GTask *
820 : 127389 : g_task_new (gpointer source_object,
821 : : GCancellable *cancellable,
822 : : GAsyncReadyCallback callback,
823 : : gpointer callback_data)
824 : : {
825 : : GTask *task;
826 : : GSource *source;
827 : :
828 : 127389 : task = g_object_new (G_TYPE_TASK, NULL);
829 : 127389 : task->source_object = source_object ? g_object_ref (source_object) : NULL;
830 : 127389 : task->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
831 : 127389 : task->callback = callback;
832 : 127389 : task->callback_data = callback_data;
833 : 127389 : task->context = g_main_context_ref_thread_default ();
834 : :
835 : 127389 : source = g_main_current_source ();
836 : 127389 : if (source)
837 : 117310 : task->creation_time = g_source_get_time (source);
838 : :
839 : 127389 : TRACE (GIO_TASK_NEW (task, source_object, cancellable,
840 : : callback, callback_data));
841 : :
842 : 127389 : return task;
843 : : }
844 : :
845 : : /**
846 : : * g_task_report_error:
847 : : * @source_object: (nullable) (type GObject): the #GObject that owns
848 : : * this task, or %NULL.
849 : : * @callback: (scope async) (closure callback_data): a #GAsyncReadyCallback.
850 : : * @callback_data: user data passed to @callback.
851 : : * @source_tag: an opaque pointer indicating the source of this task
852 : : * @error: (transfer full): error to report
853 : : *
854 : : * Creates a #GTask and then immediately calls g_task_return_error()
855 : : * on it. Use this in the wrapper function of an asynchronous method
856 : : * when you want to avoid even calling the virtual method. You can
857 : : * then use g_async_result_is_tagged() in the finish method wrapper to
858 : : * check if the result there is tagged as having been created by the
859 : : * wrapper method, and deal with it appropriately if so.
860 : : *
861 : : * See also g_task_report_new_error().
862 : : *
863 : : * Since: 2.36
864 : : */
865 : : void
866 : 11 : g_task_report_error (gpointer source_object,
867 : : GAsyncReadyCallback callback,
868 : : gpointer callback_data,
869 : : gpointer source_tag,
870 : : GError *error)
871 : : {
872 : : GTask *task;
873 : :
874 : 11 : task = g_task_new (source_object, NULL, callback, callback_data);
875 : 11 : g_task_set_source_tag (task, source_tag);
876 : 11 : g_task_set_static_name (task, G_STRFUNC);
877 : 11 : g_task_return_error (task, error);
878 : 11 : g_object_unref (task);
879 : 11 : }
880 : :
881 : : /**
882 : : * g_task_report_new_error:
883 : : * @source_object: (nullable) (type GObject): the #GObject that owns
884 : : * this task, or %NULL.
885 : : * @callback: (scope async) (closure callback_data): a #GAsyncReadyCallback.
886 : : * @callback_data: user data passed to @callback.
887 : : * @source_tag: an opaque pointer indicating the source of this task
888 : : * @domain: a #GQuark.
889 : : * @code: an error code.
890 : : * @format: a string with format characters.
891 : : * @...: a list of values to insert into @format.
892 : : *
893 : : * Creates a #GTask and then immediately calls
894 : : * g_task_return_new_error() on it. Use this in the wrapper function
895 : : * of an asynchronous method when you want to avoid even calling the
896 : : * virtual method. You can then use g_async_result_is_tagged() in the
897 : : * finish method wrapper to check if the result there is tagged as
898 : : * having been created by the wrapper method, and deal with it
899 : : * appropriately if so.
900 : : *
901 : : * See also g_task_report_error().
902 : : *
903 : : * Since: 2.36
904 : : */
905 : : void
906 : 3 : g_task_report_new_error (gpointer source_object,
907 : : GAsyncReadyCallback callback,
908 : : gpointer callback_data,
909 : : gpointer source_tag,
910 : : GQuark domain,
911 : : gint code,
912 : : const char *format,
913 : : ...)
914 : : {
915 : : GError *error;
916 : : va_list ap;
917 : :
918 : 3 : va_start (ap, format);
919 : 3 : error = g_error_new_valist (domain, code, format, ap);
920 : 3 : va_end (ap);
921 : :
922 : 3 : g_task_report_error (source_object, callback, callback_data,
923 : : source_tag, error);
924 : 3 : }
925 : :
926 : : /**
927 : : * g_task_set_task_data:
928 : : * @task: the #GTask
929 : : * @task_data: (nullable): task-specific data
930 : : * @task_data_destroy: (nullable): #GDestroyNotify for @task_data
931 : : *
932 : : * Sets @task's task data (freeing the existing task data, if any).
933 : : *
934 : : * Since: 2.36
935 : : */
936 : : void
937 : 96584 : g_task_set_task_data (GTask *task,
938 : : gpointer task_data,
939 : : GDestroyNotify task_data_destroy)
940 : : {
941 : 96584 : g_return_if_fail (G_IS_TASK (task));
942 : :
943 : 96584 : if (task->task_data_destroy)
944 : 1 : task->task_data_destroy (task->task_data);
945 : :
946 : 96584 : task->task_data = task_data;
947 : 96584 : task->task_data_destroy = task_data_destroy;
948 : :
949 : 96584 : TRACE (GIO_TASK_SET_TASK_DATA (task, task_data, task_data_destroy));
950 : : }
951 : :
952 : : /**
953 : : * g_task_set_priority:
954 : : * @task: the #GTask
955 : : * @priority: the [priority](iface.AsyncResult.html#io-priority) of the request
956 : : *
957 : : * Sets @task's priority. If you do not call this, it will default to
958 : : * %G_PRIORITY_DEFAULT.
959 : : *
960 : : * This will affect the priority of #GSources created with
961 : : * g_task_attach_source() and the scheduling of tasks run in threads,
962 : : * and can also be explicitly retrieved later via
963 : : * g_task_get_priority().
964 : : *
965 : : * Since: 2.36
966 : : */
967 : : void
968 : 33607 : g_task_set_priority (GTask *task,
969 : : gint priority)
970 : : {
971 : 33607 : g_return_if_fail (G_IS_TASK (task));
972 : :
973 : 33607 : task->priority = priority;
974 : :
975 : 33607 : TRACE (GIO_TASK_SET_PRIORITY (task, priority));
976 : : }
977 : :
978 : : /**
979 : : * g_task_set_check_cancellable:
980 : : * @task: the #GTask
981 : : * @check_cancellable: whether #GTask will check the state of
982 : : * its #GCancellable for you.
983 : : *
984 : : * Sets or clears @task's check-cancellable flag. If this is %TRUE
985 : : * (the default), then g_task_propagate_pointer(), etc, and
986 : : * g_task_had_error() will check the task's #GCancellable first, and
987 : : * if it has been cancelled, then they will consider the task to have
988 : : * returned an "Operation was cancelled" error
989 : : * (%G_IO_ERROR_CANCELLED), regardless of any other error or return
990 : : * value the task may have had.
991 : : *
992 : : * If @check_cancellable is %FALSE, then the #GTask will not check the
993 : : * cancellable itself, and it is up to @task's owner to do this (eg,
994 : : * via g_task_return_error_if_cancelled()).
995 : : *
996 : : * If you are using g_task_set_return_on_cancel() as well, then
997 : : * you must leave check-cancellable set %TRUE.
998 : : *
999 : : * Since: 2.36
1000 : : */
1001 : : void
1002 : 15717 : g_task_set_check_cancellable (GTask *task,
1003 : : gboolean check_cancellable)
1004 : : {
1005 : 15717 : g_return_if_fail (G_IS_TASK (task));
1006 : 15717 : g_return_if_fail (check_cancellable || !task->return_on_cancel);
1007 : :
1008 : 15717 : task->check_cancellable = check_cancellable;
1009 : : }
1010 : :
1011 : : static void g_task_thread_complete (GTask *task);
1012 : :
1013 : : /**
1014 : : * g_task_set_return_on_cancel:
1015 : : * @task: the #GTask
1016 : : * @return_on_cancel: whether the task returns automatically when
1017 : : * it is cancelled.
1018 : : *
1019 : : * Sets or clears @task's return-on-cancel flag. This is only
1020 : : * meaningful for tasks run via g_task_run_in_thread() or
1021 : : * g_task_run_in_thread_sync().
1022 : : *
1023 : : * If @return_on_cancel is %TRUE, then cancelling @task's
1024 : : * #GCancellable will immediately cause it to return, as though the
1025 : : * task's #GTaskThreadFunc had called
1026 : : * g_task_return_error_if_cancelled() and then returned.
1027 : : *
1028 : : * This allows you to create a cancellable wrapper around an
1029 : : * uninterruptible function. The #GTaskThreadFunc just needs to be
1030 : : * careful that it does not modify any externally-visible state after
1031 : : * it has been cancelled. To do that, the thread should call
1032 : : * g_task_set_return_on_cancel() again to (atomically) set
1033 : : * return-on-cancel %FALSE before making externally-visible changes;
1034 : : * if the task gets cancelled before the return-on-cancel flag could
1035 : : * be changed, g_task_set_return_on_cancel() will indicate this by
1036 : : * returning %FALSE.
1037 : : *
1038 : : * You can disable and re-enable this flag multiple times if you wish.
1039 : : * If the task's #GCancellable is cancelled while return-on-cancel is
1040 : : * %FALSE, then calling g_task_set_return_on_cancel() to set it %TRUE
1041 : : * again will cause the task to be cancelled at that point.
1042 : : *
1043 : : * If the task's #GCancellable is already cancelled before you call
1044 : : * g_task_run_in_thread()/g_task_run_in_thread_sync(), then the
1045 : : * #GTaskThreadFunc will still be run (for consistency), but the task
1046 : : * will also be completed right away.
1047 : : *
1048 : : * Returns: %TRUE if @task's return-on-cancel flag was changed to
1049 : : * match @return_on_cancel. %FALSE if @task has already been
1050 : : * cancelled.
1051 : : *
1052 : : * Since: 2.36
1053 : : */
1054 : : gboolean
1055 : 16 : g_task_set_return_on_cancel (GTask *task,
1056 : : gboolean return_on_cancel)
1057 : : {
1058 : 16 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
1059 : 16 : g_return_val_if_fail (task->check_cancellable || !return_on_cancel, FALSE);
1060 : :
1061 : 16 : if (!G_TASK_IS_THREADED (task))
1062 : : {
1063 : 6 : task->return_on_cancel = return_on_cancel;
1064 : 6 : return TRUE;
1065 : : }
1066 : :
1067 : 10 : g_mutex_lock (&task->lock);
1068 : 10 : if (task->thread_cancelled)
1069 : : {
1070 : 6 : if (return_on_cancel && !task->return_on_cancel)
1071 : : {
1072 : 2 : g_mutex_unlock (&task->lock);
1073 : 2 : g_task_thread_complete (task);
1074 : : }
1075 : : else
1076 : 4 : g_mutex_unlock (&task->lock);
1077 : 6 : return FALSE;
1078 : : }
1079 : 4 : task->return_on_cancel = return_on_cancel;
1080 : 4 : g_mutex_unlock (&task->lock);
1081 : :
1082 : 4 : return TRUE;
1083 : : }
1084 : :
1085 : : /**
1086 : : * g_task_set_source_tag:
1087 : : * @task: the #GTask
1088 : : * @source_tag: an opaque pointer indicating the source of this task
1089 : : *
1090 : : * Sets @task's source tag.
1091 : : *
1092 : : * You can use this to tag a task return
1093 : : * value with a particular pointer (usually a pointer to the function
1094 : : * doing the tagging) and then later check it using
1095 : : * g_task_get_source_tag() (or g_async_result_is_tagged()) in the
1096 : : * task's "finish" function, to figure out if the response came from a
1097 : : * particular place.
1098 : : *
1099 : : * A macro wrapper around this function will automatically set the
1100 : : * task’s name to the string form of @source_tag if it’s not already
1101 : : * set, for convenience.
1102 : : *
1103 : : * Since: 2.36
1104 : : */
1105 : : void
1106 : 117179 : (g_task_set_source_tag) (GTask *task,
1107 : : gpointer source_tag)
1108 : : {
1109 : 117179 : g_return_if_fail (G_IS_TASK (task));
1110 : :
1111 : 117179 : task->source_tag = source_tag;
1112 : :
1113 : 117179 : TRACE (GIO_TASK_SET_SOURCE_TAG (task, source_tag));
1114 : : }
1115 : :
1116 : : /**
1117 : : * g_task_set_name:
1118 : : * @task: a #GTask
1119 : : * @name: (nullable): a human readable name for the task, or %NULL to unset it
1120 : : *
1121 : : * Sets @task’s name, used in debugging and profiling. The name defaults to
1122 : : * %NULL.
1123 : : *
1124 : : * The task name should describe in a human readable way what the task does.
1125 : : * For example, ‘Open file’ or ‘Connect to network host’. It is used to set the
1126 : : * name of the #GSource used for idle completion of the task.
1127 : : *
1128 : : * This function may only be called before the @task is first used in a thread
1129 : : * other than the one it was constructed in.
1130 : : *
1131 : : * Since: 2.60
1132 : : */
1133 : : void
1134 : 26 : (g_task_set_name) (GTask *task,
1135 : : const char *name)
1136 : : {
1137 : : char *new_name;
1138 : :
1139 : 26 : g_return_if_fail (G_IS_TASK (task));
1140 : :
1141 : 26 : new_name = g_strdup (name);
1142 : 26 : if (!task->name_is_static)
1143 : 26 : g_free (task->name);
1144 : 26 : task->name = g_steal_pointer (&new_name);
1145 : 26 : task->name_is_static = FALSE;
1146 : : }
1147 : :
1148 : : /**
1149 : : * g_task_set_static_name:
1150 : : * @task: a #GTask
1151 : : * @name: (nullable): a human readable name for the task. Must be a string literal
1152 : : *
1153 : : * Sets @task’s name, used in debugging and profiling.
1154 : : *
1155 : : * This is a variant of g_task_set_name() that avoids copying @name.
1156 : : *
1157 : : * This function is called automatically by [method@Gio.Task.set_source_tag]
1158 : : * unless a name is set.
1159 : : *
1160 : : * Since: 2.76
1161 : : */
1162 : : void
1163 : 188977 : g_task_set_static_name (GTask *task,
1164 : : const char *name)
1165 : : {
1166 : 188977 : g_return_if_fail (G_IS_TASK (task));
1167 : :
1168 : 188977 : if (!task->name_is_static)
1169 : 117191 : g_free (task->name);
1170 : 188977 : task->name = (char *) name;
1171 : 188977 : task->name_is_static = TRUE;
1172 : : }
1173 : :
1174 : : /**
1175 : : * g_task_get_source_object:
1176 : : * @task: a #GTask
1177 : : *
1178 : : * Gets the source object from @task. Like
1179 : : * g_async_result_get_source_object(), but does not ref the object.
1180 : : *
1181 : : * Returns: (transfer none) (nullable) (type GObject): @task's source object, or %NULL
1182 : : *
1183 : : * Since: 2.36
1184 : : */
1185 : : gpointer
1186 : 7587 : g_task_get_source_object (GTask *task)
1187 : : {
1188 : 7587 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1189 : :
1190 : 7587 : return task->source_object;
1191 : : }
1192 : :
1193 : : static GObject *
1194 : 427 : g_task_ref_source_object (GAsyncResult *res)
1195 : : {
1196 : 427 : GTask *task = G_TASK (res);
1197 : :
1198 : 427 : if (task->source_object)
1199 : 427 : return g_object_ref (task->source_object);
1200 : : else
1201 : 0 : return NULL;
1202 : : }
1203 : :
1204 : : /**
1205 : : * g_task_get_task_data:
1206 : : * @task: a #GTask
1207 : : *
1208 : : * Gets @task's `task_data`.
1209 : : *
1210 : : * Returns: (transfer none): @task's `task_data`.
1211 : : *
1212 : : * Since: 2.36
1213 : : */
1214 : : gpointer
1215 : 111798 : g_task_get_task_data (GTask *task)
1216 : : {
1217 : 111798 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1218 : :
1219 : 111798 : return task->task_data;
1220 : : }
1221 : :
1222 : : /**
1223 : : * g_task_get_priority:
1224 : : * @task: a #GTask
1225 : : *
1226 : : * Gets @task's priority
1227 : : *
1228 : : * Returns: @task's priority
1229 : : *
1230 : : * Since: 2.36
1231 : : */
1232 : : gint
1233 : 942 : g_task_get_priority (GTask *task)
1234 : : {
1235 : 942 : g_return_val_if_fail (G_IS_TASK (task), G_PRIORITY_DEFAULT);
1236 : :
1237 : 942 : return task->priority;
1238 : : }
1239 : :
1240 : : /**
1241 : : * g_task_get_context:
1242 : : * @task: a #GTask
1243 : : *
1244 : : * Gets the #GMainContext that @task will return its result in (that
1245 : : * is, the context that was the
1246 : : * [thread-default main context][g-main-context-push-thread-default]
1247 : : * at the point when @task was created).
1248 : : *
1249 : : * This will always return a non-%NULL value, even if the task's
1250 : : * context is the default #GMainContext.
1251 : : *
1252 : : * Returns: (transfer none): @task's #GMainContext
1253 : : *
1254 : : * Since: 2.36
1255 : : */
1256 : : GMainContext *
1257 : 29 : g_task_get_context (GTask *task)
1258 : : {
1259 : 29 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1260 : :
1261 : 29 : return task->context;
1262 : : }
1263 : :
1264 : : /**
1265 : : * g_task_get_cancellable:
1266 : : * @task: a #GTask
1267 : : *
1268 : : * Gets @task's #GCancellable
1269 : : *
1270 : : * Returns: (nullable) (transfer none): @task's #GCancellable
1271 : : *
1272 : : * Since: 2.36
1273 : : */
1274 : : GCancellable *
1275 : 145056 : g_task_get_cancellable (GTask *task)
1276 : : {
1277 : 145056 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1278 : :
1279 : 145056 : return task->cancellable;
1280 : : }
1281 : :
1282 : : /**
1283 : : * g_task_get_check_cancellable:
1284 : : * @task: the #GTask
1285 : : *
1286 : : * Gets @task's check-cancellable flag. See
1287 : : * g_task_set_check_cancellable() for more details.
1288 : : *
1289 : : * Since: 2.36
1290 : : */
1291 : : gboolean
1292 : 26 : g_task_get_check_cancellable (GTask *task)
1293 : : {
1294 : 26 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
1295 : :
1296 : : /* Convert from a bit field to a boolean. */
1297 : 26 : return task->check_cancellable ? TRUE : FALSE;
1298 : : }
1299 : :
1300 : : /**
1301 : : * g_task_get_return_on_cancel:
1302 : : * @task: the #GTask
1303 : : *
1304 : : * Gets @task's return-on-cancel flag. See
1305 : : * g_task_set_return_on_cancel() for more details.
1306 : : *
1307 : : * Since: 2.36
1308 : : */
1309 : : gboolean
1310 : 9 : g_task_get_return_on_cancel (GTask *task)
1311 : : {
1312 : 9 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
1313 : :
1314 : : /* Convert from a bit field to a boolean. */
1315 : 9 : return task->return_on_cancel ? TRUE : FALSE;
1316 : : }
1317 : :
1318 : : /**
1319 : : * g_task_get_source_tag:
1320 : : * @task: a #GTask
1321 : : *
1322 : : * Gets @task's source tag. See g_task_set_source_tag().
1323 : : *
1324 : : * Returns: (transfer none): @task's source tag
1325 : : *
1326 : : * Since: 2.36
1327 : : */
1328 : : gpointer
1329 : 45 : g_task_get_source_tag (GTask *task)
1330 : : {
1331 : 45 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1332 : :
1333 : 45 : return task->source_tag;
1334 : : }
1335 : :
1336 : : /**
1337 : : * g_task_get_name:
1338 : : * @task: a #GTask
1339 : : *
1340 : : * Gets @task’s name. See g_task_set_name().
1341 : : *
1342 : : * Returns: (nullable) (transfer none): @task’s name, or %NULL
1343 : : * Since: 2.60
1344 : : */
1345 : : const gchar *
1346 : 117242 : g_task_get_name (GTask *task)
1347 : : {
1348 : 117242 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1349 : :
1350 : 117242 : return task->name;
1351 : : }
1352 : :
1353 : : static void
1354 : 127218 : g_task_return_now (GTask *task)
1355 : : {
1356 : 127218 : TRACE (GIO_TASK_BEFORE_RETURN (task, task->source_object, task->callback,
1357 : : task->callback_data));
1358 : :
1359 : 127218 : g_main_context_push_thread_default (task->context);
1360 : :
1361 : 127218 : if (task->callback != NULL)
1362 : : {
1363 : 126146 : task->callback (task->source_object,
1364 : 126146 : G_ASYNC_RESULT (task),
1365 : : task->callback_data);
1366 : : }
1367 : :
1368 : 127218 : task->completed = TRUE;
1369 : 127218 : g_object_notify (G_OBJECT (task), "completed");
1370 : :
1371 : 127218 : g_main_context_pop_thread_default (task->context);
1372 : 127218 : }
1373 : :
1374 : : static gboolean
1375 : 91634 : complete_in_idle_cb (gpointer task)
1376 : : {
1377 : 91634 : g_task_return_now (task);
1378 : 91634 : g_object_unref (task);
1379 : 91634 : return FALSE;
1380 : : }
1381 : :
1382 : : typedef enum {
1383 : : G_TASK_RETURN_SUCCESS,
1384 : : G_TASK_RETURN_ERROR,
1385 : : G_TASK_RETURN_FROM_THREAD
1386 : : } GTaskReturnType;
1387 : :
1388 : : static void
1389 : 130757 : g_task_return (GTask *task,
1390 : : GTaskReturnType type)
1391 : : {
1392 : : GSource *source;
1393 : :
1394 : 130757 : if (type != G_TASK_RETURN_FROM_THREAD)
1395 : 127254 : task->ever_returned = TRUE;
1396 : :
1397 : 130757 : if (type == G_TASK_RETURN_SUCCESS)
1398 : 123073 : task->result_set = TRUE;
1399 : :
1400 : 130757 : if (task->synchronous)
1401 : 4 : return;
1402 : :
1403 : : /* Normally we want to invoke the task's callback when its return
1404 : : * value is set. But if the task is running in a thread, then we
1405 : : * want to wait until after the task_func returns, to simplify
1406 : : * locking/refcounting/etc.
1407 : : */
1408 : 130753 : if (G_TASK_IS_THREADED (task) && type != G_TASK_RETURN_FROM_THREAD)
1409 : 3501 : return;
1410 : :
1411 : 127252 : g_object_ref (task);
1412 : :
1413 : : /* See if we can complete the task immediately. First, we have to be
1414 : : * running inside the task's thread/GMainContext.
1415 : : */
1416 : 127252 : source = g_main_current_source ();
1417 : 127252 : if (source && g_source_get_context (source) == task->context)
1418 : : {
1419 : : /* Second, we can only complete immediately if this is not the
1420 : : * same iteration of the main loop that the task was created in.
1421 : : */
1422 : 117111 : if (g_source_get_time (source) > task->creation_time)
1423 : : {
1424 : : /* Finally, if the task has been cancelled, we shouldn't
1425 : : * return synchronously from inside the
1426 : : * GCancellable::cancelled handler. It's easier to run
1427 : : * another iteration of the main loop than tracking how the
1428 : : * cancellation was handled.
1429 : : */
1430 : 37582 : if (!g_cancellable_is_cancelled (task->cancellable))
1431 : : {
1432 : 35584 : g_task_return_now (task);
1433 : 35584 : g_object_unref (task);
1434 : 35584 : return;
1435 : : }
1436 : : }
1437 : : }
1438 : :
1439 : : /* Otherwise, complete in the next iteration */
1440 : 91668 : source = g_idle_source_new ();
1441 : :
1442 : : /* Note: in case the task name is NULL we set it as a const string instead
1443 : : * of going through the concat path which is more expensive and may show in the
1444 : : * profiler if g_task_return is called very often
1445 : : */
1446 : 91668 : if (task->name == NULL)
1447 : 10043 : g_source_set_static_name (source, "[gio] (unnamed) complete_in_idle_cb");
1448 : : else
1449 : : {
1450 : : gchar *source_name;
1451 : :
1452 : 81625 : source_name = g_strconcat ("[gio] ", task->name, " complete_in_idle_cb", NULL);
1453 : 81625 : g_source_set_name (source, source_name);
1454 : 81625 : g_free (source_name);
1455 : : }
1456 : :
1457 : 91668 : g_task_attach_source (task, source, complete_in_idle_cb);
1458 : 91667 : g_source_unref (source);
1459 : : }
1460 : :
1461 : :
1462 : : /**
1463 : : * GTaskThreadFunc:
1464 : : * @task: the #GTask
1465 : : * @source_object: (type GObject): @task's source object
1466 : : * @task_data: @task's task data
1467 : : * @cancellable: @task's #GCancellable, or %NULL
1468 : : *
1469 : : * The prototype for a task function to be run in a thread via
1470 : : * g_task_run_in_thread() or g_task_run_in_thread_sync().
1471 : : *
1472 : : * If the return-on-cancel flag is set on @task, and @cancellable gets
1473 : : * cancelled, then the #GTask will be completed immediately (as though
1474 : : * g_task_return_error_if_cancelled() had been called), without
1475 : : * waiting for the task function to complete. However, the task
1476 : : * function will continue running in its thread in the background. The
1477 : : * function therefore needs to be careful about how it uses
1478 : : * externally-visible state in this case. See
1479 : : * g_task_set_return_on_cancel() for more details.
1480 : : *
1481 : : * Other than in that case, @task will be completed when the
1482 : : * #GTaskThreadFunc returns, not when it calls a
1483 : : * `g_task_return_` function.
1484 : : *
1485 : : * Since: 2.36
1486 : : */
1487 : :
1488 : : static void task_thread_cancelled (GCancellable *cancellable,
1489 : : gpointer user_data);
1490 : :
1491 : : static void
1492 : 3513 : g_task_thread_complete (GTask *task)
1493 : : {
1494 : 3513 : g_mutex_lock (&task->lock);
1495 : 3513 : if (task->thread_complete)
1496 : : {
1497 : : /* The task belatedly completed after having been cancelled
1498 : : * (or was cancelled in the midst of being completed).
1499 : : */
1500 : 6 : g_mutex_unlock (&task->lock);
1501 : 6 : return;
1502 : : }
1503 : :
1504 : 3507 : TRACE (GIO_TASK_AFTER_RUN_IN_THREAD (task, task->thread_cancelled));
1505 : :
1506 : 3507 : task->thread_complete = TRUE;
1507 : 3507 : g_mutex_unlock (&task->lock);
1508 : :
1509 : 3507 : if (task->cancellable)
1510 : 1362 : g_signal_handlers_disconnect_by_func (task->cancellable, task_thread_cancelled, task);
1511 : :
1512 : 3507 : if (task->synchronous)
1513 : 5 : g_cond_signal (&task->cond);
1514 : : else
1515 : 3502 : g_task_return (task, G_TASK_RETURN_FROM_THREAD);
1516 : : }
1517 : :
1518 : : static gboolean
1519 : 6 : task_pool_manager_timeout (gpointer user_data)
1520 : : {
1521 : 6 : g_mutex_lock (&task_pool_mutex);
1522 : 6 : g_thread_pool_set_max_threads (task_pool, tasks_running + 1, NULL);
1523 : 6 : g_trace_set_int64_counter (task_pool_max_counter, tasks_running + 1);
1524 : 6 : g_source_set_ready_time (task_pool_manager, -1);
1525 : 6 : g_mutex_unlock (&task_pool_mutex);
1526 : :
1527 : 6 : return TRUE;
1528 : : }
1529 : :
1530 : : static void
1531 : 3509 : g_task_thread_setup (void)
1532 : : {
1533 : 3509 : g_private_set (&task_private, GUINT_TO_POINTER (TRUE));
1534 : 3509 : g_mutex_lock (&task_pool_mutex);
1535 : 3509 : tasks_running++;
1536 : :
1537 : 3509 : g_trace_set_int64_counter (tasks_running_counter, tasks_running);
1538 : :
1539 : 3509 : if (tasks_running == G_TASK_POOL_SIZE)
1540 : 1012 : task_wait_time = G_TASK_WAIT_TIME_BASE;
1541 : 2497 : else if (tasks_running > G_TASK_POOL_SIZE && tasks_running < G_TASK_WAIT_TIME_MAX_POOL_SIZE)
1542 : 6 : task_wait_time = (guint64) (task_wait_time * G_TASK_WAIT_TIME_MULTIPLIER);
1543 : :
1544 : 3509 : if (tasks_running >= G_TASK_POOL_SIZE)
1545 : 1018 : g_source_set_ready_time (task_pool_manager, g_get_monotonic_time () + task_wait_time);
1546 : :
1547 : 3509 : g_mutex_unlock (&task_pool_mutex);
1548 : 3509 : }
1549 : :
1550 : : static void
1551 : 3508 : g_task_thread_cleanup (void)
1552 : : {
1553 : : gint tasks_pending;
1554 : :
1555 : 3508 : g_mutex_lock (&task_pool_mutex);
1556 : 3508 : tasks_pending = g_thread_pool_unprocessed (task_pool);
1557 : :
1558 : 3508 : if (tasks_running > G_TASK_POOL_SIZE)
1559 : : {
1560 : 6 : g_thread_pool_set_max_threads (task_pool, tasks_running - 1, NULL);
1561 : 6 : g_trace_set_int64_counter (task_pool_max_counter, tasks_running - 1);
1562 : : }
1563 : 3502 : else if (tasks_running + tasks_pending < G_TASK_POOL_SIZE)
1564 : 2484 : g_source_set_ready_time (task_pool_manager, -1);
1565 : :
1566 : 3508 : if (tasks_running > G_TASK_POOL_SIZE && tasks_running < G_TASK_WAIT_TIME_MAX_POOL_SIZE)
1567 : 6 : task_wait_time = (guint64) (task_wait_time / G_TASK_WAIT_TIME_MULTIPLIER);
1568 : :
1569 : 3508 : tasks_running--;
1570 : :
1571 : 3508 : g_trace_set_int64_counter (tasks_running_counter, tasks_running);
1572 : :
1573 : 3508 : g_mutex_unlock (&task_pool_mutex);
1574 : 3508 : g_private_set (&task_private, GUINT_TO_POINTER (FALSE));
1575 : 3508 : }
1576 : :
1577 : : static void
1578 : 3509 : g_task_thread_pool_thread (gpointer thread_data,
1579 : : gpointer pool_data)
1580 : : {
1581 : 3509 : GTask *task = thread_data;
1582 : :
1583 : 3509 : g_task_thread_setup ();
1584 : :
1585 : 3509 : task->task_func (task, task->source_object, task->task_data,
1586 : : task->cancellable);
1587 : 3509 : g_task_thread_complete (task);
1588 : 3508 : g_object_unref (task);
1589 : :
1590 : 3508 : g_task_thread_cleanup ();
1591 : 3508 : }
1592 : :
1593 : : static void
1594 : 1037 : task_thread_cancelled (GCancellable *cancellable,
1595 : : gpointer user_data)
1596 : : {
1597 : 1037 : GTask *task = user_data;
1598 : :
1599 : : /* Move this task to the front of the queue - no need for
1600 : : * a complete resorting of the queue.
1601 : : */
1602 : 1037 : g_thread_pool_move_to_front (task_pool, task);
1603 : :
1604 : 1037 : g_mutex_lock (&task->lock);
1605 : 1037 : task->thread_cancelled = TRUE;
1606 : :
1607 : 1037 : if (!task->return_on_cancel)
1608 : : {
1609 : 1035 : g_mutex_unlock (&task->lock);
1610 : 1035 : return;
1611 : : }
1612 : :
1613 : : /* We don't actually set task->error; g_task_return_error() doesn't
1614 : : * use a lock, and g_task_propagate_error() will call
1615 : : * g_cancellable_set_error_if_cancelled() anyway.
1616 : : */
1617 : 2 : g_mutex_unlock (&task->lock);
1618 : 2 : g_task_thread_complete (task);
1619 : : }
1620 : :
1621 : : static void
1622 : 1362 : task_thread_cancelled_disconnect_notify (gpointer task,
1623 : : GClosure *closure)
1624 : : {
1625 : 1362 : g_object_unref (task);
1626 : 1362 : }
1627 : :
1628 : : static void
1629 : 3509 : g_task_start_task_thread (GTask *task,
1630 : : GTaskThreadFunc task_func)
1631 : : {
1632 : 3509 : g_mutex_init (&task->lock);
1633 : 3509 : g_cond_init (&task->cond);
1634 : :
1635 : 3509 : g_mutex_lock (&task->lock);
1636 : :
1637 : 3509 : TRACE (GIO_TASK_BEFORE_RUN_IN_THREAD (task, task_func));
1638 : :
1639 : 3509 : task->task_func = task_func;
1640 : :
1641 : 3509 : if (task->cancellable)
1642 : : {
1643 : 1370 : if (task->return_on_cancel &&
1644 : 6 : g_cancellable_set_error_if_cancelled (task->cancellable,
1645 : : &task->error))
1646 : : {
1647 : 2 : task->thread_cancelled = task->thread_complete = TRUE;
1648 : 2 : TRACE (GIO_TASK_AFTER_RUN_IN_THREAD (task, task->thread_cancelled));
1649 : 2 : g_thread_pool_push (task_pool, g_object_ref (task), NULL);
1650 : 2 : return;
1651 : : }
1652 : :
1653 : : /* This introduces a reference count loop between the GTask and
1654 : : * GCancellable, but is necessary to avoid a race on finalising the GTask
1655 : : * between task_thread_cancelled() (in one thread) and
1656 : : * g_task_thread_complete() (in another).
1657 : : *
1658 : : * Accordingly, the signal handler *must* be removed once the task has
1659 : : * completed.
1660 : : */
1661 : 1362 : g_signal_connect_data (task->cancellable, "cancelled",
1662 : : G_CALLBACK (task_thread_cancelled),
1663 : : g_object_ref (task),
1664 : : task_thread_cancelled_disconnect_notify,
1665 : : G_CONNECT_DEFAULT);
1666 : : }
1667 : :
1668 : 3507 : if (g_private_get (&task_private))
1669 : 2 : task->blocking_other_task = TRUE;
1670 : 3507 : g_thread_pool_push (task_pool, g_object_ref (task), NULL);
1671 : : }
1672 : :
1673 : : /**
1674 : : * g_task_run_in_thread:
1675 : : * @task: a #GTask
1676 : : * @task_func: (scope async): a #GTaskThreadFunc
1677 : : *
1678 : : * Runs @task_func in another thread. When @task_func returns, @task's
1679 : : * #GAsyncReadyCallback will be invoked in @task's #GMainContext.
1680 : : *
1681 : : * This takes a ref on @task until the task completes.
1682 : : *
1683 : : * See #GTaskThreadFunc for more details about how @task_func is handled.
1684 : : *
1685 : : * Although GLib currently rate-limits the tasks queued via
1686 : : * g_task_run_in_thread(), you should not assume that it will always
1687 : : * do this. If you have a very large number of tasks to run (several tens of
1688 : : * tasks), but don't want them to all run at once, you should only queue a
1689 : : * limited number of them (around ten) at a time.
1690 : : *
1691 : : * Be aware that if your task depends on other tasks to complete, use of this
1692 : : * function could lead to a livelock if the other tasks also use this function
1693 : : * and enough of them (around 10) execute in a dependency chain, as that will
1694 : : * exhaust the thread pool. If this situation is possible, consider using a
1695 : : * separate worker thread or thread pool explicitly, rather than using
1696 : : * g_task_run_in_thread().
1697 : : *
1698 : : * Since: 2.36
1699 : : */
1700 : : void
1701 : 3503 : g_task_run_in_thread (GTask *task,
1702 : : GTaskThreadFunc task_func)
1703 : : {
1704 : 3503 : g_return_if_fail (G_IS_TASK (task));
1705 : :
1706 : 3503 : g_object_ref (task);
1707 : 3503 : g_task_start_task_thread (task, task_func);
1708 : :
1709 : : /* The task may already be cancelled, or g_thread_pool_push() may
1710 : : * have failed.
1711 : : */
1712 : 3503 : if (task->thread_complete)
1713 : : {
1714 : 1 : g_mutex_unlock (&task->lock);
1715 : 1 : g_task_return (task, G_TASK_RETURN_FROM_THREAD);
1716 : : }
1717 : : else
1718 : 3502 : g_mutex_unlock (&task->lock);
1719 : :
1720 : 3503 : g_object_unref (task);
1721 : : }
1722 : :
1723 : : /**
1724 : : * g_task_run_in_thread_sync:
1725 : : * @task: a #GTask
1726 : : * @task_func: (scope async): a #GTaskThreadFunc
1727 : : *
1728 : : * Runs @task_func in another thread, and waits for it to return or be
1729 : : * cancelled. You can use g_task_propagate_pointer(), etc, afterward
1730 : : * to get the result of @task_func.
1731 : : *
1732 : : * See #GTaskThreadFunc for more details about how @task_func is handled.
1733 : : *
1734 : : * Normally this is used with tasks created with a %NULL
1735 : : * `callback`, but note that even if the task does
1736 : : * have a callback, it will not be invoked when @task_func returns.
1737 : : * #GTask:completed will be set to %TRUE just before this function returns.
1738 : : *
1739 : : * Although GLib currently rate-limits the tasks queued via
1740 : : * g_task_run_in_thread_sync(), you should not assume that it will
1741 : : * always do this. If you have a very large number of tasks to run,
1742 : : * but don't want them to all run at once, you should only queue a
1743 : : * limited number of them at a time.
1744 : : *
1745 : : * Since: 2.36
1746 : : */
1747 : : void
1748 : 6 : g_task_run_in_thread_sync (GTask *task,
1749 : : GTaskThreadFunc task_func)
1750 : : {
1751 : 6 : g_return_if_fail (G_IS_TASK (task));
1752 : :
1753 : 6 : g_object_ref (task);
1754 : :
1755 : 6 : task->synchronous = TRUE;
1756 : 6 : g_task_start_task_thread (task, task_func);
1757 : :
1758 : 11 : while (!task->thread_complete)
1759 : 5 : g_cond_wait (&task->cond, &task->lock);
1760 : :
1761 : 6 : g_mutex_unlock (&task->lock);
1762 : :
1763 : 6 : TRACE (GIO_TASK_BEFORE_RETURN (task, task->source_object,
1764 : : NULL /* callback */,
1765 : : NULL /* callback data */));
1766 : :
1767 : : /* Notify of completion in this thread. */
1768 : 6 : task->completed = TRUE;
1769 : 6 : g_object_notify (G_OBJECT (task), "completed");
1770 : :
1771 : 6 : g_object_unref (task);
1772 : : }
1773 : :
1774 : : /**
1775 : : * g_task_attach_source:
1776 : : * @task: a #GTask
1777 : : * @source: the source to attach
1778 : : * @callback: the callback to invoke when @source triggers
1779 : : *
1780 : : * A utility function for dealing with async operations where you need
1781 : : * to wait for a #GSource to trigger. Attaches @source to @task's
1782 : : * #GMainContext with @task's [priority](iface.AsyncResult.html#io-priority),
1783 : : * and sets @source's callback to @callback, with @task as the callback's
1784 : : * `user_data`.
1785 : : *
1786 : : * It will set the @source’s name to the task’s name (as set with
1787 : : * g_task_set_name()), if one has been set on the task and the source doesn’t
1788 : : * yet have a name.
1789 : : *
1790 : : * This takes a reference on @task until @source is destroyed.
1791 : : *
1792 : : * Since: 2.36
1793 : : */
1794 : : void
1795 : 113467 : g_task_attach_source (GTask *task,
1796 : : GSource *source,
1797 : : GSourceFunc callback)
1798 : : {
1799 : 113467 : g_return_if_fail (G_IS_TASK (task));
1800 : :
1801 : 113467 : g_source_set_callback (source, callback,
1802 : : g_object_ref (task), g_object_unref);
1803 : 113467 : g_source_set_priority (source, task->priority);
1804 : 113467 : if (task->name != NULL && g_source_get_name (source) == NULL)
1805 : 1 : g_source_set_name (source, task->name);
1806 : :
1807 : 113467 : g_source_attach (source, task->context);
1808 : : }
1809 : :
1810 : :
1811 : : static gboolean
1812 : 124276 : g_task_propagate_error (GTask *task,
1813 : : GError **error)
1814 : : {
1815 : : gboolean error_set;
1816 : :
1817 : 232883 : if (task->check_cancellable &&
1818 : 108607 : g_cancellable_set_error_if_cancelled (task->cancellable, error))
1819 : 465 : error_set = TRUE;
1820 : 123811 : else if (task->error)
1821 : : {
1822 : 1172 : g_propagate_error (error, task->error);
1823 : 1172 : task->error = NULL;
1824 : 1172 : task->had_error = TRUE;
1825 : 1172 : error_set = TRUE;
1826 : : }
1827 : : else
1828 : 122639 : error_set = FALSE;
1829 : :
1830 : 124276 : TRACE (GIO_TASK_PROPAGATE (task, error_set));
1831 : :
1832 : 124276 : return error_set;
1833 : : }
1834 : :
1835 : : /**
1836 : : * g_task_return_pointer:
1837 : : * @task: a #GTask
1838 : : * @result: (nullable) (transfer full): the pointer result of a task
1839 : : * function
1840 : : * @result_destroy: (nullable): a #GDestroyNotify function.
1841 : : *
1842 : : * Sets @task's result to @result and completes the task. If @result
1843 : : * is not %NULL, then @result_destroy will be used to free @result if
1844 : : * the caller does not take ownership of it with
1845 : : * g_task_propagate_pointer().
1846 : : *
1847 : : * "Completes the task" means that for an ordinary asynchronous task
1848 : : * it will either invoke the task's callback, or else queue that
1849 : : * callback to be invoked in the proper #GMainContext, or in the next
1850 : : * iteration of the current #GMainContext. For a task run via
1851 : : * g_task_run_in_thread() or g_task_run_in_thread_sync(), calling this
1852 : : * method will save @result to be returned to the caller later, but
1853 : : * the task will not actually be completed until the #GTaskThreadFunc
1854 : : * exits.
1855 : : *
1856 : : * Note that since the task may be completed before returning from
1857 : : * g_task_return_pointer(), you cannot assume that @result is still
1858 : : * valid after calling this, unless you are still holding another
1859 : : * reference on it.
1860 : : *
1861 : : * Since: 2.36
1862 : : */
1863 : : void
1864 : 8465 : g_task_return_pointer (GTask *task,
1865 : : gpointer result,
1866 : : GDestroyNotify result_destroy)
1867 : : {
1868 : 8465 : g_return_if_fail (G_IS_TASK (task));
1869 : 8465 : g_return_if_fail (!task->ever_returned);
1870 : :
1871 : 8465 : task->result.pointer = result;
1872 : 8465 : task->result_destroy = result_destroy;
1873 : :
1874 : 8465 : g_task_return (task, G_TASK_RETURN_SUCCESS);
1875 : : }
1876 : :
1877 : : /**
1878 : : * g_task_propagate_pointer:
1879 : : * @task: a #GTask
1880 : : * @error: return location for a #GError
1881 : : *
1882 : : * Gets the result of @task as a pointer, and transfers ownership
1883 : : * of that value to the caller.
1884 : : *
1885 : : * If the task resulted in an error, or was cancelled, then this will
1886 : : * instead return %NULL and set @error.
1887 : : *
1888 : : * Since this method transfers ownership of the return value (or
1889 : : * error) to the caller, you may only call it once.
1890 : : *
1891 : : * Returns: (transfer full): the task result, or %NULL on error
1892 : : *
1893 : : * Since: 2.36
1894 : : */
1895 : : gpointer
1896 : 9257 : g_task_propagate_pointer (GTask *task,
1897 : : GError **error)
1898 : : {
1899 : 9257 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1900 : :
1901 : 9257 : if (g_task_propagate_error (task, error))
1902 : 804 : return NULL;
1903 : :
1904 : 8453 : g_return_val_if_fail (task->result_set, NULL);
1905 : :
1906 : 8453 : task->result_destroy = NULL;
1907 : 8453 : task->result_set = FALSE;
1908 : 8453 : return task->result.pointer;
1909 : : }
1910 : :
1911 : : /**
1912 : : * g_task_return_int:
1913 : : * @task: a #GTask.
1914 : : * @result: the integer (#gssize) result of a task function.
1915 : : *
1916 : : * Sets @task's result to @result and completes the task (see
1917 : : * g_task_return_pointer() for more discussion of exactly what this
1918 : : * means).
1919 : : *
1920 : : * Since: 2.36
1921 : : */
1922 : : void
1923 : 92566 : g_task_return_int (GTask *task,
1924 : : gssize result)
1925 : : {
1926 : 92566 : g_return_if_fail (G_IS_TASK (task));
1927 : 92566 : g_return_if_fail (!task->ever_returned);
1928 : :
1929 : 92566 : task->result.size = result;
1930 : :
1931 : 92566 : g_task_return (task, G_TASK_RETURN_SUCCESS);
1932 : : }
1933 : :
1934 : : /**
1935 : : * g_task_propagate_int:
1936 : : * @task: a #GTask.
1937 : : * @error: return location for a #GError
1938 : : *
1939 : : * Gets the result of @task as an integer (#gssize).
1940 : : *
1941 : : * If the task resulted in an error, or was cancelled, then this will
1942 : : * instead return -1 and set @error.
1943 : : *
1944 : : * Since this method transfers ownership of the return value (or
1945 : : * error) to the caller, you may only call it once.
1946 : : *
1947 : : * Returns: the task result, or -1 on error
1948 : : *
1949 : : * Since: 2.36
1950 : : */
1951 : : gssize
1952 : 92990 : g_task_propagate_int (GTask *task,
1953 : : GError **error)
1954 : : {
1955 : 92990 : g_return_val_if_fail (G_IS_TASK (task), -1);
1956 : :
1957 : 92990 : if (g_task_propagate_error (task, error))
1958 : 460 : return -1;
1959 : :
1960 : 92530 : g_return_val_if_fail (task->result_set, -1);
1961 : :
1962 : 92530 : task->result_set = FALSE;
1963 : 92530 : return task->result.size;
1964 : : }
1965 : :
1966 : : /**
1967 : : * g_task_return_boolean:
1968 : : * @task: a #GTask.
1969 : : * @result: the #gboolean result of a task function.
1970 : : *
1971 : : * Sets @task's result to @result and completes the task (see
1972 : : * g_task_return_pointer() for more discussion of exactly what this
1973 : : * means).
1974 : : *
1975 : : * Since: 2.36
1976 : : */
1977 : : void
1978 : 22042 : g_task_return_boolean (GTask *task,
1979 : : gboolean result)
1980 : : {
1981 : 22042 : g_return_if_fail (G_IS_TASK (task));
1982 : 22042 : g_return_if_fail (!task->ever_returned);
1983 : :
1984 : 22042 : task->result.boolean = result;
1985 : :
1986 : 22042 : g_task_return (task, G_TASK_RETURN_SUCCESS);
1987 : : }
1988 : :
1989 : : /**
1990 : : * g_task_propagate_boolean:
1991 : : * @task: a #GTask.
1992 : : * @error: return location for a #GError
1993 : : *
1994 : : * Gets the result of @task as a #gboolean.
1995 : : *
1996 : : * If the task resulted in an error, or was cancelled, then this will
1997 : : * instead return %FALSE and set @error.
1998 : : *
1999 : : * Since this method transfers ownership of the return value (or
2000 : : * error) to the caller, you may only call it once.
2001 : : *
2002 : : * Returns: the task result, or %FALSE on error
2003 : : *
2004 : : * Since: 2.36
2005 : : */
2006 : : gboolean
2007 : 22028 : g_task_propagate_boolean (GTask *task,
2008 : : GError **error)
2009 : : {
2010 : 22028 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
2011 : :
2012 : 22028 : if (g_task_propagate_error (task, error))
2013 : 373 : return FALSE;
2014 : :
2015 : 21655 : g_return_val_if_fail (task->result_set, FALSE);
2016 : :
2017 : 21655 : task->result_set = FALSE;
2018 : 21655 : return task->result.boolean;
2019 : : }
2020 : :
2021 : : /**
2022 : : * g_task_return_error:
2023 : : * @task: a #GTask.
2024 : : * @error: (transfer full): the #GError result of a task function.
2025 : : *
2026 : : * Sets @task's result to @error (which @task assumes ownership of)
2027 : : * and completes the task (see g_task_return_pointer() for more
2028 : : * discussion of exactly what this means).
2029 : : *
2030 : : * Note that since the task takes ownership of @error, and since the
2031 : : * task may be completed before returning from g_task_return_error(),
2032 : : * you cannot assume that @error is still valid after calling this.
2033 : : * Call g_error_copy() on the error if you need to keep a local copy
2034 : : * as well.
2035 : : *
2036 : : * See also [method@Gio.Task.return_new_error],
2037 : : * [method@Gio.Task.return_new_error_literal].
2038 : : *
2039 : : * Since: 2.36
2040 : : */
2041 : : void
2042 : 2936 : g_task_return_error (GTask *task,
2043 : : GError *error)
2044 : : {
2045 : 2936 : g_return_if_fail (G_IS_TASK (task));
2046 : 2936 : g_return_if_fail (!task->ever_returned);
2047 : 2936 : g_return_if_fail (error != NULL);
2048 : :
2049 : 2936 : task->error = error;
2050 : :
2051 : 2936 : g_task_return (task, G_TASK_RETURN_ERROR);
2052 : : }
2053 : :
2054 : : /**
2055 : : * g_task_return_prefixed_error:
2056 : : * @task: a #GTask.
2057 : : * @error: (transfer full): the #GError result of a task function.
2058 : : * @format: a string with format characters.
2059 : : * @...: a list of values to insert into @format.
2060 : : *
2061 : : * Sets @task's result to @error (which @task assumes ownership of), with
2062 : : * the message prefixed according to @format, and completes the task
2063 : : * (see g_task_return_pointer() for more discussion of exactly what this
2064 : : * means).
2065 : : *
2066 : : * Note that since the task takes ownership of @error, and since the
2067 : : * task may be completed before returning from g_task_return_prefixed_error(),
2068 : : * you cannot assume that @error is still valid after calling this.
2069 : : * Call g_error_copy() on the error if you need to keep a local copy
2070 : : * as well.
2071 : : *
2072 : : * See also g_task_return_error(), g_prefix_error().
2073 : : *
2074 : : * Since: 2.80
2075 : : */
2076 : : void
2077 : 1 : g_task_return_prefixed_error (GTask *task,
2078 : : GError *error,
2079 : : const char *format,
2080 : : ...)
2081 : : {
2082 : : char *prefix;
2083 : : va_list ap;
2084 : :
2085 : 1 : g_return_if_fail (G_IS_TASK (task));
2086 : 1 : g_return_if_fail (!task->ever_returned);
2087 : 1 : g_return_if_fail (error != NULL);
2088 : :
2089 : 1 : task->error = error;
2090 : :
2091 : 1 : va_start (ap, format);
2092 : 1 : prefix = g_strdup_vprintf (format, ap);
2093 : 1 : va_end (ap);
2094 : :
2095 : 1 : g_prefix_error_literal (&task->error, prefix);
2096 : :
2097 : 1 : g_free (prefix);
2098 : :
2099 : 1 : g_task_return (task, G_TASK_RETURN_ERROR);
2100 : : }
2101 : :
2102 : : /**
2103 : : * g_task_return_new_error:
2104 : : * @task: a #GTask.
2105 : : * @domain: a #GQuark.
2106 : : * @code: an error code.
2107 : : * @format: a string with format characters.
2108 : : * @...: a list of values to insert into @format.
2109 : : *
2110 : : * Sets @task's result to a new #GError created from @domain, @code,
2111 : : * @format, and the remaining arguments, and completes the task (see
2112 : : * g_task_return_pointer() for more discussion of exactly what this
2113 : : * means).
2114 : : *
2115 : : * See also g_task_return_error().
2116 : : *
2117 : : * Since: 2.36
2118 : : */
2119 : : void
2120 : 21 : g_task_return_new_error (GTask *task,
2121 : : GQuark domain,
2122 : : gint code,
2123 : : const char *format,
2124 : : ...)
2125 : : {
2126 : : GError *error;
2127 : : va_list args;
2128 : :
2129 : 21 : va_start (args, format);
2130 : 21 : error = g_error_new_valist (domain, code, format, args);
2131 : 21 : va_end (args);
2132 : :
2133 : 21 : g_task_return_error (task, error);
2134 : 21 : }
2135 : :
2136 : : /**
2137 : : * g_task_return_new_error_literal:
2138 : : * @task: a #GTask.
2139 : : * @domain: a #GQuark.
2140 : : * @code: an error code.
2141 : : * @message: an error message
2142 : : *
2143 : : * Sets @task’s result to a new [type@GLib.Error] created from @domain, @code,
2144 : : * @message and completes the task.
2145 : : *
2146 : : * See [method@Gio.Task.return_pointer] for more discussion of exactly what
2147 : : * ‘completing the task’ means.
2148 : : *
2149 : : * See also [method@Gio.Task.return_new_error].
2150 : : *
2151 : : * Since: 2.80
2152 : : */
2153 : : void
2154 : 160 : g_task_return_new_error_literal (GTask *task,
2155 : : GQuark domain,
2156 : : gint code,
2157 : : const char *message)
2158 : : {
2159 : 160 : g_task_return_error (task, g_error_new_literal (domain, code, message));
2160 : 160 : }
2161 : :
2162 : : /**
2163 : : * g_task_return_error_if_cancelled:
2164 : : * @task: a #GTask
2165 : : *
2166 : : * Checks if @task's #GCancellable has been cancelled, and if so, sets
2167 : : * @task's error accordingly and completes the task (see
2168 : : * g_task_return_pointer() for more discussion of exactly what this
2169 : : * means).
2170 : : *
2171 : : * Returns: %TRUE if @task has been cancelled, %FALSE if not
2172 : : *
2173 : : * Since: 2.36
2174 : : */
2175 : : gboolean
2176 : 36389 : g_task_return_error_if_cancelled (GTask *task)
2177 : : {
2178 : 36389 : GError *error = NULL;
2179 : :
2180 : 36389 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
2181 : 36389 : g_return_val_if_fail (!task->ever_returned, FALSE);
2182 : :
2183 : 36389 : if (g_cancellable_set_error_if_cancelled (task->cancellable, &error))
2184 : : {
2185 : : /* We explicitly set task->error so this works even when
2186 : : * check-cancellable is not set.
2187 : : */
2188 : 1244 : g_clear_error (&task->error);
2189 : 1244 : task->error = error;
2190 : :
2191 : 1244 : g_task_return (task, G_TASK_RETURN_ERROR);
2192 : 1244 : return TRUE;
2193 : : }
2194 : : else
2195 : 35145 : return FALSE;
2196 : : }
2197 : :
2198 : : /**
2199 : : * g_task_had_error:
2200 : : * @task: a #GTask.
2201 : : *
2202 : : * Tests if @task resulted in an error.
2203 : : *
2204 : : * Returns: %TRUE if the task resulted in an error, %FALSE otherwise.
2205 : : *
2206 : : * Since: 2.36
2207 : : */
2208 : : gboolean
2209 : 404 : g_task_had_error (GTask *task)
2210 : : {
2211 : 404 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
2212 : :
2213 : 404 : if (task->error != NULL || task->had_error)
2214 : 15 : return TRUE;
2215 : :
2216 : 389 : if (task->check_cancellable && g_cancellable_is_cancelled (task->cancellable))
2217 : 18 : return TRUE;
2218 : :
2219 : 371 : return FALSE;
2220 : : }
2221 : :
2222 : : static void
2223 : 0 : value_free (gpointer value)
2224 : : {
2225 : 0 : g_value_unset (value);
2226 : 0 : g_free (value);
2227 : 0 : }
2228 : :
2229 : : /**
2230 : : * g_task_return_value:
2231 : : * @task: a #GTask
2232 : : * @result: (nullable) (transfer none): the #GValue result of
2233 : : * a task function
2234 : : *
2235 : : * Sets @task's result to @result (by copying it) and completes the task.
2236 : : *
2237 : : * If @result is %NULL then a #GValue of type %G_TYPE_POINTER
2238 : : * with a value of %NULL will be used for the result.
2239 : : *
2240 : : * This is a very generic low-level method intended primarily for use
2241 : : * by language bindings; for C code, g_task_return_pointer() and the
2242 : : * like will normally be much easier to use.
2243 : : *
2244 : : * Since: 2.64
2245 : : */
2246 : : void
2247 : 1 : g_task_return_value (GTask *task,
2248 : : GValue *result)
2249 : : {
2250 : : GValue *value;
2251 : :
2252 : 1 : g_return_if_fail (G_IS_TASK (task));
2253 : 1 : g_return_if_fail (!task->ever_returned);
2254 : :
2255 : 1 : value = g_new0 (GValue, 1);
2256 : :
2257 : 1 : if (result == NULL)
2258 : : {
2259 : 0 : g_value_init (value, G_TYPE_POINTER);
2260 : 0 : g_value_set_pointer (value, NULL);
2261 : : }
2262 : : else
2263 : : {
2264 : 1 : g_value_init (value, G_VALUE_TYPE (result));
2265 : 1 : g_value_copy (result, value);
2266 : : }
2267 : :
2268 : 1 : g_task_return_pointer (task, value, value_free);
2269 : : }
2270 : :
2271 : : /**
2272 : : * g_task_propagate_value:
2273 : : * @task: a #GTask
2274 : : * @value: (out caller-allocates): return location for the #GValue
2275 : : * @error: return location for a #GError
2276 : : *
2277 : : * Gets the result of @task as a #GValue, and transfers ownership of
2278 : : * that value to the caller. As with g_task_return_value(), this is
2279 : : * a generic low-level method; g_task_propagate_pointer() and the like
2280 : : * will usually be more useful for C code.
2281 : : *
2282 : : * If the task resulted in an error, or was cancelled, then this will
2283 : : * instead set @error and return %FALSE.
2284 : : *
2285 : : * Since this method transfers ownership of the return value (or
2286 : : * error) to the caller, you may only call it once.
2287 : : *
2288 : : * Returns: %TRUE if @task succeeded, %FALSE on error.
2289 : : *
2290 : : * Since: 2.64
2291 : : */
2292 : : gboolean
2293 : 1 : g_task_propagate_value (GTask *task,
2294 : : GValue *value,
2295 : : GError **error)
2296 : : {
2297 : 1 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
2298 : 1 : g_return_val_if_fail (value != NULL, FALSE);
2299 : 1 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2300 : :
2301 : 1 : if (g_task_propagate_error (task, error))
2302 : 0 : return FALSE;
2303 : :
2304 : 1 : g_return_val_if_fail (task->result_set, FALSE);
2305 : 1 : g_return_val_if_fail (task->result_destroy == value_free, FALSE);
2306 : :
2307 : 1 : memcpy (value, task->result.pointer, sizeof (GValue));
2308 : 1 : g_free (task->result.pointer);
2309 : :
2310 : 1 : task->result_destroy = NULL;
2311 : 1 : task->result_set = FALSE;
2312 : :
2313 : 1 : return TRUE;
2314 : : }
2315 : :
2316 : : /**
2317 : : * g_task_get_completed:
2318 : : * @task: a #GTask.
2319 : : *
2320 : : * Gets the value of #GTask:completed. This changes from %FALSE to %TRUE after
2321 : : * the task’s callback is invoked, and will return %FALSE if called from inside
2322 : : * the callback.
2323 : : *
2324 : : * Returns: %TRUE if the task has completed, %FALSE otherwise.
2325 : : *
2326 : : * Since: 2.44
2327 : : */
2328 : : gboolean
2329 : 67 : g_task_get_completed (GTask *task)
2330 : : {
2331 : 67 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
2332 : :
2333 : : /* Convert from a bit field to a boolean. */
2334 : 67 : return task->completed ? TRUE : FALSE;
2335 : : }
2336 : :
2337 : : /**
2338 : : * g_task_is_valid:
2339 : : * @result: (type Gio.AsyncResult): A #GAsyncResult
2340 : : * @source_object: (nullable) (type GObject): the source object
2341 : : * expected to be associated with the task
2342 : : *
2343 : : * Checks that @result is a #GTask, and that @source_object is its
2344 : : * source object (or that @source_object is %NULL and @result has no
2345 : : * source object). This can be used in g_return_if_fail() checks.
2346 : : *
2347 : : * Returns: %TRUE if @result and @source_object are valid, %FALSE
2348 : : * if not
2349 : : *
2350 : : * Since: 2.36
2351 : : */
2352 : : gboolean
2353 : 122216 : g_task_is_valid (gpointer result,
2354 : : gpointer source_object)
2355 : : {
2356 : 122216 : if (!G_IS_TASK (result))
2357 : 1 : return FALSE;
2358 : :
2359 : 122215 : return G_TASK (result)->source_object == source_object;
2360 : : }
2361 : :
2362 : : static gint
2363 : 1230 : g_task_compare_priority (gconstpointer a,
2364 : : gconstpointer b,
2365 : : gpointer user_data)
2366 : : {
2367 : 1230 : const GTask *ta = a;
2368 : 1230 : const GTask *tb = b;
2369 : : gboolean a_cancelled, b_cancelled;
2370 : :
2371 : : /* Tasks that are causing other tasks to block have higher
2372 : : * priority.
2373 : : */
2374 : 1230 : if (ta->blocking_other_task && !tb->blocking_other_task)
2375 : 0 : return -1;
2376 : 1230 : else if (tb->blocking_other_task && !ta->blocking_other_task)
2377 : 0 : return 1;
2378 : :
2379 : : /* Let already-cancelled tasks finish right away */
2380 : 2343 : a_cancelled = (ta->check_cancellable &&
2381 : 1113 : g_cancellable_is_cancelled (ta->cancellable));
2382 : 2440 : b_cancelled = (tb->check_cancellable &&
2383 : 1210 : g_cancellable_is_cancelled (tb->cancellable));
2384 : 1230 : if (a_cancelled && !b_cancelled)
2385 : 0 : return -1;
2386 : 1230 : else if (b_cancelled && !a_cancelled)
2387 : 0 : return 1;
2388 : :
2389 : : /* Lower priority == run sooner == negative return value */
2390 : 1230 : return ta->priority - tb->priority;
2391 : : }
2392 : :
2393 : : static gboolean
2394 : 6 : trivial_source_dispatch (GSource *source,
2395 : : GSourceFunc callback,
2396 : : gpointer user_data)
2397 : : {
2398 : 6 : return callback (user_data);
2399 : : }
2400 : :
2401 : : GSourceFuncs trivial_source_funcs = {
2402 : : NULL, /* prepare */
2403 : : NULL, /* check */
2404 : : trivial_source_dispatch,
2405 : : NULL, /* finalize */
2406 : : NULL, /* closure */
2407 : : NULL /* marshal */
2408 : : };
2409 : :
2410 : : static void
2411 : 163 : g_task_thread_pool_init (void)
2412 : : {
2413 : 163 : task_pool = g_thread_pool_new (g_task_thread_pool_thread, NULL,
2414 : : G_TASK_POOL_SIZE, FALSE, NULL);
2415 : 163 : g_assert (task_pool != NULL);
2416 : :
2417 : 163 : g_thread_pool_set_sort_function (task_pool, g_task_compare_priority, NULL);
2418 : :
2419 : 163 : task_pool_manager = g_source_new (&trivial_source_funcs, sizeof (GSource));
2420 : 163 : g_source_set_static_name (task_pool_manager, "GTask thread pool manager");
2421 : 163 : g_source_set_callback (task_pool_manager, task_pool_manager_timeout, NULL, NULL);
2422 : 163 : g_source_set_ready_time (task_pool_manager, -1);
2423 : 163 : g_source_attach (task_pool_manager,
2424 : 163 : GLIB_PRIVATE_CALL (g_get_worker_context ()));
2425 : 163 : g_source_unref (task_pool_manager);
2426 : 163 : }
2427 : :
2428 : : static void
2429 : 10 : g_task_get_property (GObject *object,
2430 : : guint prop_id,
2431 : : GValue *value,
2432 : : GParamSpec *pspec)
2433 : : {
2434 : 10 : GTask *task = G_TASK (object);
2435 : :
2436 : 10 : switch ((GTaskProperty) prop_id)
2437 : : {
2438 : 10 : case PROP_COMPLETED:
2439 : 10 : g_value_set_boolean (value, g_task_get_completed (task));
2440 : 10 : break;
2441 : : }
2442 : 10 : }
2443 : :
2444 : : static void
2445 : 163 : g_task_class_init (GTaskClass *klass)
2446 : : {
2447 : 163 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2448 : :
2449 : : #ifdef G_ENABLE_DEBUG
2450 : 163 : gobject_class->constructed = g_task_constructed;
2451 : : #endif
2452 : 163 : gobject_class->get_property = g_task_get_property;
2453 : 163 : gobject_class->finalize = g_task_finalize;
2454 : :
2455 : : /**
2456 : : * GTask:completed:
2457 : : *
2458 : : * Whether the task has completed, meaning its callback (if set) has been
2459 : : * invoked.
2460 : : *
2461 : : * This can only happen after g_task_return_pointer(),
2462 : : * g_task_return_error() or one of the other return functions have been called
2463 : : * on the task. However, it is not guaranteed to happen immediately after
2464 : : * those functions are called, as the task’s callback may need to be scheduled
2465 : : * to run in a different thread.
2466 : : *
2467 : : * That means it is **not safe** to use this property to track whether a
2468 : : * return function has been called on the #GTask. Callers must do that
2469 : : * tracking themselves, typically by linking the lifetime of the #GTask to the
2470 : : * control flow of their code.
2471 : : *
2472 : : * This property is guaranteed to change from %FALSE to %TRUE exactly once.
2473 : : *
2474 : : * The #GObject::notify signal for this change is emitted in the same main
2475 : : * context as the task’s callback, immediately after that callback is invoked.
2476 : : *
2477 : : * Since: 2.44
2478 : : */
2479 : 163 : g_object_class_install_property (gobject_class, PROP_COMPLETED,
2480 : : g_param_spec_boolean ("completed", NULL, NULL,
2481 : : FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
2482 : :
2483 : 163 : if (G_UNLIKELY (task_pool_max_counter == 0))
2484 : : {
2485 : : /* We use two counters to track characteristics of the GTask thread pool.
2486 : : * task pool max size - the value of g_thread_pool_set_max_threads()
2487 : : * tasks running - the number of running threads
2488 : : */
2489 : 163 : task_pool_max_counter = g_trace_define_int64_counter ("GIO", "task pool max size", "Maximum number of threads allowed in the GTask thread pool; see g_thread_pool_set_max_threads()");
2490 : 163 : tasks_running_counter = g_trace_define_int64_counter ("GIO", "tasks running", "Number of currently running tasks in the GTask thread pool");
2491 : : }
2492 : 163 : }
2493 : :
2494 : : static gpointer
2495 : 45 : g_task_get_user_data (GAsyncResult *res)
2496 : : {
2497 : 45 : return G_TASK (res)->callback_data;
2498 : : }
2499 : :
2500 : : static gboolean
2501 : 31660 : g_task_is_tagged (GAsyncResult *res,
2502 : : gpointer source_tag)
2503 : : {
2504 : 31660 : return G_TASK (res)->source_tag == source_tag;
2505 : : }
2506 : :
2507 : : static void
2508 : 163 : g_task_async_result_iface_init (GAsyncResultIface *iface)
2509 : : {
2510 : 163 : iface->get_user_data = g_task_get_user_data;
2511 : 163 : iface->get_source_object = g_task_ref_source_object;
2512 : 163 : iface->is_tagged = g_task_is_tagged;
2513 : 163 : }
|