Coverage Report

Created: 2026-07-16 06:32

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