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 [ + + + - : 2148555 : 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 : 125075 : g_task_init (GTask *task)
665 : : {
666 : 125075 : task->check_cancellable = TRUE;
667 : 125075 : }
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 : 125072 : g_task_constructed (GObject *object)
707 : : {
708 : 125072 : GTask *task = G_TASK (object);
709 : :
710 : 125069 : G_OBJECT_CLASS (g_task_parent_class)->constructed (object);
711 : :
712 : : /* Track pending tasks for debugging purposes */
713 : 125069 : G_LOCK (task_list);
714 [ + + ]: 125075 : if (G_UNLIKELY (task_list == NULL))
715 : 2432 : task_list = g_ptr_array_new ();
716 : 125075 : g_ptr_array_add (task_list, task);
717 : 125075 : G_UNLOCK (task_list);
718 : 125075 : }
719 : : #endif /* G_ENABLE_DEBUG */
720 : :
721 : : static void
722 : 124910 : g_task_finalize (GObject *object)
723 : : {
724 : 124910 : 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 [ + + ]: 124906 : 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 : 124906 : g_clear_object (&task->source_object);
755 : 124907 : g_clear_object (&task->cancellable);
756 [ + + ]: 124907 : if (!task->name_is_static)
757 : 10327 : g_free (task->name);
758 : :
759 [ + + ]: 124907 : if (task->context)
760 : 124906 : g_main_context_unref (task->context);
761 : :
762 [ + + ]: 124913 : if (task->task_data_destroy)
763 : 93599 : task->task_data_destroy (task->task_data);
764 : :
765 [ + + + - ]: 124913 : if (task->result_destroy && task->result.pointer)
766 : 8 : task->result_destroy (task->result.pointer);
767 : :
768 [ + + ]: 124913 : if (task->error)
769 : 2581 : g_error_free (task->error);
770 : :
771 [ + + ]: 124913 : if (G_TASK_IS_THREADED (task))
772 : : {
773 : 3445 : g_mutex_clear (&task->lock);
774 : 3446 : g_cond_clear (&task->cond);
775 : : }
776 : :
777 : : /* Track pending tasks for debugging purposes */
778 : : #ifdef G_ENABLE_DEBUG
779 : 124914 : G_LOCK (task_list);
780 : 124914 : g_assert (task_list != NULL);
781 : 124914 : g_ptr_array_remove_fast (task_list, task);
782 [ + + ]: 124914 : if (G_UNLIKELY (task_list->len == 0))
783 : 2368 : g_clear_pointer (&task_list, g_ptr_array_unref);
784 : 124914 : G_UNLOCK (task_list);
785 : : #endif /* G_ENABLE_DEBUG */
786 : :
787 : 124914 : G_OBJECT_CLASS (g_task_parent_class)->finalize (object);
788 : 124914 : }
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 : 125072 : 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 : 125072 : task = g_object_new (G_TYPE_TASK, NULL);
829 [ + + ]: 125074 : task->source_object = source_object ? g_object_ref (source_object) : NULL;
830 [ + + ]: 125073 : task->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
831 : 125073 : task->callback = callback;
832 : 125073 : task->callback_data = callback_data;
833 : 125073 : task->context = g_main_context_ref_thread_default ();
834 : :
835 : 125074 : source = g_main_current_source ();
836 [ + + ]: 125073 : if (source)
837 : 115978 : task->creation_time = g_source_get_time (source);
838 : :
839 : 125073 : TRACE (GIO_TASK_NEW (task, source_object, cancellable,
840 : : callback, callback_data));
841 : :
842 : 125073 : 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 : 95727 : g_task_set_task_data (GTask *task,
938 : : gpointer task_data,
939 : : GDestroyNotify task_data_destroy)
940 : : {
941 : 95727 : g_return_if_fail (G_IS_TASK (task));
942 : :
943 [ + + ]: 95727 : if (task->task_data_destroy)
944 : 1 : task->task_data_destroy (task->task_data);
945 : :
946 : 95727 : task->task_data = task_data;
947 : 95727 : task->task_data_destroy = task_data_destroy;
948 : :
949 : 95727 : 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 : 34745 : g_task_set_priority (GTask *task,
969 : : gint priority)
970 : : {
971 : 34745 : g_return_if_fail (G_IS_TASK (task));
972 : :
973 : 34745 : task->priority = priority;
974 : :
975 : 34745 : 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 : 16221 : g_task_set_check_cancellable (GTask *task,
1003 : : gboolean check_cancellable)
1004 : : {
1005 : 16221 : g_return_if_fail (G_IS_TASK (task));
1006 : 16221 : g_return_if_fail (check_cancellable || !task->return_on_cancel);
1007 : :
1008 : 16221 : 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 : 114708 : (g_task_set_source_tag) (GTask *task,
1107 : : gpointer source_tag)
1108 : : {
1109 : 114708 : g_return_if_fail (G_IS_TASK (task));
1110 : :
1111 : 114708 : task->source_tag = source_tag;
1112 : :
1113 : 114708 : 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. It is called automatically by
1130 : : * g_task_set_source_tag() if not called already.
1131 : : *
1132 : : * Since: 2.60
1133 : : */
1134 : : void
1135 : 26 : (g_task_set_name) (GTask *task,
1136 : : const char *name)
1137 : : {
1138 : : char *new_name;
1139 : :
1140 : 26 : g_return_if_fail (G_IS_TASK (task));
1141 : :
1142 : 26 : new_name = g_strdup (name);
1143 [ + - ]: 26 : if (!task->name_is_static)
1144 : 26 : g_free (task->name);
1145 : 26 : task->name = g_steal_pointer (&new_name);
1146 : 26 : task->name_is_static = FALSE;
1147 : : }
1148 : :
1149 : : /**
1150 : : * g_task_set_static_name:
1151 : : * @task: a #GTask
1152 : : * @name: (nullable): a human readable name for the task. Must be a string literal
1153 : : *
1154 : : * Sets @task’s name, used in debugging and profiling.
1155 : : *
1156 : : * This is a variant of g_task_set_name() that avoids copying @name.
1157 : : *
1158 : : * Since: 2.76
1159 : : */
1160 : : void
1161 : 184573 : g_task_set_static_name (GTask *task,
1162 : : const char *name)
1163 : : {
1164 : 184573 : g_return_if_fail (G_IS_TASK (task));
1165 : :
1166 [ + + ]: 184573 : if (!task->name_is_static)
1167 : 114709 : g_free (task->name);
1168 : 184577 : task->name = (char *) name;
1169 : 184577 : task->name_is_static = TRUE;
1170 : : }
1171 : :
1172 : : /**
1173 : : * g_task_get_source_object:
1174 : : * @task: a #GTask
1175 : : *
1176 : : * Gets the source object from @task. Like
1177 : : * g_async_result_get_source_object(), but does not ref the object.
1178 : : *
1179 : : * Returns: (transfer none) (nullable) (type GObject): @task's source object, or %NULL
1180 : : *
1181 : : * Since: 2.36
1182 : : */
1183 : : gpointer
1184 : 6748 : g_task_get_source_object (GTask *task)
1185 : : {
1186 : 6748 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1187 : :
1188 : 6748 : return task->source_object;
1189 : : }
1190 : :
1191 : : static GObject *
1192 : 427 : g_task_ref_source_object (GAsyncResult *res)
1193 : : {
1194 : 427 : GTask *task = G_TASK (res);
1195 : :
1196 [ + - ]: 427 : if (task->source_object)
1197 : 427 : return g_object_ref (task->source_object);
1198 : : else
1199 : 0 : return NULL;
1200 : : }
1201 : :
1202 : : /**
1203 : : * g_task_get_task_data:
1204 : : * @task: a #GTask
1205 : : *
1206 : : * Gets @task's `task_data`.
1207 : : *
1208 : : * Returns: (transfer none): @task's `task_data`.
1209 : : *
1210 : : * Since: 2.36
1211 : : */
1212 : : gpointer
1213 : 117688 : g_task_get_task_data (GTask *task)
1214 : : {
1215 : 117688 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1216 : :
1217 : 117688 : return task->task_data;
1218 : : }
1219 : :
1220 : : /**
1221 : : * g_task_get_priority:
1222 : : * @task: a #GTask
1223 : : *
1224 : : * Gets @task's priority
1225 : : *
1226 : : * Returns: @task's priority
1227 : : *
1228 : : * Since: 2.36
1229 : : */
1230 : : gint
1231 : 920 : g_task_get_priority (GTask *task)
1232 : : {
1233 : 920 : g_return_val_if_fail (G_IS_TASK (task), G_PRIORITY_DEFAULT);
1234 : :
1235 : 920 : return task->priority;
1236 : : }
1237 : :
1238 : : /**
1239 : : * g_task_get_context:
1240 : : * @task: a #GTask
1241 : : *
1242 : : * Gets the #GMainContext that @task will return its result in (that
1243 : : * is, the context that was the
1244 : : * [thread-default main context][g-main-context-push-thread-default]
1245 : : * at the point when @task was created).
1246 : : *
1247 : : * This will always return a non-%NULL value, even if the task's
1248 : : * context is the default #GMainContext.
1249 : : *
1250 : : * Returns: (transfer none): @task's #GMainContext
1251 : : *
1252 : : * Since: 2.36
1253 : : */
1254 : : GMainContext *
1255 : 27 : g_task_get_context (GTask *task)
1256 : : {
1257 : 27 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1258 : :
1259 : 27 : return task->context;
1260 : : }
1261 : :
1262 : : /**
1263 : : * g_task_get_cancellable:
1264 : : * @task: a #GTask
1265 : : *
1266 : : * Gets @task's #GCancellable
1267 : : *
1268 : : * Returns: (nullable) (transfer none): @task's #GCancellable
1269 : : *
1270 : : * Since: 2.36
1271 : : */
1272 : : GCancellable *
1273 : 179110 : g_task_get_cancellable (GTask *task)
1274 : : {
1275 : 179110 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1276 : :
1277 : 179110 : return task->cancellable;
1278 : : }
1279 : :
1280 : : /**
1281 : : * g_task_get_check_cancellable:
1282 : : * @task: the #GTask
1283 : : *
1284 : : * Gets @task's check-cancellable flag. See
1285 : : * g_task_set_check_cancellable() for more details.
1286 : : *
1287 : : * Since: 2.36
1288 : : */
1289 : : gboolean
1290 : 26 : g_task_get_check_cancellable (GTask *task)
1291 : : {
1292 : 26 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
1293 : :
1294 : : /* Convert from a bit field to a boolean. */
1295 : 26 : return task->check_cancellable ? TRUE : FALSE;
1296 : : }
1297 : :
1298 : : /**
1299 : : * g_task_get_return_on_cancel:
1300 : : * @task: the #GTask
1301 : : *
1302 : : * Gets @task's return-on-cancel flag. See
1303 : : * g_task_set_return_on_cancel() for more details.
1304 : : *
1305 : : * Since: 2.36
1306 : : */
1307 : : gboolean
1308 : 9 : g_task_get_return_on_cancel (GTask *task)
1309 : : {
1310 : 9 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
1311 : :
1312 : : /* Convert from a bit field to a boolean. */
1313 : 9 : return task->return_on_cancel ? TRUE : FALSE;
1314 : : }
1315 : :
1316 : : /**
1317 : : * g_task_get_source_tag:
1318 : : * @task: a #GTask
1319 : : *
1320 : : * Gets @task's source tag. See g_task_set_source_tag().
1321 : : *
1322 : : * Returns: (transfer none): @task's source tag
1323 : : *
1324 : : * Since: 2.36
1325 : : */
1326 : : gpointer
1327 : 40 : g_task_get_source_tag (GTask *task)
1328 : : {
1329 : 40 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1330 : :
1331 : 40 : return task->source_tag;
1332 : : }
1333 : :
1334 : : /**
1335 : : * g_task_get_name:
1336 : : * @task: a #GTask
1337 : : *
1338 : : * Gets @task’s name. See g_task_set_name().
1339 : : *
1340 : : * Returns: (nullable) (transfer none): @task’s name, or %NULL
1341 : : * Since: 2.60
1342 : : */
1343 : : const gchar *
1344 : 114769 : g_task_get_name (GTask *task)
1345 : : {
1346 : 114769 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1347 : :
1348 : 114769 : return task->name;
1349 : : }
1350 : :
1351 : : static void
1352 : 124899 : g_task_return_now (GTask *task)
1353 : : {
1354 : 124899 : TRACE (GIO_TASK_BEFORE_RETURN (task, task->source_object, task->callback,
1355 : : task->callback_data));
1356 : :
1357 : 124899 : g_main_context_push_thread_default (task->context);
1358 : :
1359 [ + + ]: 124900 : if (task->callback != NULL)
1360 : : {
1361 : 123820 : task->callback (task->source_object,
1362 : 123827 : G_ASYNC_RESULT (task),
1363 : : task->callback_data);
1364 : : }
1365 : :
1366 : 124894 : task->completed = TRUE;
1367 : 124894 : g_object_notify (G_OBJECT (task), "completed");
1368 : :
1369 : 124899 : g_main_context_pop_thread_default (task->context);
1370 : 124899 : }
1371 : :
1372 : : static gboolean
1373 : 82676 : complete_in_idle_cb (gpointer task)
1374 : : {
1375 : 82676 : g_task_return_now (task);
1376 : 82679 : g_object_unref (task);
1377 : 82678 : return FALSE;
1378 : : }
1379 : :
1380 : : typedef enum {
1381 : : G_TASK_RETURN_SUCCESS,
1382 : : G_TASK_RETURN_ERROR,
1383 : : G_TASK_RETURN_FROM_THREAD
1384 : : } GTaskReturnType;
1385 : :
1386 : : static void
1387 : 128382 : g_task_return (GTask *task,
1388 : : GTaskReturnType type)
1389 : : {
1390 : : GSource *source;
1391 : :
1392 [ + + ]: 128382 : if (type != G_TASK_RETURN_FROM_THREAD)
1393 : 124933 : task->ever_returned = TRUE;
1394 : :
1395 [ + + ]: 128382 : if (type == G_TASK_RETURN_SUCCESS)
1396 : 121448 : task->result_set = TRUE;
1397 : :
1398 [ + + ]: 128382 : if (task->synchronous)
1399 : 4 : return;
1400 : :
1401 : : /* Normally we want to invoke the task's callback when its return
1402 : : * value is set. But if the task is running in a thread, then we
1403 : : * want to wait until after the task_func returns, to simplify
1404 : : * locking/refcounting/etc.
1405 : : */
1406 [ + + + + ]: 128378 : if (G_TASK_IS_THREADED (task) && type != G_TASK_RETURN_FROM_THREAD)
1407 : 3455 : return;
1408 : :
1409 : 124923 : g_object_ref (task);
1410 : :
1411 : : /* See if we can complete the task immediately. First, we have to be
1412 : : * running inside the task's thread/GMainContext.
1413 : : */
1414 : 124928 : source = g_main_current_source ();
1415 [ + + + + ]: 124930 : if (source && g_source_get_context (source) == task->context)
1416 : : {
1417 : : /* Second, we can only complete immediately if this is not the
1418 : : * same iteration of the main loop that the task was created in.
1419 : : */
1420 [ + + ]: 115565 : if (g_source_get_time (source) > task->creation_time)
1421 : : {
1422 : : /* Finally, if the task has been cancelled, we shouldn't
1423 : : * return synchronously from inside the
1424 : : * GCancellable::cancelled handler. It's easier to run
1425 : : * another iteration of the main loop than tracking how the
1426 : : * cancellation was handled.
1427 : : */
1428 [ + + ]: 43808 : if (!g_cancellable_is_cancelled (task->cancellable))
1429 : : {
1430 : 42221 : g_task_return_now (task);
1431 : 42221 : g_object_unref (task);
1432 : 42221 : return;
1433 : : }
1434 : : }
1435 : : }
1436 : :
1437 : : /* Otherwise, complete in the next iteration */
1438 : 82709 : source = g_idle_source_new ();
1439 : :
1440 : : /* Note: in case the task name is NULL we set it as a const string instead
1441 : : * of going through the concat path which is more expensive and may show in the
1442 : : * profiler if g_task_return is called very often
1443 : : */
1444 [ + + ]: 82708 : if (task->name == NULL)
1445 : 10092 : g_source_set_static_name (source, "[gio] (unnamed) complete_in_idle_cb");
1446 : : else
1447 : : {
1448 : : gchar *source_name;
1449 : :
1450 : 72616 : source_name = g_strconcat ("[gio] ", task->name, " complete_in_idle_cb", NULL);
1451 : 72617 : g_source_set_name (source, source_name);
1452 : 72617 : g_free (source_name);
1453 : : }
1454 : :
1455 : 82709 : g_task_attach_source (task, source, complete_in_idle_cb);
1456 : 82709 : g_source_unref (source);
1457 : : }
1458 : :
1459 : :
1460 : : /**
1461 : : * GTaskThreadFunc:
1462 : : * @task: the #GTask
1463 : : * @source_object: (type GObject): @task's source object
1464 : : * @task_data: @task's task data
1465 : : * @cancellable: @task's #GCancellable, or %NULL
1466 : : *
1467 : : * The prototype for a task function to be run in a thread via
1468 : : * g_task_run_in_thread() or g_task_run_in_thread_sync().
1469 : : *
1470 : : * If the return-on-cancel flag is set on @task, and @cancellable gets
1471 : : * cancelled, then the #GTask will be completed immediately (as though
1472 : : * g_task_return_error_if_cancelled() had been called), without
1473 : : * waiting for the task function to complete. However, the task
1474 : : * function will continue running in its thread in the background. The
1475 : : * function therefore needs to be careful about how it uses
1476 : : * externally-visible state in this case. See
1477 : : * g_task_set_return_on_cancel() for more details.
1478 : : *
1479 : : * Other than in that case, @task will be completed when the
1480 : : * #GTaskThreadFunc returns, not when it calls a
1481 : : * `g_task_return_` function.
1482 : : *
1483 : : * Since: 2.36
1484 : : */
1485 : :
1486 : : static void task_thread_cancelled (GCancellable *cancellable,
1487 : : gpointer user_data);
1488 : :
1489 : : static void
1490 : 3467 : g_task_thread_complete (GTask *task)
1491 : : {
1492 : 3467 : g_mutex_lock (&task->lock);
1493 [ + + ]: 3467 : if (task->thread_complete)
1494 : : {
1495 : : /* The task belatedly completed after having been cancelled
1496 : : * (or was cancelled in the midst of being completed).
1497 : : */
1498 : 6 : g_mutex_unlock (&task->lock);
1499 : 6 : return;
1500 : : }
1501 : :
1502 : 3461 : TRACE (GIO_TASK_AFTER_RUN_IN_THREAD (task, task->thread_cancelled));
1503 : :
1504 : 3461 : task->thread_complete = TRUE;
1505 : 3461 : g_mutex_unlock (&task->lock);
1506 : :
1507 [ + + ]: 3461 : if (task->cancellable)
1508 : 1331 : g_signal_handlers_disconnect_by_func (task->cancellable, task_thread_cancelled, task);
1509 : :
1510 [ + + ]: 3460 : if (task->synchronous)
1511 : 5 : g_cond_signal (&task->cond);
1512 : : else
1513 : 3455 : g_task_return (task, G_TASK_RETURN_FROM_THREAD);
1514 : : }
1515 : :
1516 : : static gboolean
1517 : 6 : task_pool_manager_timeout (gpointer user_data)
1518 : : {
1519 : 6 : g_mutex_lock (&task_pool_mutex);
1520 : 6 : g_thread_pool_set_max_threads (task_pool, tasks_running + 1, NULL);
1521 : : g_trace_set_int64_counter (task_pool_max_counter, tasks_running + 1);
1522 : 6 : g_source_set_ready_time (task_pool_manager, -1);
1523 : 6 : g_mutex_unlock (&task_pool_mutex);
1524 : :
1525 : 6 : return TRUE;
1526 : : }
1527 : :
1528 : : static void
1529 : 3463 : g_task_thread_setup (void)
1530 : : {
1531 : 3463 : g_private_set (&task_private, GUINT_TO_POINTER (TRUE));
1532 : 3463 : g_mutex_lock (&task_pool_mutex);
1533 : 3463 : tasks_running++;
1534 : :
1535 : : g_trace_set_int64_counter (tasks_running_counter, tasks_running);
1536 : :
1537 [ + + ]: 3463 : if (tasks_running == G_TASK_POOL_SIZE)
1538 : 705 : task_wait_time = G_TASK_WAIT_TIME_BASE;
1539 [ + + + - ]: 2758 : else if (tasks_running > G_TASK_POOL_SIZE && tasks_running < G_TASK_WAIT_TIME_MAX_POOL_SIZE)
1540 : 6 : task_wait_time *= G_TASK_WAIT_TIME_MULTIPLIER;
1541 : :
1542 [ + + ]: 3463 : if (tasks_running >= G_TASK_POOL_SIZE)
1543 : 711 : g_source_set_ready_time (task_pool_manager, g_get_monotonic_time () + task_wait_time);
1544 : :
1545 : 3463 : g_mutex_unlock (&task_pool_mutex);
1546 : 3463 : }
1547 : :
1548 : : static void
1549 : 3463 : g_task_thread_cleanup (void)
1550 : : {
1551 : : gint tasks_pending;
1552 : :
1553 : 3463 : g_mutex_lock (&task_pool_mutex);
1554 : 3463 : tasks_pending = g_thread_pool_unprocessed (task_pool);
1555 : :
1556 [ + + ]: 3463 : if (tasks_running > G_TASK_POOL_SIZE)
1557 : : {
1558 : 6 : g_thread_pool_set_max_threads (task_pool, tasks_running - 1, NULL);
1559 : : g_trace_set_int64_counter (task_pool_max_counter, tasks_running - 1);
1560 : : }
1561 [ + + ]: 3457 : else if (tasks_running + tasks_pending < G_TASK_POOL_SIZE)
1562 : 2439 : g_source_set_ready_time (task_pool_manager, -1);
1563 : :
1564 [ + + + - ]: 3463 : if (tasks_running > G_TASK_POOL_SIZE && tasks_running < G_TASK_WAIT_TIME_MAX_POOL_SIZE)
1565 : 6 : task_wait_time /= G_TASK_WAIT_TIME_MULTIPLIER;
1566 : :
1567 : 3463 : tasks_running--;
1568 : :
1569 : : g_trace_set_int64_counter (tasks_running_counter, tasks_running);
1570 : :
1571 : 3463 : g_mutex_unlock (&task_pool_mutex);
1572 : 3462 : g_private_set (&task_private, GUINT_TO_POINTER (FALSE));
1573 : 3463 : }
1574 : :
1575 : : static void
1576 : 3462 : g_task_thread_pool_thread (gpointer thread_data,
1577 : : gpointer pool_data)
1578 : : {
1579 : 3462 : GTask *task = thread_data;
1580 : :
1581 : 3462 : g_task_thread_setup ();
1582 : :
1583 : 3463 : task->task_func (task, task->source_object, task->task_data,
1584 : : task->cancellable);
1585 : 3463 : g_task_thread_complete (task);
1586 : 3461 : g_object_unref (task);
1587 : :
1588 : 3463 : g_task_thread_cleanup ();
1589 : 3463 : }
1590 : :
1591 : : static void
1592 : 1037 : task_thread_cancelled (GCancellable *cancellable,
1593 : : gpointer user_data)
1594 : : {
1595 : 1037 : GTask *task = user_data;
1596 : :
1597 : : /* Move this task to the front of the queue - no need for
1598 : : * a complete resorting of the queue.
1599 : : */
1600 : 1037 : g_thread_pool_move_to_front (task_pool, task);
1601 : :
1602 : 1037 : g_mutex_lock (&task->lock);
1603 : 1037 : task->thread_cancelled = TRUE;
1604 : :
1605 [ + + ]: 1037 : if (!task->return_on_cancel)
1606 : : {
1607 : 1035 : g_mutex_unlock (&task->lock);
1608 : 1035 : return;
1609 : : }
1610 : :
1611 : : /* We don't actually set task->error; g_task_return_error() doesn't
1612 : : * use a lock, and g_task_propagate_error() will call
1613 : : * g_cancellable_set_error_if_cancelled() anyway.
1614 : : */
1615 : 2 : g_mutex_unlock (&task->lock);
1616 : 2 : g_task_thread_complete (task);
1617 : : }
1618 : :
1619 : : static void
1620 : 1331 : task_thread_cancelled_disconnect_notify (gpointer task,
1621 : : GClosure *closure)
1622 : : {
1623 : 1331 : g_object_unref (task);
1624 : 1330 : }
1625 : :
1626 : : static void
1627 : 3463 : g_task_start_task_thread (GTask *task,
1628 : : GTaskThreadFunc task_func)
1629 : : {
1630 : 3463 : g_mutex_init (&task->lock);
1631 : 3463 : g_cond_init (&task->cond);
1632 : :
1633 : 3463 : g_mutex_lock (&task->lock);
1634 : :
1635 : 3463 : TRACE (GIO_TASK_BEFORE_RUN_IN_THREAD (task, task_func));
1636 : :
1637 : 3463 : task->task_func = task_func;
1638 : :
1639 [ + + ]: 3463 : if (task->cancellable)
1640 : : {
1641 [ + + + + ]: 1339 : if (task->return_on_cancel &&
1642 : 6 : g_cancellable_set_error_if_cancelled (task->cancellable,
1643 : : &task->error))
1644 : : {
1645 : 2 : task->thread_cancelled = task->thread_complete = TRUE;
1646 : 2 : TRACE (GIO_TASK_AFTER_RUN_IN_THREAD (task, task->thread_cancelled));
1647 : 2 : g_thread_pool_push (task_pool, g_object_ref (task), NULL);
1648 : 2 : return;
1649 : : }
1650 : :
1651 : : /* This introduces a reference count loop between the GTask and
1652 : : * GCancellable, but is necessary to avoid a race on finalising the GTask
1653 : : * between task_thread_cancelled() (in one thread) and
1654 : : * g_task_thread_complete() (in another).
1655 : : *
1656 : : * Accordingly, the signal handler *must* be removed once the task has
1657 : : * completed.
1658 : : */
1659 : 1331 : g_signal_connect_data (task->cancellable, "cancelled",
1660 : : G_CALLBACK (task_thread_cancelled),
1661 : : g_object_ref (task),
1662 : : task_thread_cancelled_disconnect_notify,
1663 : : G_CONNECT_DEFAULT);
1664 : : }
1665 : :
1666 [ + + ]: 3461 : if (g_private_get (&task_private))
1667 : 2 : task->blocking_other_task = TRUE;
1668 : 3460 : g_thread_pool_push (task_pool, g_object_ref (task), NULL);
1669 : : }
1670 : :
1671 : : /**
1672 : : * g_task_run_in_thread:
1673 : : * @task: a #GTask
1674 : : * @task_func: (scope async): a #GTaskThreadFunc
1675 : : *
1676 : : * Runs @task_func in another thread. When @task_func returns, @task's
1677 : : * #GAsyncReadyCallback will be invoked in @task's #GMainContext.
1678 : : *
1679 : : * This takes a ref on @task until the task completes.
1680 : : *
1681 : : * See #GTaskThreadFunc for more details about how @task_func is handled.
1682 : : *
1683 : : * Although GLib currently rate-limits the tasks queued via
1684 : : * g_task_run_in_thread(), you should not assume that it will always
1685 : : * do this. If you have a very large number of tasks to run (several tens of
1686 : : * tasks), but don't want them to all run at once, you should only queue a
1687 : : * limited number of them (around ten) at a time.
1688 : : *
1689 : : * Be aware that if your task depends on other tasks to complete, use of this
1690 : : * function could lead to a livelock if the other tasks also use this function
1691 : : * and enough of them (around 10) execute in a dependency chain, as that will
1692 : : * exhaust the thread pool. If this situation is possible, consider using a
1693 : : * separate worker thread or thread pool explicitly, rather than using
1694 : : * g_task_run_in_thread().
1695 : : *
1696 : : * Since: 2.36
1697 : : */
1698 : : void
1699 : 3457 : g_task_run_in_thread (GTask *task,
1700 : : GTaskThreadFunc task_func)
1701 : : {
1702 : 3457 : g_return_if_fail (G_IS_TASK (task));
1703 : :
1704 : 3457 : g_object_ref (task);
1705 : 3457 : g_task_start_task_thread (task, task_func);
1706 : :
1707 : : /* The task may already be cancelled, or g_thread_pool_push() may
1708 : : * have failed.
1709 : : */
1710 [ + + ]: 3457 : if (task->thread_complete)
1711 : : {
1712 : 1 : g_mutex_unlock (&task->lock);
1713 : 1 : g_task_return (task, G_TASK_RETURN_FROM_THREAD);
1714 : : }
1715 : : else
1716 : 3456 : g_mutex_unlock (&task->lock);
1717 : :
1718 : 3457 : g_object_unref (task);
1719 : : }
1720 : :
1721 : : /**
1722 : : * g_task_run_in_thread_sync:
1723 : : * @task: a #GTask
1724 : : * @task_func: (scope async): a #GTaskThreadFunc
1725 : : *
1726 : : * Runs @task_func in another thread, and waits for it to return or be
1727 : : * cancelled. You can use g_task_propagate_pointer(), etc, afterward
1728 : : * to get the result of @task_func.
1729 : : *
1730 : : * See #GTaskThreadFunc for more details about how @task_func is handled.
1731 : : *
1732 : : * Normally this is used with tasks created with a %NULL
1733 : : * `callback`, but note that even if the task does
1734 : : * have a callback, it will not be invoked when @task_func returns.
1735 : : * #GTask:completed will be set to %TRUE just before this function returns.
1736 : : *
1737 : : * Although GLib currently rate-limits the tasks queued via
1738 : : * g_task_run_in_thread_sync(), you should not assume that it will
1739 : : * always do this. If you have a very large number of tasks to run,
1740 : : * but don't want them to all run at once, you should only queue a
1741 : : * limited number of them at a time.
1742 : : *
1743 : : * Since: 2.36
1744 : : */
1745 : : void
1746 : 6 : g_task_run_in_thread_sync (GTask *task,
1747 : : GTaskThreadFunc task_func)
1748 : : {
1749 : 6 : g_return_if_fail (G_IS_TASK (task));
1750 : :
1751 : 6 : g_object_ref (task);
1752 : :
1753 : 6 : task->synchronous = TRUE;
1754 : 6 : g_task_start_task_thread (task, task_func);
1755 : :
1756 [ + + ]: 11 : while (!task->thread_complete)
1757 : 5 : g_cond_wait (&task->cond, &task->lock);
1758 : :
1759 : 6 : g_mutex_unlock (&task->lock);
1760 : :
1761 : 6 : TRACE (GIO_TASK_BEFORE_RETURN (task, task->source_object,
1762 : : NULL /* callback */,
1763 : : NULL /* callback data */));
1764 : :
1765 : : /* Notify of completion in this thread. */
1766 : 6 : task->completed = TRUE;
1767 : 6 : g_object_notify (G_OBJECT (task), "completed");
1768 : :
1769 : 6 : g_object_unref (task);
1770 : : }
1771 : :
1772 : : /**
1773 : : * g_task_attach_source:
1774 : : * @task: a #GTask
1775 : : * @source: the source to attach
1776 : : * @callback: the callback to invoke when @source triggers
1777 : : *
1778 : : * A utility function for dealing with async operations where you need
1779 : : * to wait for a #GSource to trigger. Attaches @source to @task's
1780 : : * #GMainContext with @task's [priority](iface.AsyncResult.html#io-priority),
1781 : : * and sets @source's callback to @callback, with @task as the callback's
1782 : : * `user_data`.
1783 : : *
1784 : : * It will set the @source’s name to the task’s name (as set with
1785 : : * g_task_set_name()), if one has been set on the task and the source doesn’t
1786 : : * yet have a name.
1787 : : *
1788 : : * This takes a reference on @task until @source is destroyed.
1789 : : *
1790 : : * Since: 2.36
1791 : : */
1792 : : void
1793 : 110142 : g_task_attach_source (GTask *task,
1794 : : GSource *source,
1795 : : GSourceFunc callback)
1796 : : {
1797 : 110142 : g_return_if_fail (G_IS_TASK (task));
1798 : :
1799 : 110142 : g_source_set_callback (source, callback,
1800 : : g_object_ref (task), g_object_unref);
1801 : 110142 : g_source_set_priority (source, task->priority);
1802 [ + + + + ]: 110138 : if (task->name != NULL && g_source_get_name (source) == NULL)
1803 : 1 : g_source_set_name (source, task->name);
1804 : :
1805 : 110138 : g_source_attach (source, task->context);
1806 : : }
1807 : :
1808 : :
1809 : : static gboolean
1810 : 122332 : g_task_propagate_error (GTask *task,
1811 : : GError **error)
1812 : : {
1813 : : gboolean error_set;
1814 : :
1815 [ + + + + ]: 228486 : if (task->check_cancellable &&
1816 : 106154 : g_cancellable_set_error_if_cancelled (task->cancellable, error))
1817 : 437 : error_set = TRUE;
1818 [ + + ]: 121895 : else if (task->error)
1819 : : {
1820 : 882 : g_propagate_error (error, task->error);
1821 : 882 : task->error = NULL;
1822 : 882 : task->had_error = TRUE;
1823 : 882 : error_set = TRUE;
1824 : : }
1825 : : else
1826 : 121013 : error_set = FALSE;
1827 : :
1828 : 122332 : TRACE (GIO_TASK_PROPAGATE (task, error_set));
1829 : :
1830 : 122331 : return error_set;
1831 : : }
1832 : :
1833 : : /**
1834 : : * g_task_return_pointer:
1835 : : * @task: a #GTask
1836 : : * @result: (nullable) (transfer full): the pointer result of a task
1837 : : * function
1838 : : * @result_destroy: (nullable): a #GDestroyNotify function.
1839 : : *
1840 : : * Sets @task's result to @result and completes the task. If @result
1841 : : * is not %NULL, then @result_destroy will be used to free @result if
1842 : : * the caller does not take ownership of it with
1843 : : * g_task_propagate_pointer().
1844 : : *
1845 : : * "Completes the task" means that for an ordinary asynchronous task
1846 : : * it will either invoke the task's callback, or else queue that
1847 : : * callback to be invoked in the proper #GMainContext, or in the next
1848 : : * iteration of the current #GMainContext. For a task run via
1849 : : * g_task_run_in_thread() or g_task_run_in_thread_sync(), calling this
1850 : : * method will save @result to be returned to the caller later, but
1851 : : * the task will not actually be completed until the #GTaskThreadFunc
1852 : : * exits.
1853 : : *
1854 : : * Note that since the task may be completed before returning from
1855 : : * g_task_return_pointer(), you cannot assume that @result is still
1856 : : * valid after calling this, unless you are still holding another
1857 : : * reference on it.
1858 : : *
1859 : : * Since: 2.36
1860 : : */
1861 : : void
1862 : 7713 : g_task_return_pointer (GTask *task,
1863 : : gpointer result,
1864 : : GDestroyNotify result_destroy)
1865 : : {
1866 : 7713 : g_return_if_fail (G_IS_TASK (task));
1867 : 7713 : g_return_if_fail (!task->ever_returned);
1868 : :
1869 : 7713 : task->result.pointer = result;
1870 : 7713 : task->result_destroy = result_destroy;
1871 : :
1872 : 7713 : g_task_return (task, G_TASK_RETURN_SUCCESS);
1873 : : }
1874 : :
1875 : : /**
1876 : : * g_task_propagate_pointer:
1877 : : * @task: a #GTask
1878 : : * @error: return location for a #GError
1879 : : *
1880 : : * Gets the result of @task as a pointer, and transfers ownership
1881 : : * of that value to the caller.
1882 : : *
1883 : : * If the task resulted in an error, or was cancelled, then this will
1884 : : * instead return %NULL and set @error.
1885 : : *
1886 : : * Since this method transfers ownership of the return value (or
1887 : : * error) to the caller, you may only call it once.
1888 : : *
1889 : : * Returns: (transfer full): the task result, or %NULL on error
1890 : : *
1891 : : * Since: 2.36
1892 : : */
1893 : : gpointer
1894 : 8292 : g_task_propagate_pointer (GTask *task,
1895 : : GError **error)
1896 : : {
1897 : 8292 : g_return_val_if_fail (G_IS_TASK (task), NULL);
1898 : :
1899 [ + + ]: 8292 : if (g_task_propagate_error (task, error))
1900 : 589 : return NULL;
1901 : :
1902 : 7703 : g_return_val_if_fail (task->result_set, NULL);
1903 : :
1904 : 7703 : task->result_destroy = NULL;
1905 : 7703 : task->result_set = FALSE;
1906 : 7703 : return task->result.pointer;
1907 : : }
1908 : :
1909 : : /**
1910 : : * g_task_return_int:
1911 : : * @task: a #GTask.
1912 : : * @result: the integer (#gssize) result of a task function.
1913 : : *
1914 : : * Sets @task's result to @result and completes the task (see
1915 : : * g_task_return_pointer() for more discussion of exactly what this
1916 : : * means).
1917 : : *
1918 : : * Since: 2.36
1919 : : */
1920 : : void
1921 : 93242 : g_task_return_int (GTask *task,
1922 : : gssize result)
1923 : : {
1924 : 93242 : g_return_if_fail (G_IS_TASK (task));
1925 : 93242 : g_return_if_fail (!task->ever_returned);
1926 : :
1927 : 93242 : task->result.size = result;
1928 : :
1929 : 93242 : g_task_return (task, G_TASK_RETURN_SUCCESS);
1930 : : }
1931 : :
1932 : : /**
1933 : : * g_task_propagate_int:
1934 : : * @task: a #GTask.
1935 : : * @error: return location for a #GError
1936 : : *
1937 : : * Gets the result of @task as an integer (#gssize).
1938 : : *
1939 : : * If the task resulted in an error, or was cancelled, then this will
1940 : : * instead return -1 and set @error.
1941 : : *
1942 : : * Since this method transfers ownership of the return value (or
1943 : : * error) to the caller, you may only call it once.
1944 : : *
1945 : : * Returns: the task result, or -1 on error
1946 : : *
1947 : : * Since: 2.36
1948 : : */
1949 : : gssize
1950 : 93620 : g_task_propagate_int (GTask *task,
1951 : : GError **error)
1952 : : {
1953 : 93620 : g_return_val_if_fail (G_IS_TASK (task), -1);
1954 : :
1955 [ + + ]: 93620 : if (g_task_propagate_error (task, error))
1956 : 410 : return -1;
1957 : :
1958 : 93210 : g_return_val_if_fail (task->result_set, -1);
1959 : :
1960 : 93210 : task->result_set = FALSE;
1961 : 93210 : return task->result.size;
1962 : : }
1963 : :
1964 : : /**
1965 : : * g_task_return_boolean:
1966 : : * @task: a #GTask.
1967 : : * @result: the #gboolean result of a task function.
1968 : : *
1969 : : * Sets @task's result to @result and completes the task (see
1970 : : * g_task_return_pointer() for more discussion of exactly what this
1971 : : * means).
1972 : : *
1973 : : * Since: 2.36
1974 : : */
1975 : : void
1976 : 20493 : g_task_return_boolean (GTask *task,
1977 : : gboolean result)
1978 : : {
1979 : 20493 : g_return_if_fail (G_IS_TASK (task));
1980 : 20493 : g_return_if_fail (!task->ever_returned);
1981 : :
1982 : 20493 : task->result.boolean = result;
1983 : :
1984 : 20493 : g_task_return (task, G_TASK_RETURN_SUCCESS);
1985 : : }
1986 : :
1987 : : /**
1988 : : * g_task_propagate_boolean:
1989 : : * @task: a #GTask.
1990 : : * @error: return location for a #GError
1991 : : *
1992 : : * Gets the result of @task as a #gboolean.
1993 : : *
1994 : : * If the task resulted in an error, or was cancelled, then this will
1995 : : * instead return %FALSE and set @error.
1996 : : *
1997 : : * Since this method transfers ownership of the return value (or
1998 : : * error) to the caller, you may only call it once.
1999 : : *
2000 : : * Returns: the task result, or %FALSE on error
2001 : : *
2002 : : * Since: 2.36
2003 : : */
2004 : : gboolean
2005 : 20425 : g_task_propagate_boolean (GTask *task,
2006 : : GError **error)
2007 : : {
2008 : 20425 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
2009 : :
2010 [ + + ]: 20425 : if (g_task_propagate_error (task, error))
2011 : 320 : return FALSE;
2012 : :
2013 : 20105 : g_return_val_if_fail (task->result_set, FALSE);
2014 : :
2015 : 20105 : task->result_set = FALSE;
2016 : 20105 : return task->result.boolean;
2017 : : }
2018 : :
2019 : : /**
2020 : : * g_task_return_error:
2021 : : * @task: a #GTask.
2022 : : * @error: (transfer full): the #GError result of a task function.
2023 : : *
2024 : : * Sets @task's result to @error (which @task assumes ownership of)
2025 : : * and completes the task (see g_task_return_pointer() for more
2026 : : * discussion of exactly what this means).
2027 : : *
2028 : : * Note that since the task takes ownership of @error, and since the
2029 : : * task may be completed before returning from g_task_return_error(),
2030 : : * you cannot assume that @error is still valid after calling this.
2031 : : * Call g_error_copy() on the error if you need to keep a local copy
2032 : : * as well.
2033 : : *
2034 : : * See also [method@Gio.Task.return_new_error],
2035 : : * [method@Gio.Task.return_new_error_literal].
2036 : : *
2037 : : * Since: 2.36
2038 : : */
2039 : : void
2040 : 2239 : g_task_return_error (GTask *task,
2041 : : GError *error)
2042 : : {
2043 : 2239 : g_return_if_fail (G_IS_TASK (task));
2044 : 2239 : g_return_if_fail (!task->ever_returned);
2045 : 2239 : g_return_if_fail (error != NULL);
2046 : :
2047 : 2239 : task->error = error;
2048 : :
2049 : 2239 : g_task_return (task, G_TASK_RETURN_ERROR);
2050 : : }
2051 : :
2052 : : /**
2053 : : * g_task_return_prefixed_error:
2054 : : * @task: a #GTask.
2055 : : * @error: (transfer full): the #GError result of a task function.
2056 : : * @format: a string with format characters.
2057 : : * @...: a list of values to insert into @format.
2058 : : *
2059 : : * Sets @task's result to @error (which @task assumes ownership of), with
2060 : : * the message prefixed according to @format, and completes the task
2061 : : * (see g_task_return_pointer() for more discussion of exactly what this
2062 : : * means).
2063 : : *
2064 : : * Note that since the task takes ownership of @error, and since the
2065 : : * task may be completed before returning from g_task_return_prefixed_error(),
2066 : : * you cannot assume that @error is still valid after calling this.
2067 : : * Call g_error_copy() on the error if you need to keep a local copy
2068 : : * as well.
2069 : : *
2070 : : * See also g_task_return_error(), g_prefix_error().
2071 : : *
2072 : : * Since: 2.80
2073 : : */
2074 : : void
2075 : 1 : g_task_return_prefixed_error (GTask *task,
2076 : : GError *error,
2077 : : const char *format,
2078 : : ...)
2079 : : {
2080 : : char *prefix;
2081 : : va_list ap;
2082 : :
2083 : 1 : g_return_if_fail (G_IS_TASK (task));
2084 : 1 : g_return_if_fail (!task->ever_returned);
2085 : 1 : g_return_if_fail (error != NULL);
2086 : :
2087 : 1 : task->error = error;
2088 : :
2089 : 1 : va_start (ap, format);
2090 : 1 : prefix = g_strdup_vprintf (format, ap);
2091 : 1 : va_end (ap);
2092 : :
2093 : 1 : g_prefix_error_literal (&task->error, prefix);
2094 : :
2095 : 1 : g_free (prefix);
2096 : :
2097 : 1 : g_task_return (task, G_TASK_RETURN_ERROR);
2098 : : }
2099 : :
2100 : : /**
2101 : : * g_task_return_new_error:
2102 : : * @task: a #GTask.
2103 : : * @domain: a #GQuark.
2104 : : * @code: an error code.
2105 : : * @format: a string with format characters.
2106 : : * @...: a list of values to insert into @format.
2107 : : *
2108 : : * Sets @task's result to a new #GError created from @domain, @code,
2109 : : * @format, and the remaining arguments, and completes the task (see
2110 : : * g_task_return_pointer() for more discussion of exactly what this
2111 : : * means).
2112 : : *
2113 : : * See also g_task_return_error().
2114 : : *
2115 : : * Since: 2.36
2116 : : */
2117 : : void
2118 : 16 : g_task_return_new_error (GTask *task,
2119 : : GQuark domain,
2120 : : gint code,
2121 : : const char *format,
2122 : : ...)
2123 : : {
2124 : : GError *error;
2125 : : va_list args;
2126 : :
2127 : 16 : va_start (args, format);
2128 : 16 : error = g_error_new_valist (domain, code, format, args);
2129 : 16 : va_end (args);
2130 : :
2131 : 16 : g_task_return_error (task, error);
2132 : 16 : }
2133 : :
2134 : : /**
2135 : : * g_task_return_new_error_literal:
2136 : : * @task: a #GTask.
2137 : : * @domain: a #GQuark.
2138 : : * @code: an error code.
2139 : : * @message: an error message
2140 : : *
2141 : : * Sets @task’s result to a new [type@GLib.Error] created from @domain, @code,
2142 : : * @message and completes the task.
2143 : : *
2144 : : * See [method@Gio.Task.return_pointer] for more discussion of exactly what
2145 : : * ‘completing the task’ means.
2146 : : *
2147 : : * See also [method@Gio.Task.return_new_error].
2148 : : *
2149 : : * Since: 2.80
2150 : : */
2151 : : void
2152 : 154 : g_task_return_new_error_literal (GTask *task,
2153 : : GQuark domain,
2154 : : gint code,
2155 : : const char *message)
2156 : : {
2157 : 154 : g_task_return_error (task, g_error_new_literal (domain, code, message));
2158 : 154 : }
2159 : :
2160 : : /**
2161 : : * g_task_return_error_if_cancelled:
2162 : : * @task: a #GTask
2163 : : *
2164 : : * Checks if @task's #GCancellable has been cancelled, and if so, sets
2165 : : * @task's error accordingly and completes the task (see
2166 : : * g_task_return_pointer() for more discussion of exactly what this
2167 : : * means).
2168 : : *
2169 : : * Returns: %TRUE if @task has been cancelled, %FALSE if not
2170 : : *
2171 : : * Since: 2.36
2172 : : */
2173 : : gboolean
2174 : 44233 : g_task_return_error_if_cancelled (GTask *task)
2175 : : {
2176 : 44233 : GError *error = NULL;
2177 : :
2178 : 44233 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
2179 : 44233 : g_return_val_if_fail (!task->ever_returned, FALSE);
2180 : :
2181 [ + + ]: 44233 : if (g_cancellable_set_error_if_cancelled (task->cancellable, &error))
2182 : : {
2183 : : /* We explicitly set task->error so this works even when
2184 : : * check-cancellable is not set.
2185 : : */
2186 : 1244 : g_clear_error (&task->error);
2187 : 1245 : task->error = error;
2188 : :
2189 : 1245 : g_task_return (task, G_TASK_RETURN_ERROR);
2190 : 1245 : return TRUE;
2191 : : }
2192 : : else
2193 : 42988 : return FALSE;
2194 : : }
2195 : :
2196 : : /**
2197 : : * g_task_had_error:
2198 : : * @task: a #GTask.
2199 : : *
2200 : : * Tests if @task resulted in an error.
2201 : : *
2202 : : * Returns: %TRUE if the task resulted in an error, %FALSE otherwise.
2203 : : *
2204 : : * Since: 2.36
2205 : : */
2206 : : gboolean
2207 : 382 : g_task_had_error (GTask *task)
2208 : : {
2209 : 382 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
2210 : :
2211 [ + + + + ]: 382 : if (task->error != NULL || task->had_error)
2212 : 15 : return TRUE;
2213 : :
2214 [ + - + + ]: 367 : if (task->check_cancellable && g_cancellable_is_cancelled (task->cancellable))
2215 : 18 : return TRUE;
2216 : :
2217 : 349 : return FALSE;
2218 : : }
2219 : :
2220 : : static void
2221 : 0 : value_free (gpointer value)
2222 : : {
2223 : 0 : g_value_unset (value);
2224 : 0 : g_free (value);
2225 : 0 : }
2226 : :
2227 : : /**
2228 : : * g_task_return_value:
2229 : : * @task: a #GTask
2230 : : * @result: (nullable) (transfer none): the #GValue result of
2231 : : * a task function
2232 : : *
2233 : : * Sets @task's result to @result (by copying it) and completes the task.
2234 : : *
2235 : : * If @result is %NULL then a #GValue of type %G_TYPE_POINTER
2236 : : * with a value of %NULL will be used for the result.
2237 : : *
2238 : : * This is a very generic low-level method intended primarily for use
2239 : : * by language bindings; for C code, g_task_return_pointer() and the
2240 : : * like will normally be much easier to use.
2241 : : *
2242 : : * Since: 2.64
2243 : : */
2244 : : void
2245 : 1 : g_task_return_value (GTask *task,
2246 : : GValue *result)
2247 : : {
2248 : : GValue *value;
2249 : :
2250 : 1 : g_return_if_fail (G_IS_TASK (task));
2251 : 1 : g_return_if_fail (!task->ever_returned);
2252 : :
2253 : 1 : value = g_new0 (GValue, 1);
2254 : :
2255 [ - + ]: 1 : if (result == NULL)
2256 : : {
2257 : 0 : g_value_init (value, G_TYPE_POINTER);
2258 : 0 : g_value_set_pointer (value, NULL);
2259 : : }
2260 : : else
2261 : : {
2262 : 1 : g_value_init (value, G_VALUE_TYPE (result));
2263 : 1 : g_value_copy (result, value);
2264 : : }
2265 : :
2266 : 1 : g_task_return_pointer (task, value, value_free);
2267 : : }
2268 : :
2269 : : /**
2270 : : * g_task_propagate_value:
2271 : : * @task: a #GTask
2272 : : * @value: (out caller-allocates): return location for the #GValue
2273 : : * @error: return location for a #GError
2274 : : *
2275 : : * Gets the result of @task as a #GValue, and transfers ownership of
2276 : : * that value to the caller. As with g_task_return_value(), this is
2277 : : * a generic low-level method; g_task_propagate_pointer() and the like
2278 : : * will usually be more useful for C code.
2279 : : *
2280 : : * If the task resulted in an error, or was cancelled, then this will
2281 : : * instead set @error and return %FALSE.
2282 : : *
2283 : : * Since this method transfers ownership of the return value (or
2284 : : * error) to the caller, you may only call it once.
2285 : : *
2286 : : * Returns: %TRUE if @task succeeded, %FALSE on error.
2287 : : *
2288 : : * Since: 2.64
2289 : : */
2290 : : gboolean
2291 : 1 : g_task_propagate_value (GTask *task,
2292 : : GValue *value,
2293 : : GError **error)
2294 : : {
2295 : 1 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
2296 : 1 : g_return_val_if_fail (value != NULL, FALSE);
2297 : 1 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2298 : :
2299 [ - + ]: 1 : if (g_task_propagate_error (task, error))
2300 : 0 : return FALSE;
2301 : :
2302 : 1 : g_return_val_if_fail (task->result_set, FALSE);
2303 : 1 : g_return_val_if_fail (task->result_destroy == value_free, FALSE);
2304 : :
2305 : 1 : memcpy (value, task->result.pointer, sizeof (GValue));
2306 : 1 : g_free (task->result.pointer);
2307 : :
2308 : 1 : task->result_destroy = NULL;
2309 : 1 : task->result_set = FALSE;
2310 : :
2311 : 1 : return TRUE;
2312 : : }
2313 : :
2314 : : /**
2315 : : * g_task_get_completed:
2316 : : * @task: a #GTask.
2317 : : *
2318 : : * Gets the value of #GTask:completed. This changes from %FALSE to %TRUE after
2319 : : * the task’s callback is invoked, and will return %FALSE if called from inside
2320 : : * the callback.
2321 : : *
2322 : : * Returns: %TRUE if the task has completed, %FALSE otherwise.
2323 : : *
2324 : : * Since: 2.44
2325 : : */
2326 : : gboolean
2327 : 67 : g_task_get_completed (GTask *task)
2328 : : {
2329 : 67 : g_return_val_if_fail (G_IS_TASK (task), FALSE);
2330 : :
2331 : : /* Convert from a bit field to a boolean. */
2332 : 67 : return task->completed ? TRUE : FALSE;
2333 : : }
2334 : :
2335 : : /**
2336 : : * g_task_is_valid:
2337 : : * @result: (type Gio.AsyncResult): A #GAsyncResult
2338 : : * @source_object: (nullable) (type GObject): the source object
2339 : : * expected to be associated with the task
2340 : : *
2341 : : * Checks that @result is a #GTask, and that @source_object is its
2342 : : * source object (or that @source_object is %NULL and @result has no
2343 : : * source object). This can be used in g_return_if_fail() checks.
2344 : : *
2345 : : * Returns: %TRUE if @result and @source_object are valid, %FALSE
2346 : : * if not
2347 : : *
2348 : : * Since: 2.36
2349 : : */
2350 : : gboolean
2351 : 120692 : g_task_is_valid (gpointer result,
2352 : : gpointer source_object)
2353 : : {
2354 [ - + + - : 120692 : if (!G_IS_TASK (result))
+ + + + ]
2355 : 1 : return FALSE;
2356 : :
2357 : 120691 : return G_TASK (result)->source_object == source_object;
2358 : : }
2359 : :
2360 : : static gint
2361 : 1484 : g_task_compare_priority (gconstpointer a,
2362 : : gconstpointer b,
2363 : : gpointer user_data)
2364 : : {
2365 : 1484 : const GTask *ta = a;
2366 : 1484 : const GTask *tb = b;
2367 : : gboolean a_cancelled, b_cancelled;
2368 : :
2369 : : /* Tasks that are causing other tasks to block have higher
2370 : : * priority.
2371 : : */
2372 [ - + - - ]: 1484 : if (ta->blocking_other_task && !tb->blocking_other_task)
2373 : 0 : return -1;
2374 [ - + - - ]: 1484 : else if (tb->blocking_other_task && !ta->blocking_other_task)
2375 : 0 : return 1;
2376 : :
2377 : : /* Let already-cancelled tasks finish right away */
2378 [ + + + + ]: 2666 : a_cancelled = (ta->check_cancellable &&
2379 : 1182 : g_cancellable_is_cancelled (ta->cancellable));
2380 [ + + - + ]: 2934 : b_cancelled = (tb->check_cancellable &&
2381 : 1450 : g_cancellable_is_cancelled (tb->cancellable));
2382 [ + + + - ]: 1484 : if (a_cancelled && !b_cancelled)
2383 : 6 : return -1;
2384 [ - + - - ]: 1478 : else if (b_cancelled && !a_cancelled)
2385 : 0 : return 1;
2386 : :
2387 : : /* Lower priority == run sooner == negative return value */
2388 : 1478 : return ta->priority - tb->priority;
2389 : : }
2390 : :
2391 : : static gboolean
2392 : 6 : trivial_source_dispatch (GSource *source,
2393 : : GSourceFunc callback,
2394 : : gpointer user_data)
2395 : : {
2396 : 6 : return callback (user_data);
2397 : : }
2398 : :
2399 : : GSourceFuncs trivial_source_funcs = {
2400 : : NULL, /* prepare */
2401 : : NULL, /* check */
2402 : : trivial_source_dispatch,
2403 : : NULL, /* finalize */
2404 : : NULL, /* closure */
2405 : : NULL /* marshal */
2406 : : };
2407 : :
2408 : : static void
2409 : 162 : g_task_thread_pool_init (void)
2410 : : {
2411 : 162 : task_pool = g_thread_pool_new (g_task_thread_pool_thread, NULL,
2412 : : G_TASK_POOL_SIZE, FALSE, NULL);
2413 : 162 : g_assert (task_pool != NULL);
2414 : :
2415 : 162 : g_thread_pool_set_sort_function (task_pool, g_task_compare_priority, NULL);
2416 : :
2417 : 162 : task_pool_manager = g_source_new (&trivial_source_funcs, sizeof (GSource));
2418 : 162 : g_source_set_static_name (task_pool_manager, "GTask thread pool manager");
2419 : 162 : g_source_set_callback (task_pool_manager, task_pool_manager_timeout, NULL, NULL);
2420 : 162 : g_source_set_ready_time (task_pool_manager, -1);
2421 : 162 : g_source_attach (task_pool_manager,
2422 : 162 : GLIB_PRIVATE_CALL (g_get_worker_context ()));
2423 : 162 : g_source_unref (task_pool_manager);
2424 : 162 : }
2425 : :
2426 : : static void
2427 : 10 : g_task_get_property (GObject *object,
2428 : : guint prop_id,
2429 : : GValue *value,
2430 : : GParamSpec *pspec)
2431 : : {
2432 : 10 : GTask *task = G_TASK (object);
2433 : :
2434 [ + - ]: 10 : switch ((GTaskProperty) prop_id)
2435 : : {
2436 : 10 : case PROP_COMPLETED:
2437 : 10 : g_value_set_boolean (value, g_task_get_completed (task));
2438 : 10 : break;
2439 : : }
2440 : 10 : }
2441 : :
2442 : : static void
2443 : 162 : g_task_class_init (GTaskClass *klass)
2444 : : {
2445 : 162 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2446 : :
2447 : : #ifdef G_ENABLE_DEBUG
2448 : 162 : gobject_class->constructed = g_task_constructed;
2449 : : #endif
2450 : 162 : gobject_class->get_property = g_task_get_property;
2451 : 162 : gobject_class->finalize = g_task_finalize;
2452 : :
2453 : : /**
2454 : : * GTask:completed:
2455 : : *
2456 : : * Whether the task has completed, meaning its callback (if set) has been
2457 : : * invoked.
2458 : : *
2459 : : * This can only happen after g_task_return_pointer(),
2460 : : * g_task_return_error() or one of the other return functions have been called
2461 : : * on the task. However, it is not guaranteed to happen immediately after
2462 : : * those functions are called, as the task’s callback may need to be scheduled
2463 : : * to run in a different thread.
2464 : : *
2465 : : * That means it is **not safe** to use this property to track whether a
2466 : : * return function has been called on the #GTask. Callers must do that
2467 : : * tracking themselves, typically by linking the lifetime of the #GTask to the
2468 : : * control flow of their code.
2469 : : *
2470 : : * This property is guaranteed to change from %FALSE to %TRUE exactly once.
2471 : : *
2472 : : * The #GObject::notify signal for this change is emitted in the same main
2473 : : * context as the task’s callback, immediately after that callback is invoked.
2474 : : *
2475 : : * Since: 2.44
2476 : : */
2477 : 162 : g_object_class_install_property (gobject_class, PROP_COMPLETED,
2478 : : g_param_spec_boolean ("completed", NULL, NULL,
2479 : : FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
2480 : :
2481 [ + - ]: 162 : if (G_UNLIKELY (task_pool_max_counter == 0))
2482 : : {
2483 : : /* We use two counters to track characteristics of the GTask thread pool.
2484 : : * task pool max size - the value of g_thread_pool_set_max_threads()
2485 : : * tasks running - the number of running threads
2486 : : */
2487 : 162 : 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()");
2488 : 162 : tasks_running_counter = g_trace_define_int64_counter ("GIO", "tasks running", "Number of currently running tasks in the GTask thread pool");
2489 : : }
2490 : 162 : }
2491 : :
2492 : : static gpointer
2493 : 45 : g_task_get_user_data (GAsyncResult *res)
2494 : : {
2495 : 45 : return G_TASK (res)->callback_data;
2496 : : }
2497 : :
2498 : : static gboolean
2499 : 32839 : g_task_is_tagged (GAsyncResult *res,
2500 : : gpointer source_tag)
2501 : : {
2502 : 32839 : return G_TASK (res)->source_tag == source_tag;
2503 : : }
2504 : :
2505 : : static void
2506 : 162 : g_task_async_result_iface_init (GAsyncResultIface *iface)
2507 : : {
2508 : 162 : iface->get_user_data = g_task_get_user_data;
2509 : 162 : iface->get_source_object = g_task_ref_source_object;
2510 : 162 : iface->is_tagged = g_task_is_tagged;
2511 : 162 : }
|