1/*
2 * Copyright 2012-2019 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * See the included COPYING file for more information.
10 */
11
12#include <gio/gio.h>
13#include <string.h>
14
15static GMainLoop *loop;
16static GThread *main_thread;
17static gssize magic;
18
19/* We need objects for a few tests where we don't care what type
20 * they are, just that they're GObjects.
21 */
22#define g_dummy_object_new g_socket_client_new
23
24static gboolean
25idle_quit_loop (gpointer user_data)
26{
27 g_main_loop_quit (loop);
28 return FALSE;
29}
30
31static void
32completed_cb (GObject *gobject,
33 GParamSpec *pspec,
34 gpointer user_data)
35{
36 gboolean *notification_emitted = user_data;
37 *notification_emitted = TRUE;
38}
39
40static void
41wait_for_completed_notification (GTask *task)
42{
43 gboolean notification_emitted = FALSE;
44 gboolean is_completed = FALSE;
45
46 /* Hold a ref. so we can check the :completed property afterwards. */
47 g_object_ref (task);
48
49 g_signal_connect (task, "notify::completed",
50 (GCallback) completed_cb, &notification_emitted);
51 g_idle_add (function: idle_quit_loop, NULL);
52 g_main_loop_run (loop);
53 g_assert_true (notification_emitted);
54
55 g_assert_true (g_task_get_completed (task));
56 g_object_get (G_OBJECT (task), first_property_name: "completed", &is_completed, NULL);
57 g_assert_true (is_completed);
58
59 g_object_unref (object: task);
60}
61
62/* test_basic */
63
64static void
65basic_callback (GObject *object,
66 GAsyncResult *result,
67 gpointer user_data)
68{
69 gssize *result_out = user_data;
70 GError *error = NULL;
71
72 g_assert (object == NULL);
73 g_assert (g_task_is_valid (result, object));
74 g_assert (g_async_result_get_user_data (result) == user_data);
75 g_assert (!g_task_had_error (G_TASK (result)));
76 g_assert_false (g_task_get_completed (G_TASK (result)));
77
78 *result_out = g_task_propagate_int (G_TASK (result), error: &error);
79 g_assert_no_error (error);
80
81 g_assert (!g_task_had_error (G_TASK (result)));
82
83 g_main_loop_quit (loop);
84}
85
86static gboolean
87basic_return (gpointer user_data)
88{
89 GTask *task = user_data;
90
91 g_task_return_int (task, result: magic);
92 g_object_unref (object: task);
93
94 return FALSE;
95}
96
97static void
98basic_destroy_notify (gpointer user_data)
99{
100 gboolean *destroyed = user_data;
101
102 *destroyed = TRUE;
103}
104
105static void
106test_basic (void)
107{
108 GTask *task;
109 gssize result;
110 gboolean task_data_destroyed = FALSE;
111 gboolean notification_emitted = FALSE;
112
113 task = g_task_new (NULL, NULL, callback: basic_callback, callback_data: &result);
114 g_task_set_task_data (task, task_data: &task_data_destroyed, task_data_destroy: basic_destroy_notify);
115 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
116 g_signal_connect (task, "notify::completed",
117 (GCallback) completed_cb, &notification_emitted);
118
119 g_idle_add (function: basic_return, data: task);
120 g_main_loop_run (loop);
121
122 g_assert_cmpint (result, ==, magic);
123 g_assert (task_data_destroyed == TRUE);
124 g_assert_true (notification_emitted);
125 g_assert (task == NULL);
126}
127
128/* test_error */
129
130static void
131error_callback (GObject *object,
132 GAsyncResult *result,
133 gpointer user_data)
134{
135 gssize *result_out = user_data;
136 GError *error = NULL;
137
138 g_assert (object == NULL);
139 g_assert (g_task_is_valid (result, object));
140 g_assert (g_async_result_get_user_data (result) == user_data);
141 g_assert (g_task_had_error (G_TASK (result)));
142 g_assert_false (g_task_get_completed (G_TASK (result)));
143
144 *result_out = g_task_propagate_int (G_TASK (result), error: &error);
145 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
146 g_error_free (error);
147
148 g_assert (g_task_had_error (G_TASK (result)));
149
150 g_main_loop_quit (loop);
151}
152
153static gboolean
154error_return (gpointer user_data)
155{
156 GTask *task = user_data;
157
158 g_task_return_new_error (task,
159 G_IO_ERROR, code: G_IO_ERROR_FAILED,
160 format: "Failed");
161 g_object_unref (object: task);
162
163 return FALSE;
164}
165
166static void
167error_destroy_notify (gpointer user_data)
168{
169 gboolean *destroyed = user_data;
170
171 *destroyed = TRUE;
172}
173
174static void
175test_error (void)
176{
177 GTask *task;
178 gssize result;
179 gboolean first_task_data_destroyed = FALSE;
180 gboolean second_task_data_destroyed = FALSE;
181 gboolean notification_emitted = FALSE;
182
183 task = g_task_new (NULL, NULL, callback: error_callback, callback_data: &result);
184 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
185 g_signal_connect (task, "notify::completed",
186 (GCallback) completed_cb, &notification_emitted);
187
188 g_assert (first_task_data_destroyed == FALSE);
189 g_task_set_task_data (task, task_data: &first_task_data_destroyed, task_data_destroy: error_destroy_notify);
190 g_assert (first_task_data_destroyed == FALSE);
191
192 /* Calling g_task_set_task_data() again will destroy the first data */
193 g_task_set_task_data (task, task_data: &second_task_data_destroyed, task_data_destroy: error_destroy_notify);
194 g_assert (first_task_data_destroyed == TRUE);
195 g_assert (second_task_data_destroyed == FALSE);
196
197 g_idle_add (function: error_return, data: task);
198 g_main_loop_run (loop);
199
200 g_assert_cmpint (result, ==, -1);
201 g_assert (second_task_data_destroyed == TRUE);
202 g_assert_true (notification_emitted);
203 g_assert (task == NULL);
204}
205
206/* test_return_from_same_iteration: calling g_task_return_* from the
207 * loop iteration the task was created in defers completion until the
208 * next iteration.
209 */
210gboolean same_result = FALSE;
211gboolean same_notification_emitted = FALSE;
212
213static void
214same_callback (GObject *object,
215 GAsyncResult *result,
216 gpointer user_data)
217{
218 gboolean *result_out = user_data;
219 GError *error = NULL;
220
221 g_assert (object == NULL);
222 g_assert (g_task_is_valid (result, object));
223 g_assert (g_async_result_get_user_data (result) == user_data);
224 g_assert (!g_task_had_error (G_TASK (result)));
225 g_assert_false (g_task_get_completed (G_TASK (result)));
226
227 *result_out = g_task_propagate_boolean (G_TASK (result), error: &error);
228 g_assert_no_error (error);
229
230 g_assert (!g_task_had_error (G_TASK (result)));
231
232 g_main_loop_quit (loop);
233}
234
235static gboolean
236same_start (gpointer user_data)
237{
238 gpointer *weak_pointer = user_data;
239 GTask *task;
240
241 task = g_task_new (NULL, NULL, callback: same_callback, callback_data: &same_result);
242 *weak_pointer = task;
243 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: weak_pointer);
244 g_signal_connect (task, "notify::completed",
245 (GCallback) completed_cb, &same_notification_emitted);
246
247 g_task_return_boolean (task, TRUE);
248 g_object_unref (object: task);
249
250 /* same_callback should not have been invoked yet */
251 g_assert (same_result == FALSE);
252 g_assert (*weak_pointer == task);
253 g_assert_false (same_notification_emitted);
254
255 return FALSE;
256}
257
258static void
259test_return_from_same_iteration (void)
260{
261 gpointer weak_pointer;
262
263 g_idle_add (function: same_start, data: &weak_pointer);
264 g_main_loop_run (loop);
265
266 g_assert (same_result == TRUE);
267 g_assert (weak_pointer == NULL);
268 g_assert_true (same_notification_emitted);
269}
270
271/* test_return_from_toplevel: calling g_task_return_* from outside any
272 * main loop completes the task inside the main loop.
273 */
274gboolean toplevel_notification_emitted = FALSE;
275
276static void
277toplevel_callback (GObject *object,
278 GAsyncResult *result,
279 gpointer user_data)
280{
281 gboolean *result_out = user_data;
282 GError *error = NULL;
283
284 g_assert (object == NULL);
285 g_assert (g_task_is_valid (result, object));
286 g_assert (g_async_result_get_user_data (result) == user_data);
287 g_assert (!g_task_had_error (G_TASK (result)));
288 g_assert_false (g_task_get_completed (G_TASK (result)));
289
290 *result_out = g_task_propagate_boolean (G_TASK (result), error: &error);
291 g_assert_no_error (error);
292
293 g_assert (!g_task_had_error (G_TASK (result)));
294
295 g_main_loop_quit (loop);
296}
297
298static void
299test_return_from_toplevel (void)
300{
301 GTask *task;
302 gboolean result = FALSE;
303
304 task = g_task_new (NULL, NULL, callback: toplevel_callback, callback_data: &result);
305 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
306 g_signal_connect (task, "notify::completed",
307 (GCallback) completed_cb, &toplevel_notification_emitted);
308
309 g_task_return_boolean (task, TRUE);
310 g_object_unref (object: task);
311
312 /* toplevel_callback should not have been invoked yet */
313 g_assert (result == FALSE);
314 g_assert (task != NULL);
315 g_assert_false (toplevel_notification_emitted);
316
317 g_main_loop_run (loop);
318
319 g_assert (result == TRUE);
320 g_assert (task == NULL);
321 g_assert_true (toplevel_notification_emitted);
322}
323
324/* test_return_from_anon_thread: calling g_task_return_* from a
325 * thread with no thread-default main context will complete the
326 * task in the task's context/thread.
327 */
328
329gboolean anon_thread_notification_emitted = FALSE;
330GThread *anon_thread;
331
332static void
333anon_callback (GObject *object,
334 GAsyncResult *result,
335 gpointer user_data)
336{
337 gssize *result_out = user_data;
338 GError *error = NULL;
339
340 g_assert (object == NULL);
341 g_assert (g_task_is_valid (result, object));
342 g_assert (g_async_result_get_user_data (result) == user_data);
343 g_assert (!g_task_had_error (G_TASK (result)));
344 g_assert_false (g_task_get_completed (G_TASK (result)));
345
346 g_assert (g_thread_self () == main_thread);
347
348 *result_out = g_task_propagate_int (G_TASK (result), error: &error);
349 g_assert_no_error (error);
350
351 g_assert (!g_task_had_error (G_TASK (result)));
352
353 g_main_loop_quit (loop);
354}
355
356static gpointer
357anon_thread_func (gpointer user_data)
358{
359 GTask *task = user_data;
360
361 g_task_return_int (task, result: magic);
362 g_object_unref (object: task);
363
364 return NULL;
365}
366
367static gboolean
368anon_start (gpointer user_data)
369{
370 GTask *task = user_data;
371
372 anon_thread = g_thread_new (name: "test_return_from_anon_thread",
373 func: anon_thread_func, data: task);
374 return FALSE;
375}
376
377static void
378test_return_from_anon_thread (void)
379{
380 GTask *task;
381 gssize result = 0;
382
383 task = g_task_new (NULL, NULL, callback: anon_callback, callback_data: &result);
384 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
385 g_signal_connect (task, "notify::completed",
386 (GCallback) completed_cb,
387 &anon_thread_notification_emitted);
388
389 g_idle_add (function: anon_start, data: task);
390 g_main_loop_run (loop);
391
392 g_thread_join (thread: anon_thread);
393
394 g_assert_cmpint (result, ==, magic);
395 g_assert (task == NULL);
396 g_assert_true (anon_thread_notification_emitted);
397}
398
399/* test_return_from_wrong_thread: calling g_task_return_* from a
400 * thread with its own thread-default main context will complete the
401 * task in the task's context/thread.
402 */
403
404gboolean wrong_thread_notification_emitted = FALSE;
405GThread *wrong_thread;
406
407static void
408wrong_callback (GObject *object,
409 GAsyncResult *result,
410 gpointer user_data)
411{
412 gssize *result_out = user_data;
413 GError *error = NULL;
414
415 g_assert (object == NULL);
416 g_assert (g_task_is_valid (result, object));
417 g_assert (g_async_result_get_user_data (result) == user_data);
418 g_assert (!g_task_had_error (G_TASK (result)));
419 g_assert_false (g_task_get_completed (G_TASK (result)));
420
421 g_assert (g_thread_self () == main_thread);
422
423 *result_out = g_task_propagate_int (G_TASK (result), error: &error);
424 g_assert_no_error (error);
425
426 g_assert (!g_task_had_error (G_TASK (result)));
427
428 g_main_loop_quit (loop);
429}
430
431static gpointer
432wrong_thread_func (gpointer user_data)
433{
434 GTask *task = user_data;
435 GMainContext *context;
436
437 context = g_main_context_new ();
438 g_main_context_push_thread_default (context);
439
440 g_assert (g_task_get_context (task) != context);
441
442 g_task_return_int (task, result: magic);
443 g_object_unref (object: task);
444
445 g_main_context_pop_thread_default (context);
446 g_main_context_unref (context);
447
448 return NULL;
449}
450
451static gboolean
452wrong_start (gpointer user_data)
453{
454 GTask *task = user_data;
455
456 wrong_thread = g_thread_new (name: "test_return_from_anon_thread",
457 func: wrong_thread_func, data: task);
458 return FALSE;
459}
460
461static void
462test_return_from_wrong_thread (void)
463{
464 GTask *task;
465 gssize result = 0;
466
467 task = g_task_new (NULL, NULL, callback: wrong_callback, callback_data: &result);
468 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
469 g_signal_connect (task, "notify::completed",
470 (GCallback) completed_cb,
471 &wrong_thread_notification_emitted);
472
473 g_idle_add (function: wrong_start, data: task);
474 g_main_loop_run (loop);
475
476 g_thread_join (thread: wrong_thread);
477
478 g_assert_cmpint (result, ==, magic);
479 g_assert (task == NULL);
480 g_assert_true (wrong_thread_notification_emitted);
481}
482
483/* test_no_callback */
484
485static void
486test_no_callback (void)
487{
488 GTask *task;
489
490 task = g_task_new (NULL, NULL, NULL, NULL);
491 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
492
493 g_task_return_boolean (task, TRUE);
494 g_object_unref (object: task);
495
496 /* Even though there’s no callback, the :completed notification has to
497 * happen in an idle handler. */
498 g_assert_nonnull (task);
499 wait_for_completed_notification (task);
500 g_assert_null (task);
501}
502
503/* test_report_error */
504
505static void test_report_error (void);
506gboolean error_notification_emitted = FALSE;
507
508static void
509report_callback (GObject *object,
510 GAsyncResult *result,
511 gpointer user_data)
512{
513 gpointer *weak_pointer = user_data;
514 GError *error = NULL;
515 gssize ret;
516
517 g_assert (object == NULL);
518 g_assert (g_task_is_valid (result, object));
519 g_assert (g_async_result_get_user_data (result) == user_data);
520 g_assert (g_async_result_is_tagged (result, test_report_error));
521 g_assert (g_task_get_source_tag (G_TASK (result)) == test_report_error);
522 g_assert (g_task_had_error (G_TASK (result)));
523 g_assert_false (g_task_get_completed (G_TASK (result)));
524
525 ret = g_task_propagate_int (G_TASK (result), error: &error);
526 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
527 g_assert_cmpint (ret, ==, -1);
528 g_error_free (error);
529
530 g_assert (g_task_had_error (G_TASK (result)));
531
532 *weak_pointer = result;
533 g_object_add_weak_pointer (G_OBJECT (result), weak_pointer_location: weak_pointer);
534 g_signal_connect (result, "notify::completed",
535 (GCallback) completed_cb, &error_notification_emitted);
536
537 g_main_loop_quit (loop);
538}
539
540static void
541test_report_error (void)
542{
543 gpointer weak_pointer = (gpointer)-1;
544
545 g_task_report_new_error (NULL, callback: report_callback, callback_data: &weak_pointer,
546 source_tag: test_report_error,
547 G_IO_ERROR, code: G_IO_ERROR_FAILED,
548 format: "Failed");
549 g_main_loop_run (loop);
550
551 g_assert (weak_pointer == NULL);
552 g_assert_true (error_notification_emitted);
553}
554
555/* test_priority: tasks complete in priority order */
556
557static int counter = 0;
558
559static void
560priority_callback (GObject *object,
561 GAsyncResult *result,
562 gpointer user_data)
563{
564 gssize *ret_out = user_data;
565 GError *error = NULL;
566
567 g_assert (object == NULL);
568 g_assert (g_task_is_valid (result, object));
569 g_assert (g_async_result_get_user_data (result) == user_data);
570 g_assert (!g_task_had_error (G_TASK (result)));
571 g_assert_false (g_task_get_completed (G_TASK (result)));
572
573 g_task_propagate_boolean (G_TASK (result), error: &error);
574 g_assert_no_error (error);
575
576 g_assert (!g_task_had_error (G_TASK (result)));
577
578 *ret_out = ++counter;
579
580 if (counter == 3)
581 g_main_loop_quit (loop);
582}
583
584static void
585test_priority (void)
586{
587 GTask *t1, *t2, *t3;
588 gssize ret1, ret2, ret3;
589
590 /* t2 has higher priority than either t1 or t3, so we can't
591 * accidentally pass the test just by completing the tasks in the
592 * order they were created (or in reverse order).
593 */
594
595 t1 = g_task_new (NULL, NULL, callback: priority_callback, callback_data: &ret1);
596 g_task_set_priority (task: t1, G_PRIORITY_DEFAULT);
597 g_task_return_boolean (task: t1, TRUE);
598 g_object_unref (object: t1);
599
600 t2 = g_task_new (NULL, NULL, callback: priority_callback, callback_data: &ret2);
601 g_task_set_priority (task: t2, G_PRIORITY_HIGH);
602 g_task_return_boolean (task: t2, TRUE);
603 g_object_unref (object: t2);
604
605 t3 = g_task_new (NULL, NULL, callback: priority_callback, callback_data: &ret3);
606 g_task_set_priority (task: t3, G_PRIORITY_LOW);
607 g_task_return_boolean (task: t3, TRUE);
608 g_object_unref (object: t3);
609
610 g_main_loop_run (loop);
611
612 g_assert_cmpint (ret2, ==, 1);
613 g_assert_cmpint (ret1, ==, 2);
614 g_assert_cmpint (ret3, ==, 3);
615}
616
617/* Test that getting and setting the task name works. */
618static void name_callback (GObject *object,
619 GAsyncResult *result,
620 gpointer user_data);
621
622static void
623test_name (void)
624{
625 GTask *t1 = NULL;
626 gchar *name1 = NULL;
627
628 t1 = g_task_new (NULL, NULL, callback: name_callback, callback_data: &name1);
629 g_task_set_name (task: t1, name: "some task");
630 g_task_return_boolean (task: t1, TRUE);
631 g_object_unref (object: t1);
632
633 g_main_loop_run (loop);
634
635 g_assert_cmpstr (name1, ==, "some task");
636
637 g_free (mem: name1);
638}
639
640static void
641name_callback (GObject *object,
642 GAsyncResult *result,
643 gpointer user_data)
644{
645 gchar **name_out = user_data;
646 GError *local_error = NULL;
647
648 g_assert_null (*name_out);
649 *name_out = g_strdup (str: g_task_get_name (G_TASK (result)));
650
651 g_task_propagate_boolean (G_TASK (result), error: &local_error);
652 g_assert_no_error (local_error);
653
654 g_main_loop_quit (loop);
655}
656
657/* test_asynchronous_cancellation: cancelled tasks are returned
658 * asynchronously, i.e. not from inside the GCancellable::cancelled
659 * handler.
660 *
661 * The test is set up further below in test_asynchronous_cancellation.
662 */
663
664/* asynchronous_cancellation_callback represents the callback that the
665 * caller of a typical asynchronous API would have passed. See
666 * test_asynchronous_cancellation.
667 */
668static void
669asynchronous_cancellation_callback (GObject *object,
670 GAsyncResult *result,
671 gpointer user_data)
672{
673 GError *error = NULL;
674 guint run_task_id;
675
676 g_assert_null (object);
677 g_assert_true (g_task_is_valid (result, object));
678 g_assert_true (g_async_result_get_user_data (result) == user_data);
679 g_assert_true (g_task_had_error (G_TASK (result)));
680 g_assert_false (g_task_get_completed (G_TASK (result)));
681
682 run_task_id = GPOINTER_TO_UINT (g_task_get_task_data (G_TASK (result)));
683 g_assert_cmpuint (run_task_id, ==, 0);
684
685 g_task_propagate_boolean (G_TASK (result), error: &error);
686 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
687 g_clear_error (err: &error);
688
689 g_assert_true (g_task_had_error (G_TASK (result)));
690
691 g_main_loop_quit (loop);
692}
693
694/* asynchronous_cancellation_cancel_task represents a user cancelling
695 * the ongoing operation. To make it somewhat realistic it is delayed
696 * by 50ms via a timeout GSource. See test_asynchronous_cancellation.
697 */
698static gboolean
699asynchronous_cancellation_cancel_task (gpointer user_data)
700{
701 GCancellable *cancellable;
702 GTask *task = G_TASK (user_data);
703
704 cancellable = g_task_get_cancellable (task);
705 g_assert_true (G_IS_CANCELLABLE (cancellable));
706
707 g_cancellable_cancel (cancellable);
708 g_assert_false (g_task_get_completed (task));
709
710 return G_SOURCE_REMOVE;
711}
712
713/* asynchronous_cancellation_cancelled is the GCancellable::cancelled
714 * handler that's used by the asynchronous implementation for
715 * cancelling itself.
716 */
717static void
718asynchronous_cancellation_cancelled (GCancellable *cancellable,
719 gpointer user_data)
720{
721 GTask *task = G_TASK (user_data);
722 guint run_task_id;
723
724 g_assert_true (cancellable == g_task_get_cancellable (task));
725
726 run_task_id = GPOINTER_TO_UINT (g_task_get_task_data (task));
727 g_assert_cmpuint (run_task_id, !=, 0);
728
729 g_source_remove (tag: run_task_id);
730 g_task_set_task_data (task, GUINT_TO_POINTER (0), NULL);
731
732 g_task_return_boolean (task, FALSE);
733 g_assert_false (g_task_get_completed (task));
734}
735
736/* asynchronous_cancellation_run_task represents the actual
737 * asynchronous work being done in an idle GSource as was mentioned
738 * above. This is effectively meant to be an infinite loop so that
739 * the only way to break out of it is via cancellation.
740 */
741static gboolean
742asynchronous_cancellation_run_task (gpointer user_data)
743{
744 GCancellable *cancellable;
745 GTask *task = G_TASK (user_data);
746
747 cancellable = g_task_get_cancellable (task);
748 g_assert_true (G_IS_CANCELLABLE (cancellable));
749 g_assert_false (g_cancellable_is_cancelled (cancellable));
750
751 return G_SOURCE_CONTINUE;
752}
753
754/* Test that cancellation is always asynchronous. The completion callback for
755 * a #GTask must not be called from inside the cancellation handler.
756 *
757 * The body of the loop inside test_asynchronous_cancellation
758 * represents what would have been a typical asynchronous API call,
759 * and its implementation. They are fused together without an API
760 * boundary. The actual work done by this asynchronous API is
761 * represented by an idle GSource.
762 */
763static void
764test_asynchronous_cancellation (void)
765{
766 guint i;
767
768 g_test_bug (bug_uri_snippet: "https://gitlab.gnome.org/GNOME/glib/issues/1608");
769
770 /* Run a few times to shake out any timing issues between the
771 * cancellation and task sources.
772 */
773 for (i = 0; i < 5; i++)
774 {
775 GCancellable *cancellable;
776 GTask *task;
777 gboolean notification_emitted = FALSE;
778 guint run_task_id;
779
780 cancellable = g_cancellable_new ();
781
782 task = g_task_new (NULL, cancellable, callback: asynchronous_cancellation_callback, NULL);
783 g_cancellable_connect (cancellable, callback: (GCallback) asynchronous_cancellation_cancelled, data: task, NULL);
784 g_signal_connect (task, "notify::completed", (GCallback) completed_cb, &notification_emitted);
785
786 run_task_id = g_idle_add (function: asynchronous_cancellation_run_task, data: task);
787 g_source_set_name_by_id (tag: run_task_id, name: "[test_asynchronous_cancellation] run_task");
788 g_task_set_task_data (task, GUINT_TO_POINTER (run_task_id), NULL);
789
790 g_timeout_add (interval: 50, function: asynchronous_cancellation_cancel_task, data: task);
791
792 g_main_loop_run (loop);
793
794 g_assert_true (g_task_get_completed (task));
795 g_assert_true (notification_emitted);
796
797 g_object_unref (object: cancellable);
798 g_object_unref (object: task);
799 }
800}
801
802/* test_check_cancellable: cancellation overrides return value */
803
804enum {
805 CANCEL_BEFORE = (1 << 1),
806 CANCEL_AFTER = (1 << 2),
807 CHECK_CANCELLABLE = (1 << 3)
808};
809#define NUM_CANCEL_TESTS (CANCEL_BEFORE | CANCEL_AFTER | CHECK_CANCELLABLE)
810
811static void
812cancel_callback (GObject *object,
813 GAsyncResult *result,
814 gpointer user_data)
815{
816 int state = GPOINTER_TO_INT (user_data);
817 GTask *task;
818 GCancellable *cancellable;
819 GError *error = NULL;
820
821 g_assert (object == NULL);
822 g_assert (g_task_is_valid (result, object));
823 g_assert (g_async_result_get_user_data (result) == user_data);
824
825 task = G_TASK (result);
826 cancellable = g_task_get_cancellable (task);
827 g_assert (G_IS_CANCELLABLE (cancellable));
828
829 if (state & (CANCEL_BEFORE | CANCEL_AFTER))
830 g_assert (g_cancellable_is_cancelled (cancellable));
831 else
832 g_assert (!g_cancellable_is_cancelled (cancellable));
833
834 if (state & CHECK_CANCELLABLE)
835 g_assert (g_task_get_check_cancellable (task));
836 else
837 g_assert (!g_task_get_check_cancellable (task));
838
839 if (g_task_propagate_boolean (task, error: &error))
840 {
841 g_assert (!g_cancellable_is_cancelled (cancellable) ||
842 !g_task_get_check_cancellable (task));
843 }
844 else
845 {
846 g_assert (g_cancellable_is_cancelled (cancellable) &&
847 g_task_get_check_cancellable (task));
848 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
849 g_error_free (error);
850 }
851
852 g_main_loop_quit (loop);
853}
854
855static void
856test_check_cancellable (void)
857{
858 GTask *task;
859 GCancellable *cancellable;
860 int state;
861
862 cancellable = g_cancellable_new ();
863
864 for (state = 0; state <= NUM_CANCEL_TESTS; state++)
865 {
866 task = g_task_new (NULL, cancellable, callback: cancel_callback,
867 GINT_TO_POINTER (state));
868 g_task_set_check_cancellable (task, check_cancellable: (state & CHECK_CANCELLABLE) != 0);
869
870 if (state & CANCEL_BEFORE)
871 g_cancellable_cancel (cancellable);
872 g_task_return_boolean (task, TRUE);
873 if (state & CANCEL_AFTER)
874 g_cancellable_cancel (cancellable);
875
876 g_main_loop_run (loop);
877 g_object_unref (object: task);
878 g_cancellable_reset (cancellable);
879 }
880
881 g_object_unref (object: cancellable);
882}
883
884/* test_return_if_cancelled */
885
886static void
887return_if_cancelled_callback (GObject *object,
888 GAsyncResult *result,
889 gpointer user_data)
890{
891 GError *error = NULL;
892
893 g_assert (object == NULL);
894 g_assert (g_task_is_valid (result, object));
895 g_assert (g_async_result_get_user_data (result) == user_data);
896 g_assert (g_task_had_error (G_TASK (result)));
897 g_assert_false (g_task_get_completed (G_TASK (result)));
898
899 g_task_propagate_boolean (G_TASK (result), error: &error);
900 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
901 g_clear_error (err: &error);
902
903 g_assert (g_task_had_error (G_TASK (result)));
904
905 g_main_loop_quit (loop);
906}
907
908static void
909test_return_if_cancelled (void)
910{
911 GTask *task;
912 GCancellable *cancellable;
913 gboolean cancelled;
914 gboolean notification_emitted = FALSE;
915
916 cancellable = g_cancellable_new ();
917
918 task = g_task_new (NULL, cancellable, callback: return_if_cancelled_callback, NULL);
919 g_signal_connect (task, "notify::completed",
920 (GCallback) completed_cb, &notification_emitted);
921
922 g_cancellable_cancel (cancellable);
923 cancelled = g_task_return_error_if_cancelled (task);
924 g_assert (cancelled);
925 g_assert_false (notification_emitted);
926 g_main_loop_run (loop);
927 g_object_unref (object: task);
928 g_assert_true (notification_emitted);
929 g_cancellable_reset (cancellable);
930
931 notification_emitted = FALSE;
932
933 task = g_task_new (NULL, cancellable, callback: return_if_cancelled_callback, NULL);
934 g_signal_connect (task, "notify::completed",
935 (GCallback) completed_cb, &notification_emitted);
936
937 g_task_set_check_cancellable (task, FALSE);
938 g_cancellable_cancel (cancellable);
939 cancelled = g_task_return_error_if_cancelled (task);
940 g_assert (cancelled);
941 g_assert_false (notification_emitted);
942 g_main_loop_run (loop);
943 g_object_unref (object: task);
944 g_assert_true (notification_emitted);
945 g_object_unref (object: cancellable);
946}
947
948/* test_run_in_thread */
949
950static GMutex run_in_thread_mutex;
951static GCond run_in_thread_cond;
952
953static void
954task_weak_notify (gpointer user_data,
955 GObject *ex_task)
956{
957 gboolean *weak_notify_ran = user_data;
958
959 g_mutex_lock (mutex: &run_in_thread_mutex);
960 g_atomic_int_set (weak_notify_ran, TRUE);
961 g_cond_signal (cond: &run_in_thread_cond);
962 g_mutex_unlock (mutex: &run_in_thread_mutex);
963}
964
965static void
966run_in_thread_callback (GObject *object,
967 GAsyncResult *result,
968 gpointer user_data)
969{
970 gboolean *done = user_data;
971 GError *error = NULL;
972 gssize ret;
973
974 g_assert (g_thread_self () == main_thread);
975
976 g_assert (object == NULL);
977 g_assert (g_task_is_valid (result, object));
978 g_assert (g_async_result_get_user_data (result) == user_data);
979 g_assert (!g_task_had_error (G_TASK (result)));
980 g_assert_false (g_task_get_completed (G_TASK (result)));
981 g_assert_cmpstr (g_task_get_name (G_TASK (result)), ==, "test_run_in_thread name");
982
983 ret = g_task_propagate_int (G_TASK (result), error: &error);
984 g_assert_no_error (error);
985 g_assert_cmpint (ret, ==, magic);
986
987 g_assert (!g_task_had_error (G_TASK (result)));
988
989 *done = TRUE;
990 g_main_loop_quit (loop);
991}
992
993static void
994run_in_thread_thread (GTask *task,
995 gpointer source_object,
996 gpointer task_data,
997 GCancellable *cancellable)
998{
999 gboolean *thread_ran = task_data;
1000
1001 g_assert (source_object == g_task_get_source_object (task));
1002 g_assert (task_data == g_task_get_task_data (task));
1003 g_assert (cancellable == g_task_get_cancellable (task));
1004 g_assert_false (g_task_get_completed (task));
1005 g_assert_cmpstr (g_task_get_name (task), ==, "test_run_in_thread name");
1006
1007 g_assert (g_thread_self () != main_thread);
1008
1009 g_mutex_lock (mutex: &run_in_thread_mutex);
1010 g_atomic_int_set (thread_ran, TRUE);
1011 g_cond_signal (cond: &run_in_thread_cond);
1012 g_mutex_unlock (mutex: &run_in_thread_mutex);
1013
1014 g_task_return_int (task, result: magic);
1015}
1016
1017static void
1018test_run_in_thread (void)
1019{
1020 GTask *task;
1021 gboolean thread_ran = FALSE; /* (atomic) */
1022 gboolean weak_notify_ran = FALSE; /* (atomic) */
1023 gboolean notification_emitted = FALSE;
1024 gboolean done = FALSE;
1025
1026 task = g_task_new (NULL, NULL, callback: run_in_thread_callback, callback_data: &done);
1027 g_task_set_name (task, name: "test_run_in_thread name");
1028 g_object_weak_ref (G_OBJECT (task), notify: task_weak_notify, data: (gpointer)&weak_notify_ran);
1029 g_signal_connect (task, "notify::completed",
1030 (GCallback) completed_cb, &notification_emitted);
1031
1032 g_task_set_task_data (task, task_data: (gpointer)&thread_ran, NULL);
1033 g_task_run_in_thread (task, task_func: run_in_thread_thread);
1034
1035 g_mutex_lock (mutex: &run_in_thread_mutex);
1036 while (!g_atomic_int_get (&thread_ran))
1037 g_cond_wait (cond: &run_in_thread_cond, mutex: &run_in_thread_mutex);
1038 g_mutex_unlock (mutex: &run_in_thread_mutex);
1039
1040 g_assert (done == FALSE);
1041 g_assert_false (g_atomic_int_get (&weak_notify_ran));
1042
1043 g_main_loop_run (loop);
1044
1045 g_assert (done == TRUE);
1046 g_assert_true (notification_emitted);
1047
1048 g_assert_cmpstr (g_task_get_name (task), ==, "test_run_in_thread name");
1049
1050 g_object_unref (object: task);
1051
1052 g_mutex_lock (mutex: &run_in_thread_mutex);
1053 while (!g_atomic_int_get (&weak_notify_ran))
1054 g_cond_wait (cond: &run_in_thread_cond, mutex: &run_in_thread_mutex);
1055 g_mutex_unlock (mutex: &run_in_thread_mutex);
1056}
1057
1058/* test_run_in_thread_sync */
1059
1060static void
1061run_in_thread_sync_callback (GObject *object,
1062 GAsyncResult *result,
1063 gpointer user_data)
1064{
1065 /* g_task_run_in_thread_sync() does not invoke the task's callback */
1066 g_assert_not_reached ();
1067}
1068
1069static void
1070run_in_thread_sync_thread (GTask *task,
1071 gpointer source_object,
1072 gpointer task_data,
1073 GCancellable *cancellable)
1074{
1075 gboolean *thread_ran = task_data;
1076
1077 g_assert (source_object == g_task_get_source_object (task));
1078 g_assert (task_data == g_task_get_task_data (task));
1079 g_assert (cancellable == g_task_get_cancellable (task));
1080 g_assert_false (g_task_get_completed (task));
1081
1082 g_assert (g_thread_self () != main_thread);
1083
1084 g_atomic_int_set (thread_ran, TRUE);
1085 g_task_return_int (task, result: magic);
1086}
1087
1088static void
1089test_run_in_thread_sync (void)
1090{
1091 GTask *task;
1092 gboolean thread_ran = FALSE;
1093 gssize ret;
1094 gboolean notification_emitted = FALSE;
1095 GError *error = NULL;
1096
1097 task = g_task_new (NULL, NULL, callback: run_in_thread_sync_callback, NULL);
1098 g_signal_connect (task, "notify::completed",
1099 (GCallback) completed_cb,
1100 &notification_emitted);
1101
1102 g_task_set_task_data (task, task_data: &thread_ran, NULL);
1103 g_task_run_in_thread_sync (task, task_func: run_in_thread_sync_thread);
1104
1105 g_assert_true (g_atomic_int_get (&thread_ran));
1106 g_assert (task != NULL);
1107 g_assert (!g_task_had_error (task));
1108 g_assert_true (g_task_get_completed (task));
1109 g_assert_true (notification_emitted);
1110
1111 ret = g_task_propagate_int (task, error: &error);
1112 g_assert_no_error (error);
1113 g_assert_cmpint (ret, ==, magic);
1114
1115 g_assert (!g_task_had_error (task));
1116
1117 g_object_unref (object: task);
1118}
1119
1120/* test_run_in_thread_priority */
1121
1122static GMutex fake_task_mutex, last_fake_task_mutex;
1123static gint sequence_number = 0;
1124
1125static void
1126quit_main_loop_callback (GObject *object,
1127 GAsyncResult *result,
1128 gpointer user_data)
1129{
1130 GError *error = NULL;
1131 gboolean ret;
1132
1133 g_assert (g_thread_self () == main_thread);
1134
1135 g_assert (object == NULL);
1136 g_assert (g_task_is_valid (result, object));
1137 g_assert (g_async_result_get_user_data (result) == user_data);
1138 g_assert (!g_task_had_error (G_TASK (result)));
1139 g_assert_false (g_task_get_completed (G_TASK (result)));
1140
1141 ret = g_task_propagate_boolean (G_TASK (result), error: &error);
1142 g_assert_no_error (error);
1143 g_assert_cmpint (ret, ==, TRUE);
1144
1145 g_assert (!g_task_had_error (G_TASK (result)));
1146
1147 g_main_loop_quit (loop);
1148}
1149
1150static void
1151set_sequence_number_thread (GTask *task,
1152 gpointer source_object,
1153 gpointer task_data,
1154 GCancellable *cancellable)
1155{
1156 gint *seq_no_p = task_data;
1157
1158 *seq_no_p = ++sequence_number;
1159 g_task_return_boolean (task, TRUE);
1160}
1161
1162static void
1163fake_task_thread (GTask *task,
1164 gpointer source_object,
1165 gpointer task_data,
1166 GCancellable *cancellable)
1167{
1168 GMutex *mutex = task_data;
1169
1170 g_mutex_lock (mutex);
1171 g_mutex_unlock (mutex);
1172 g_task_return_boolean (task, TRUE);
1173}
1174
1175#define G_TASK_THREAD_POOL_SIZE 10
1176static int fake_tasks_running;
1177
1178static void
1179fake_task_callback (GObject *source,
1180 GAsyncResult *result,
1181 gpointer user_data)
1182{
1183 if (--fake_tasks_running == 0)
1184 g_main_loop_quit (loop);
1185}
1186
1187static void
1188clog_up_thread_pool (void)
1189{
1190 GTask *task;
1191 int i;
1192
1193 g_thread_pool_stop_unused_threads ();
1194
1195 g_mutex_lock (mutex: &fake_task_mutex);
1196 for (i = 0; i < G_TASK_THREAD_POOL_SIZE - 1; i++)
1197 {
1198 task = g_task_new (NULL, NULL, callback: fake_task_callback, NULL);
1199 g_task_set_task_data (task, task_data: &fake_task_mutex, NULL);
1200 g_assert_cmpint (g_task_get_priority (task), ==, G_PRIORITY_DEFAULT);
1201 g_task_set_priority (task, G_PRIORITY_HIGH * 2);
1202 g_assert_cmpint (g_task_get_priority (task), ==, G_PRIORITY_HIGH * 2);
1203 g_task_run_in_thread (task, task_func: fake_task_thread);
1204 g_object_unref (object: task);
1205 fake_tasks_running++;
1206 }
1207
1208 g_mutex_lock (mutex: &last_fake_task_mutex);
1209 task = g_task_new (NULL, NULL, NULL, NULL);
1210 g_task_set_task_data (task, task_data: &last_fake_task_mutex, NULL);
1211 g_task_set_priority (task, G_PRIORITY_HIGH * 2);
1212 g_task_run_in_thread (task, task_func: fake_task_thread);
1213 g_object_unref (object: task);
1214}
1215
1216static void
1217unclog_thread_pool (void)
1218{
1219 g_mutex_unlock (mutex: &fake_task_mutex);
1220 g_main_loop_run (loop);
1221}
1222
1223static void
1224test_run_in_thread_priority (void)
1225{
1226 GTask *task;
1227 GCancellable *cancellable;
1228 int seq_a, seq_b, seq_c, seq_d;
1229
1230 clog_up_thread_pool ();
1231
1232 /* Queue three more tasks that we'll arrange to have run serially */
1233 task = g_task_new (NULL, NULL, NULL, NULL);
1234 g_task_set_task_data (task, task_data: &seq_a, NULL);
1235 g_task_run_in_thread (task, task_func: set_sequence_number_thread);
1236 g_object_unref (object: task);
1237
1238 task = g_task_new (NULL, NULL, callback: quit_main_loop_callback, NULL);
1239 g_task_set_task_data (task, task_data: &seq_b, NULL);
1240 g_task_set_priority (task, G_PRIORITY_LOW);
1241 g_task_run_in_thread (task, task_func: set_sequence_number_thread);
1242 g_object_unref (object: task);
1243
1244 task = g_task_new (NULL, NULL, NULL, NULL);
1245 g_task_set_task_data (task, task_data: &seq_c, NULL);
1246 g_task_set_priority (task, G_PRIORITY_HIGH);
1247 g_task_run_in_thread (task, task_func: set_sequence_number_thread);
1248 g_object_unref (object: task);
1249
1250 cancellable = g_cancellable_new ();
1251 task = g_task_new (NULL, cancellable, NULL, NULL);
1252 g_task_set_task_data (task, task_data: &seq_d, NULL);
1253 g_task_run_in_thread (task, task_func: set_sequence_number_thread);
1254 g_cancellable_cancel (cancellable);
1255 g_object_unref (object: cancellable);
1256 g_object_unref (object: task);
1257
1258 /* Let the last fake task complete; the four other tasks will then
1259 * complete serially, in the order D, C, A, B, and B will quit the
1260 * main loop.
1261 */
1262 g_mutex_unlock (mutex: &last_fake_task_mutex);
1263 g_main_loop_run (loop);
1264
1265 g_assert_cmpint (seq_d, ==, 1);
1266 g_assert_cmpint (seq_c, ==, 2);
1267 g_assert_cmpint (seq_a, ==, 3);
1268 g_assert_cmpint (seq_b, ==, 4);
1269
1270 unclog_thread_pool ();
1271}
1272
1273/* test_run_in_thread_nested: task threads that block waiting on
1274 * other task threads will not cause the thread pool to starve.
1275 */
1276
1277static void
1278run_nested_task_thread (GTask *task,
1279 gpointer source_object,
1280 gpointer task_data,
1281 GCancellable *cancellable)
1282{
1283 GTask *nested;
1284 int *nested_tasks_left = task_data;
1285
1286 if ((*nested_tasks_left)--)
1287 {
1288 nested = g_task_new (NULL, NULL, NULL, NULL);
1289 g_task_set_task_data (task: nested, task_data: nested_tasks_left, NULL);
1290 g_task_run_in_thread_sync (task: nested, task_func: run_nested_task_thread);
1291 g_object_unref (object: nested);
1292 }
1293
1294 g_task_return_boolean (task, TRUE);
1295}
1296
1297static void
1298test_run_in_thread_nested (void)
1299{
1300 GTask *task;
1301 int nested_tasks_left = 2;
1302
1303 clog_up_thread_pool ();
1304
1305 task = g_task_new (NULL, NULL, callback: quit_main_loop_callback, NULL);
1306 g_task_set_task_data (task, task_data: &nested_tasks_left, NULL);
1307 g_task_run_in_thread (task, task_func: run_nested_task_thread);
1308 g_object_unref (object: task);
1309
1310 g_mutex_unlock (mutex: &last_fake_task_mutex);
1311 g_main_loop_run (loop);
1312
1313 unclog_thread_pool ();
1314}
1315
1316/* test_run_in_thread_overflow: if you queue lots and lots and lots of
1317 * tasks, they won't all run at once.
1318 */
1319static GMutex overflow_mutex;
1320static guint overflow_completed;
1321
1322static void
1323run_overflow_task_thread (GTask *task,
1324 gpointer source_object,
1325 gpointer task_data,
1326 GCancellable *cancellable)
1327{
1328 gchar *result = task_data;
1329
1330 if (g_task_return_error_if_cancelled (task))
1331 {
1332 *result = 'X';
1333 }
1334 else
1335 {
1336 /* Block until the main thread is ready. */
1337 g_mutex_lock (mutex: &overflow_mutex);
1338 g_mutex_unlock (mutex: &overflow_mutex);
1339
1340 *result = '.';
1341
1342 g_task_return_boolean (task, TRUE);
1343 }
1344
1345 g_atomic_int_inc (&overflow_completed);
1346}
1347
1348#define NUM_OVERFLOW_TASKS 1024
1349
1350static void
1351test_run_in_thread_overflow (void)
1352{
1353 GCancellable *cancellable;
1354 GTask *task;
1355 gchar buf[NUM_OVERFLOW_TASKS + 1];
1356 gint i;
1357
1358 /* Queue way too many tasks and then sleep for a bit. The first 10
1359 * tasks will be dispatched to threads and will then block on
1360 * overflow_mutex, so more threads will be created while this thread
1361 * is sleeping. Then we cancel the cancellable, unlock the mutex,
1362 * wait for all of the tasks to complete, and make sure that we got
1363 * the behavior we expected.
1364 */
1365
1366 memset (s: buf, c: 0, n: sizeof (buf));
1367 cancellable = g_cancellable_new ();
1368
1369 g_mutex_lock (mutex: &overflow_mutex);
1370
1371 for (i = 0; i < NUM_OVERFLOW_TASKS; i++)
1372 {
1373 task = g_task_new (NULL, cancellable, NULL, NULL);
1374 g_task_set_task_data (task, task_data: buf + i, NULL);
1375 g_task_run_in_thread (task, task_func: run_overflow_task_thread);
1376 g_object_unref (object: task);
1377 }
1378
1379 if (g_test_slow ())
1380 g_usleep (microseconds: 5000000); /* 5 s */
1381 else
1382 g_usleep (microseconds: 500000); /* 0.5 s */
1383 g_cancellable_cancel (cancellable);
1384 g_object_unref (object: cancellable);
1385
1386 g_mutex_unlock (mutex: &overflow_mutex);
1387
1388 /* Wait for all tasks to complete. */
1389 while (g_atomic_int_get (&overflow_completed) != NUM_OVERFLOW_TASKS)
1390 g_usleep (microseconds: 1000);
1391
1392 g_assert_cmpint (strlen (buf), ==, NUM_OVERFLOW_TASKS);
1393
1394 i = strspn (s: buf, accept: ".");
1395 /* Given the sleep times above, i should be 14 for normal, 40 for
1396 * slow. But if the machine is too slow/busy then the scheduling
1397 * might get messed up and we'll get more or fewer threads than
1398 * expected. But there are limits to how messed up it could
1399 * plausibly get (and we hope that if gtask is actually broken then
1400 * it will exceed those limits).
1401 */
1402 g_assert_cmpint (i, >=, 10);
1403 if (g_test_slow ())
1404 g_assert_cmpint (i, <, 50);
1405 else
1406 g_assert_cmpint (i, <, 20);
1407
1408 g_assert_cmpint (i + strspn (buf + i, "X"), ==, NUM_OVERFLOW_TASKS);
1409}
1410
1411/* test_return_on_cancel */
1412
1413GMutex roc_init_mutex, roc_finish_mutex;
1414GCond roc_init_cond, roc_finish_cond;
1415
1416typedef enum {
1417 THREAD_STARTING,
1418 THREAD_RUNNING,
1419 THREAD_CANCELLED,
1420 THREAD_COMPLETED
1421} ThreadState;
1422
1423static void
1424return_on_cancel_callback (GObject *object,
1425 GAsyncResult *result,
1426 gpointer user_data)
1427{
1428 gboolean *callback_ran = user_data;
1429 GError *error = NULL;
1430 gssize ret;
1431
1432 g_assert (g_thread_self () == main_thread);
1433
1434 g_assert (object == NULL);
1435 g_assert (g_task_is_valid (result, object));
1436 g_assert (g_async_result_get_user_data (result) == user_data);
1437 g_assert (g_task_had_error (G_TASK (result)));
1438 g_assert_false (g_task_get_completed (G_TASK (result)));
1439
1440 ret = g_task_propagate_int (G_TASK (result), error: &error);
1441 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1442 g_clear_error (err: &error);
1443 g_assert_cmpint (ret, ==, -1);
1444
1445 g_assert (g_task_had_error (G_TASK (result)));
1446
1447 *callback_ran = TRUE;
1448 g_main_loop_quit (loop);
1449}
1450
1451static void
1452return_on_cancel_thread (GTask *task,
1453 gpointer source_object,
1454 gpointer task_data,
1455 GCancellable *cancellable)
1456{
1457 ThreadState *state = task_data;
1458
1459 g_assert (source_object == g_task_get_source_object (task));
1460 g_assert (task_data == g_task_get_task_data (task));
1461 g_assert (cancellable == g_task_get_cancellable (task));
1462
1463 g_assert (g_thread_self () != main_thread);
1464
1465 g_mutex_lock (mutex: &roc_init_mutex);
1466 *state = THREAD_RUNNING;
1467 g_cond_signal (cond: &roc_init_cond);
1468 g_mutex_unlock (mutex: &roc_init_mutex);
1469
1470 g_mutex_lock (mutex: &roc_finish_mutex);
1471
1472 if (!g_task_get_return_on_cancel (task) ||
1473 g_task_set_return_on_cancel (task, FALSE))
1474 {
1475 *state = THREAD_COMPLETED;
1476 g_task_return_int (task, result: magic);
1477 }
1478 else
1479 *state = THREAD_CANCELLED;
1480
1481 g_cond_signal (cond: &roc_finish_cond);
1482 g_mutex_unlock (mutex: &roc_finish_mutex);
1483}
1484
1485static void
1486test_return_on_cancel (void)
1487{
1488 GTask *task;
1489 GCancellable *cancellable;
1490 ThreadState thread_state; /* (atomic) */
1491 gboolean weak_notify_ran = FALSE; /* (atomic) */
1492 gboolean callback_ran;
1493 gboolean notification_emitted = FALSE;
1494
1495 cancellable = g_cancellable_new ();
1496
1497 /* If return-on-cancel is FALSE (default), the task does not return
1498 * early.
1499 */
1500 callback_ran = FALSE;
1501 g_atomic_int_set (&thread_state, THREAD_STARTING);
1502 task = g_task_new (NULL, cancellable, callback: return_on_cancel_callback, callback_data: &callback_ran);
1503 g_signal_connect (task, "notify::completed",
1504 (GCallback) completed_cb, &notification_emitted);
1505
1506 g_task_set_task_data (task, task_data: (gpointer)&thread_state, NULL);
1507 g_mutex_lock (mutex: &roc_init_mutex);
1508 g_mutex_lock (mutex: &roc_finish_mutex);
1509 g_task_run_in_thread (task, task_func: return_on_cancel_thread);
1510 g_object_unref (object: task);
1511
1512 while (g_atomic_int_get (&thread_state) == THREAD_STARTING)
1513 g_cond_wait (cond: &roc_init_cond, mutex: &roc_init_mutex);
1514 g_mutex_unlock (mutex: &roc_init_mutex);
1515
1516 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_RUNNING);
1517 g_assert (callback_ran == FALSE);
1518
1519 g_cancellable_cancel (cancellable);
1520 g_mutex_unlock (mutex: &roc_finish_mutex);
1521 g_main_loop_run (loop);
1522
1523 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_COMPLETED);
1524 g_assert (callback_ran == TRUE);
1525 g_assert_true (notification_emitted);
1526
1527 g_cancellable_reset (cancellable);
1528
1529 /* If return-on-cancel is TRUE, it does return early */
1530 callback_ran = FALSE;
1531 notification_emitted = FALSE;
1532 g_atomic_int_set (&thread_state, THREAD_STARTING);
1533 task = g_task_new (NULL, cancellable, callback: return_on_cancel_callback, callback_data: &callback_ran);
1534 g_object_weak_ref (G_OBJECT (task), notify: task_weak_notify, data: (gpointer)&weak_notify_ran);
1535 g_signal_connect (task, "notify::completed",
1536 (GCallback) completed_cb, &notification_emitted);
1537 g_task_set_return_on_cancel (task, TRUE);
1538
1539 g_task_set_task_data (task, task_data: (gpointer)&thread_state, NULL);
1540 g_mutex_lock (mutex: &roc_init_mutex);
1541 g_mutex_lock (mutex: &roc_finish_mutex);
1542 g_task_run_in_thread (task, task_func: return_on_cancel_thread);
1543 g_object_unref (object: task);
1544
1545 while (g_atomic_int_get (&thread_state) == THREAD_STARTING)
1546 g_cond_wait (cond: &roc_init_cond, mutex: &roc_init_mutex);
1547 g_mutex_unlock (mutex: &roc_init_mutex);
1548
1549 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_RUNNING);
1550 g_assert (callback_ran == FALSE);
1551
1552 g_cancellable_cancel (cancellable);
1553 g_main_loop_run (loop);
1554 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_RUNNING);
1555 g_assert (callback_ran == TRUE);
1556
1557 g_assert_false (g_atomic_int_get (&weak_notify_ran));
1558
1559 while (g_atomic_int_get (&thread_state) == THREAD_RUNNING)
1560 g_cond_wait (cond: &roc_finish_cond, mutex: &roc_finish_mutex);
1561 g_mutex_unlock (mutex: &roc_finish_mutex);
1562
1563 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_CANCELLED);
1564 g_mutex_lock (mutex: &run_in_thread_mutex);
1565 while (!g_atomic_int_get (&weak_notify_ran))
1566 g_cond_wait (cond: &run_in_thread_cond, mutex: &run_in_thread_mutex);
1567 g_mutex_unlock (mutex: &run_in_thread_mutex);
1568
1569 g_assert_true (notification_emitted);
1570 g_cancellable_reset (cancellable);
1571
1572 /* If the task is already cancelled before it starts, it returns
1573 * immediately, but the thread func still runs.
1574 */
1575 callback_ran = FALSE;
1576 notification_emitted = FALSE;
1577 g_atomic_int_set (&thread_state, THREAD_STARTING);
1578 task = g_task_new (NULL, cancellable, callback: return_on_cancel_callback, callback_data: &callback_ran);
1579 g_signal_connect (task, "notify::completed",
1580 (GCallback) completed_cb, &notification_emitted);
1581 g_task_set_return_on_cancel (task, TRUE);
1582
1583 g_cancellable_cancel (cancellable);
1584
1585 g_task_set_task_data (task, task_data: (gpointer)&thread_state, NULL);
1586 g_mutex_lock (mutex: &roc_init_mutex);
1587 g_mutex_lock (mutex: &roc_finish_mutex);
1588 g_task_run_in_thread (task, task_func: return_on_cancel_thread);
1589 g_object_unref (object: task);
1590
1591 g_main_loop_run (loop);
1592 g_assert (callback_ran == TRUE);
1593
1594 while (g_atomic_int_get (&thread_state) == THREAD_STARTING)
1595 g_cond_wait (cond: &roc_init_cond, mutex: &roc_init_mutex);
1596 g_mutex_unlock (mutex: &roc_init_mutex);
1597
1598 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_RUNNING);
1599
1600 while (g_atomic_int_get (&thread_state) == THREAD_RUNNING)
1601 g_cond_wait (cond: &roc_finish_cond, mutex: &roc_finish_mutex);
1602 g_mutex_unlock (mutex: &roc_finish_mutex);
1603
1604 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_CANCELLED);
1605 g_assert_true (notification_emitted);
1606
1607 g_object_unref (object: cancellable);
1608}
1609
1610/* test_return_on_cancel_sync */
1611
1612static gpointer
1613cancel_sync_runner_thread (gpointer task)
1614{
1615 g_task_run_in_thread_sync (task, task_func: return_on_cancel_thread);
1616 return NULL;
1617}
1618
1619static void
1620test_return_on_cancel_sync (void)
1621{
1622 GTask *task;
1623 GCancellable *cancellable;
1624 ThreadState thread_state; /* (atomic) */
1625 GThread *runner_thread;
1626 gssize ret;
1627 GError *error = NULL;
1628
1629 cancellable = g_cancellable_new ();
1630
1631 /* If return-on-cancel is FALSE, the task does not return early.
1632 */
1633 g_atomic_int_set (&thread_state, THREAD_STARTING);
1634 task = g_task_new (NULL, cancellable, callback: run_in_thread_sync_callback, NULL);
1635
1636 g_task_set_task_data (task, task_data: (gpointer)&thread_state, NULL);
1637 g_mutex_lock (mutex: &roc_init_mutex);
1638 g_mutex_lock (mutex: &roc_finish_mutex);
1639 runner_thread = g_thread_new (name: "return-on-cancel-sync runner thread",
1640 func: cancel_sync_runner_thread, data: task);
1641
1642 while (g_atomic_int_get (&thread_state) == THREAD_STARTING)
1643 g_cond_wait (cond: &roc_init_cond, mutex: &roc_init_mutex);
1644 g_mutex_unlock (mutex: &roc_init_mutex);
1645
1646 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_RUNNING);
1647
1648 g_cancellable_cancel (cancellable);
1649 g_mutex_unlock (mutex: &roc_finish_mutex);
1650 g_thread_join (thread: runner_thread);
1651 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_COMPLETED);
1652
1653 ret = g_task_propagate_int (task, error: &error);
1654 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1655 g_clear_error (err: &error);
1656 g_assert_cmpint (ret, ==, -1);
1657
1658 g_object_unref (object: task);
1659
1660 g_cancellable_reset (cancellable);
1661
1662 /* If return-on-cancel is TRUE, it does return early */
1663 g_atomic_int_set (&thread_state, THREAD_STARTING);
1664 task = g_task_new (NULL, cancellable, callback: run_in_thread_sync_callback, NULL);
1665 g_task_set_return_on_cancel (task, TRUE);
1666
1667 g_task_set_task_data (task, task_data: (gpointer)&thread_state, NULL);
1668 g_mutex_lock (mutex: &roc_init_mutex);
1669 g_mutex_lock (mutex: &roc_finish_mutex);
1670 runner_thread = g_thread_new (name: "return-on-cancel-sync runner thread",
1671 func: cancel_sync_runner_thread, data: task);
1672
1673 while (g_atomic_int_get (&thread_state) == THREAD_STARTING)
1674 g_cond_wait (cond: &roc_init_cond, mutex: &roc_init_mutex);
1675 g_mutex_unlock (mutex: &roc_init_mutex);
1676
1677 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_RUNNING);
1678
1679 g_cancellable_cancel (cancellable);
1680 g_thread_join (thread: runner_thread);
1681 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_RUNNING);
1682
1683 ret = g_task_propagate_int (task, error: &error);
1684 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1685 g_clear_error (err: &error);
1686 g_assert_cmpint (ret, ==, -1);
1687
1688 g_object_unref (object: task);
1689
1690 while (g_atomic_int_get (&thread_state) == THREAD_RUNNING)
1691 g_cond_wait (cond: &roc_finish_cond, mutex: &roc_finish_mutex);
1692 g_mutex_unlock (mutex: &roc_finish_mutex);
1693
1694 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_CANCELLED);
1695
1696 g_cancellable_reset (cancellable);
1697
1698 /* If the task is already cancelled before it starts, it returns
1699 * immediately, but the thread func still runs.
1700 */
1701 g_atomic_int_set (&thread_state, THREAD_STARTING);
1702 task = g_task_new (NULL, cancellable, callback: run_in_thread_sync_callback, NULL);
1703 g_task_set_return_on_cancel (task, TRUE);
1704
1705 g_cancellable_cancel (cancellable);
1706
1707 g_task_set_task_data (task, task_data: (gpointer)&thread_state, NULL);
1708 g_mutex_lock (mutex: &roc_init_mutex);
1709 g_mutex_lock (mutex: &roc_finish_mutex);
1710 runner_thread = g_thread_new (name: "return-on-cancel-sync runner thread",
1711 func: cancel_sync_runner_thread, data: task);
1712
1713 g_thread_join (thread: runner_thread);
1714 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_STARTING);
1715
1716 ret = g_task_propagate_int (task, error: &error);
1717 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1718 g_clear_error (err: &error);
1719 g_assert_cmpint (ret, ==, -1);
1720
1721 g_object_unref (object: task);
1722
1723 while (g_atomic_int_get (&thread_state) == THREAD_STARTING)
1724 g_cond_wait (cond: &roc_init_cond, mutex: &roc_init_mutex);
1725 g_mutex_unlock (mutex: &roc_init_mutex);
1726
1727 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_RUNNING);
1728
1729 while (g_atomic_int_get (&thread_state) == THREAD_RUNNING)
1730 g_cond_wait (cond: &roc_finish_cond, mutex: &roc_finish_mutex);
1731 g_mutex_unlock (mutex: &roc_finish_mutex);
1732
1733 g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_CANCELLED);
1734
1735 g_object_unref (object: cancellable);
1736}
1737
1738/* test_return_on_cancel_atomic: turning return-on-cancel on/off is
1739 * non-racy
1740 */
1741
1742GMutex roca_mutex_1, roca_mutex_2;
1743GCond roca_cond_1, roca_cond_2;
1744
1745static void
1746return_on_cancel_atomic_callback (GObject *object,
1747 GAsyncResult *result,
1748 gpointer user_data)
1749{
1750 gboolean *callback_ran = user_data;
1751 GError *error = NULL;
1752 gssize ret;
1753
1754 g_assert (g_thread_self () == main_thread);
1755
1756 g_assert (object == NULL);
1757 g_assert (g_task_is_valid (result, object));
1758 g_assert (g_async_result_get_user_data (result) == user_data);
1759 g_assert (g_task_had_error (G_TASK (result)));
1760 g_assert_false (g_task_get_completed (G_TASK (result)));
1761
1762 ret = g_task_propagate_int (G_TASK (result), error: &error);
1763 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1764 g_clear_error (err: &error);
1765 g_assert_cmpint (ret, ==, -1);
1766
1767 g_assert (g_task_had_error (G_TASK (result)));
1768
1769 *callback_ran = TRUE;
1770 g_main_loop_quit (loop);
1771}
1772
1773static void
1774return_on_cancel_atomic_thread (GTask *task,
1775 gpointer source_object,
1776 gpointer task_data,
1777 GCancellable *cancellable)
1778{
1779 gint *state = task_data; /* (atomic) */
1780
1781 g_assert (source_object == g_task_get_source_object (task));
1782 g_assert (task_data == g_task_get_task_data (task));
1783 g_assert (cancellable == g_task_get_cancellable (task));
1784 g_assert_false (g_task_get_completed (task));
1785
1786 g_assert (g_thread_self () != main_thread);
1787 g_assert_cmpint (g_atomic_int_get (state), ==, 0);
1788
1789 g_mutex_lock (mutex: &roca_mutex_1);
1790 g_atomic_int_set (state, 1);
1791 g_cond_signal (cond: &roca_cond_1);
1792 g_mutex_unlock (mutex: &roca_mutex_1);
1793
1794 g_mutex_lock (mutex: &roca_mutex_2);
1795 if (g_task_set_return_on_cancel (task, FALSE))
1796 g_atomic_int_set (state, 2);
1797 else
1798 g_atomic_int_set (state, 3);
1799 g_cond_signal (cond: &roca_cond_2);
1800 g_mutex_unlock (mutex: &roca_mutex_2);
1801
1802 g_mutex_lock (mutex: &roca_mutex_1);
1803 if (g_task_set_return_on_cancel (task, TRUE))
1804 g_atomic_int_set (state, 4);
1805 else
1806 g_atomic_int_set (state, 5);
1807 g_cond_signal (cond: &roca_cond_1);
1808 g_mutex_unlock (mutex: &roca_mutex_1);
1809
1810 g_mutex_lock (mutex: &roca_mutex_2);
1811 if (g_task_set_return_on_cancel (task, TRUE))
1812 g_atomic_int_set (state, 6);
1813 else
1814 g_atomic_int_set (state, 7);
1815 g_cond_signal (cond: &roca_cond_2);
1816 g_mutex_unlock (mutex: &roca_mutex_2);
1817
1818 g_task_return_int (task, result: magic);
1819}
1820
1821static void
1822test_return_on_cancel_atomic (void)
1823{
1824 GTask *task;
1825 GCancellable *cancellable;
1826 gint state; /* (atomic) */
1827 gboolean notification_emitted = FALSE;
1828 gboolean callback_ran;
1829
1830 cancellable = g_cancellable_new ();
1831 g_mutex_lock (mutex: &roca_mutex_1);
1832 g_mutex_lock (mutex: &roca_mutex_2);
1833
1834 /* If we don't cancel it, each set_return_on_cancel() call will succeed */
1835 g_atomic_int_set (&state, 0);
1836 callback_ran = FALSE;
1837 task = g_task_new (NULL, cancellable, callback: return_on_cancel_atomic_callback, callback_data: &callback_ran);
1838 g_task_set_return_on_cancel (task, TRUE);
1839 g_signal_connect (task, "notify::completed",
1840 (GCallback) completed_cb, &notification_emitted);
1841
1842 g_task_set_task_data (task, task_data: (gpointer)&state, NULL);
1843 g_task_run_in_thread (task, task_func: return_on_cancel_atomic_thread);
1844 g_object_unref (object: task);
1845
1846 g_assert_cmpint (g_atomic_int_get (&state), ==, 0);
1847
1848 while (g_atomic_int_get (&state) == 0)
1849 g_cond_wait (cond: &roca_cond_1, mutex: &roca_mutex_1);
1850 g_assert_cmpint (g_atomic_int_get (&state), ==, 1);
1851
1852 while (g_atomic_int_get (&state) == 1)
1853 g_cond_wait (cond: &roca_cond_2, mutex: &roca_mutex_2);
1854 g_assert_cmpint (g_atomic_int_get (&state), ==, 2);
1855
1856 while (g_atomic_int_get (&state) == 2)
1857 g_cond_wait (cond: &roca_cond_1, mutex: &roca_mutex_1);
1858 g_assert_cmpint (g_atomic_int_get (&state), ==, 4);
1859
1860 while (g_atomic_int_get (&state) == 4)
1861 g_cond_wait (cond: &roca_cond_2, mutex: &roca_mutex_2);
1862 g_assert_cmpint (g_atomic_int_get (&state), ==, 6);
1863
1864 /* callback assumes there'll be a cancelled error */
1865 g_cancellable_cancel (cancellable);
1866
1867 g_assert (callback_ran == FALSE);
1868 g_main_loop_run (loop);
1869 g_assert (callback_ran == TRUE);
1870 g_assert_true (notification_emitted);
1871
1872 g_cancellable_reset (cancellable);
1873
1874
1875 /* If we cancel while it's temporarily not return-on-cancel, the
1876 * task won't complete right away, and further
1877 * g_task_set_return_on_cancel() calls will return FALSE.
1878 */
1879 g_atomic_int_set (&state, 0);
1880 callback_ran = FALSE;
1881 notification_emitted = FALSE;
1882 task = g_task_new (NULL, cancellable, callback: return_on_cancel_atomic_callback, callback_data: &callback_ran);
1883 g_task_set_return_on_cancel (task, TRUE);
1884 g_signal_connect (task, "notify::completed",
1885 (GCallback) completed_cb, &notification_emitted);
1886
1887 g_task_set_task_data (task, task_data: (gpointer)&state, NULL);
1888 g_task_run_in_thread (task, task_func: return_on_cancel_atomic_thread);
1889
1890 g_assert_cmpint (g_atomic_int_get (&state), ==, 0);
1891
1892 while (g_atomic_int_get (&state) == 0)
1893 g_cond_wait (cond: &roca_cond_1, mutex: &roca_mutex_1);
1894 g_assert_cmpint (g_atomic_int_get (&state), ==, 1);
1895 g_assert (g_task_get_return_on_cancel (task));
1896
1897 while (g_atomic_int_get (&state) == 1)
1898 g_cond_wait (cond: &roca_cond_2, mutex: &roca_mutex_2);
1899 g_assert_cmpint (g_atomic_int_get (&state), ==, 2);
1900 g_assert (!g_task_get_return_on_cancel (task));
1901
1902 g_cancellable_cancel (cancellable);
1903 g_idle_add (function: idle_quit_loop, NULL);
1904 g_main_loop_run (loop);
1905 g_assert (callback_ran == FALSE);
1906
1907 while (g_atomic_int_get (&state) == 2)
1908 g_cond_wait (cond: &roca_cond_1, mutex: &roca_mutex_1);
1909 g_assert_cmpint (g_atomic_int_get (&state), ==, 5);
1910 g_assert (!g_task_get_return_on_cancel (task));
1911
1912 g_main_loop_run (loop);
1913 g_assert (callback_ran == TRUE);
1914 g_assert_true (notification_emitted);
1915
1916 while (g_atomic_int_get (&state) == 5)
1917 g_cond_wait (cond: &roca_cond_2, mutex: &roca_mutex_2);
1918 g_assert_cmpint (g_atomic_int_get (&state), ==, 7);
1919
1920 g_object_unref (object: cancellable);
1921 g_mutex_unlock (mutex: &roca_mutex_1);
1922 g_mutex_unlock (mutex: &roca_mutex_2);
1923 g_object_unref (object: task);
1924}
1925
1926/* test_return_pointer: memory management of pointer returns */
1927
1928static void
1929test_return_pointer (void)
1930{
1931 GObject *object, *ret;
1932 GTask *task;
1933 GCancellable *cancellable;
1934 GError *error = NULL;
1935
1936 /* If we don't read back the return value, the task will
1937 * run its destroy notify.
1938 */
1939 object = (GObject *)g_dummy_object_new ();
1940 g_assert_cmpint (object->ref_count, ==, 1);
1941 g_object_add_weak_pointer (object, weak_pointer_location: (gpointer *)&object);
1942
1943 task = g_task_new (NULL, NULL, NULL, NULL);
1944 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
1945 g_task_return_pointer (task, result: object, result_destroy: g_object_unref);
1946 g_assert_cmpint (object->ref_count, ==, 1);
1947
1948 /* Task and object are reffed until the :completed notification in idle. */
1949 g_object_unref (object: task);
1950 g_assert_nonnull (task);
1951 g_assert_nonnull (object);
1952
1953 wait_for_completed_notification (task);
1954
1955 g_assert_null (task);
1956 g_assert_null (object);
1957
1958 /* Likewise, if the return value is overwritten by an error */
1959 object = (GObject *)g_dummy_object_new ();
1960 g_assert_cmpint (object->ref_count, ==, 1);
1961 g_object_add_weak_pointer (object, weak_pointer_location: (gpointer *)&object);
1962
1963 cancellable = g_cancellable_new ();
1964 task = g_task_new (NULL, cancellable, NULL, NULL);
1965 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
1966 g_task_return_pointer (task, result: object, result_destroy: g_object_unref);
1967 g_assert_cmpint (object->ref_count, ==, 1);
1968 g_cancellable_cancel (cancellable);
1969 g_assert_cmpint (object->ref_count, ==, 1);
1970
1971 ret = g_task_propagate_pointer (task, error: &error);
1972 g_assert (ret == NULL);
1973 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1974 g_clear_error (err: &error);
1975 g_assert_cmpint (object->ref_count, ==, 1);
1976
1977 g_object_unref (object: task);
1978 g_object_unref (object: cancellable);
1979 g_assert_nonnull (task);
1980 g_assert_nonnull (object);
1981
1982 wait_for_completed_notification (task);
1983
1984 g_assert_null (task);
1985 g_assert_null (object);
1986
1987 /* If we read back the return value, we steal its ref */
1988 object = (GObject *)g_dummy_object_new ();
1989 g_assert_cmpint (object->ref_count, ==, 1);
1990 g_object_add_weak_pointer (object, weak_pointer_location: (gpointer *)&object);
1991
1992 task = g_task_new (NULL, NULL, NULL, NULL);
1993 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
1994 g_task_return_pointer (task, result: object, result_destroy: g_object_unref);
1995 g_assert_cmpint (object->ref_count, ==, 1);
1996
1997 ret = g_task_propagate_pointer (task, error: &error);
1998 g_assert_no_error (error);
1999 g_assert (ret == object);
2000 g_assert_cmpint (object->ref_count, ==, 1);
2001
2002 g_object_unref (object: task);
2003 g_assert_nonnull (task);
2004 g_assert_cmpint (object->ref_count, ==, 1);
2005 g_object_unref (object);
2006 g_assert (object == NULL);
2007
2008 wait_for_completed_notification (task);
2009 g_assert_null (task);
2010}
2011
2012static void
2013test_return_value (void)
2014{
2015 GObject *object;
2016 GValue value = G_VALUE_INIT;
2017 GValue ret = G_VALUE_INIT;
2018 GTask *task;
2019 GError *error = NULL;
2020
2021 object = (GObject *)g_dummy_object_new ();
2022 g_assert_cmpint (object->ref_count, ==, 1);
2023 g_object_add_weak_pointer (object, weak_pointer_location: (gpointer *)&object);
2024
2025 g_value_init (value: &value, G_TYPE_OBJECT);
2026 g_value_set_object (value: &value, v_object: object);
2027 g_assert_cmpint (object->ref_count, ==, 2);
2028
2029 task = g_task_new (NULL, NULL, NULL, NULL);
2030 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
2031 g_task_return_value (task, result: &value);
2032 g_assert_cmpint (object->ref_count, ==, 3);
2033
2034 g_assert_true (g_task_propagate_value (task, &ret, &error));
2035 g_assert_no_error (error);
2036 g_assert_true (g_value_get_object (&ret) == object);
2037 g_assert_cmpint (object->ref_count, ==, 3);
2038
2039 g_object_unref (object: task);
2040 g_assert_nonnull (task);
2041 wait_for_completed_notification (task);
2042 g_assert_null (task);
2043
2044 g_assert_cmpint (object->ref_count, ==, 3);
2045 g_value_unset (value: &ret);
2046 g_assert_cmpint (object->ref_count, ==, 2);
2047 g_value_unset (value: &value);
2048 g_assert_cmpint (object->ref_count, ==, 1);
2049 g_object_unref (object);
2050 g_assert_null (object);
2051}
2052
2053/* test_object_keepalive: GTask takes a ref on its source object */
2054
2055static GObject *keepalive_object;
2056
2057static void
2058keepalive_callback (GObject *object,
2059 GAsyncResult *result,
2060 gpointer user_data)
2061{
2062 gssize *result_out = user_data;
2063 GError *error = NULL;
2064
2065 g_assert (object == keepalive_object);
2066 g_assert (g_task_is_valid (result, object));
2067 g_assert (g_async_result_get_user_data (result) == user_data);
2068 g_assert (!g_task_had_error (G_TASK (result)));
2069 g_assert_false (g_task_get_completed (G_TASK (result)));
2070
2071 *result_out = g_task_propagate_int (G_TASK (result), error: &error);
2072 g_assert_no_error (error);
2073
2074 g_assert (!g_task_had_error (G_TASK (result)));
2075
2076 g_main_loop_quit (loop);
2077}
2078
2079static void
2080test_object_keepalive (void)
2081{
2082 GObject *object;
2083 GTask *task;
2084 gssize result;
2085 int ref_count;
2086 gboolean notification_emitted = FALSE;
2087
2088 keepalive_object = object = (GObject *)g_dummy_object_new ();
2089 g_object_add_weak_pointer (object, weak_pointer_location: (gpointer *)&object);
2090
2091 task = g_task_new (source_object: object, NULL, callback: keepalive_callback, callback_data: &result);
2092 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
2093 g_signal_connect (task, "notify::completed",
2094 (GCallback) completed_cb, &notification_emitted);
2095
2096 ref_count = object->ref_count;
2097 g_assert_cmpint (ref_count, >, 1);
2098
2099 g_assert (g_task_get_source_object (task) == object);
2100 g_assert (g_async_result_get_source_object (G_ASYNC_RESULT (task)) == object);
2101 g_assert_cmpint (object->ref_count, ==, ref_count + 1);
2102 g_object_unref (object);
2103
2104 g_object_unref (object);
2105 g_assert (object != NULL);
2106
2107 g_task_return_int (task, result: magic);
2108 g_main_loop_run (loop);
2109
2110 g_assert (object != NULL);
2111 g_assert_cmpint (result, ==, magic);
2112 g_assert_true (notification_emitted);
2113
2114 g_object_unref (object: task);
2115 g_assert (task == NULL);
2116 g_assert (object == NULL);
2117}
2118
2119/* test_legacy_error: legacy GSimpleAsyncResult handling */
2120static void test_legacy_error (void);
2121
2122static void
2123legacy_error_callback (GObject *object,
2124 GAsyncResult *result,
2125 gpointer user_data)
2126{
2127 gssize *result_out = user_data;
2128 GError *error = NULL;
2129
2130 g_assert (object == NULL);
2131 g_assert (g_async_result_is_tagged (result, test_legacy_error));
2132 g_assert (g_async_result_get_user_data (result) == user_data);
2133
2134 if (g_async_result_legacy_propagate_error (res: result, error: &error))
2135 {
2136 g_assert (!g_task_is_valid (result, object));
2137 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2138 g_assert (g_simple_async_result_is_valid (result, object, test_legacy_error));
2139 G_GNUC_END_IGNORE_DEPRECATIONS;
2140
2141 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
2142 *result_out = -2;
2143 g_clear_error (err: &error);
2144 }
2145 else
2146 {
2147 g_assert (g_task_is_valid (result, object));
2148
2149 *result_out = g_task_propagate_int (G_TASK (result), NULL);
2150 /* Might be error, might not */
2151 }
2152
2153 g_main_loop_quit (loop);
2154}
2155
2156static gboolean
2157legacy_error_return (gpointer user_data)
2158{
2159 if (G_IS_TASK (user_data))
2160 {
2161 GTask *task = user_data;
2162
2163 g_task_return_int (task, result: magic);
2164 g_object_unref (object: task);
2165 }
2166 else
2167 {
2168 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
2169
2170 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2171 g_simple_async_result_set_error (simple,
2172 G_IO_ERROR,
2173 code: G_IO_ERROR_FAILED,
2174 format: "Failed");
2175 g_simple_async_result_complete (simple);
2176 G_GNUC_END_IGNORE_DEPRECATIONS;
2177 g_object_unref (object: simple);
2178 }
2179
2180 return FALSE;
2181}
2182
2183static void
2184test_legacy_error (void)
2185{
2186 GTask *task;
2187 GSimpleAsyncResult *simple;
2188 gssize result;
2189
2190 /* GTask success */
2191 task = g_task_new (NULL, NULL, callback: legacy_error_callback, callback_data: &result);
2192 g_task_set_source_tag (task, test_legacy_error);
2193 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
2194
2195 g_idle_add (function: legacy_error_return, data: task);
2196 g_main_loop_run (loop);
2197
2198 g_assert_cmpint (result, ==, magic);
2199 g_assert (task == NULL);
2200
2201 /* GTask error */
2202 task = g_task_new (NULL, NULL, callback: legacy_error_callback, callback_data: &result);
2203 g_task_set_source_tag (task, test_legacy_error);
2204 g_object_add_weak_pointer (G_OBJECT (task), weak_pointer_location: (gpointer *)&task);
2205
2206 g_task_return_new_error (task, G_IO_ERROR, code: G_IO_ERROR_FAILED,
2207 format: "Failed");
2208 g_object_unref (object: task);
2209 g_main_loop_run (loop);
2210
2211 g_assert_cmpint (result, ==, -1);
2212 g_assert (task == NULL);
2213
2214 /* GSimpleAsyncResult error */
2215 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2216 simple = g_simple_async_result_new (NULL, callback: legacy_error_callback, user_data: &result,
2217 source_tag: test_legacy_error);
2218 G_GNUC_END_IGNORE_DEPRECATIONS;
2219 g_object_add_weak_pointer (G_OBJECT (simple), weak_pointer_location: (gpointer *)&simple);
2220
2221 g_idle_add (function: legacy_error_return, data: simple);
2222 g_main_loop_run (loop);
2223
2224 g_assert_cmpint (result, ==, -2);
2225 g_assert (simple == NULL);
2226}
2227
2228/* Various helper functions for the return tests below. */
2229static void
2230task_complete_cb (GObject *source,
2231 GAsyncResult *result,
2232 gpointer user_data)
2233{
2234 GTask *task = G_TASK (result);
2235 guint *calls = user_data;
2236
2237 g_assert_cmpint (++*calls, <=, 1);
2238
2239 /* Propagate the result, so it’s removed from the task’s internal state. */
2240 g_task_propagate_boolean (task, NULL);
2241}
2242
2243static void
2244return_twice (GTask *task)
2245{
2246 gboolean error_first = GPOINTER_TO_UINT (g_task_get_task_data (task));
2247
2248 if (error_first)
2249 {
2250 g_task_return_new_error (task, G_IO_ERROR, code: G_IO_ERROR_UNKNOWN, format: "oh no");
2251 g_task_return_boolean (task, TRUE);
2252 }
2253 else
2254 {
2255 g_task_return_boolean (task, TRUE);
2256 g_task_return_new_error (task, G_IO_ERROR, code: G_IO_ERROR_UNKNOWN, format: "oh no");
2257 }
2258}
2259
2260static gboolean
2261idle_cb (gpointer user_data)
2262{
2263 GTask *task = user_data;
2264 return_twice (task);
2265 g_object_unref (object: task);
2266
2267 return G_SOURCE_REMOVE;
2268}
2269
2270static void
2271test_return_permutation (gboolean error_first,
2272 gboolean return_in_idle)
2273{
2274 guint calls = 0;
2275 GTask *task = NULL;
2276
2277 g_test_bug (bug_uri_snippet: "https://gitlab.gnome.org/GNOME/glib/issues/1525");
2278
2279 task = g_task_new (NULL, NULL, callback: task_complete_cb, callback_data: &calls);
2280 g_task_set_task_data (task, GUINT_TO_POINTER (error_first), NULL);
2281
2282 if (return_in_idle)
2283 g_idle_add (function: idle_cb, g_object_ref (task));
2284 else
2285 return_twice (task);
2286
2287 while (calls == 0)
2288 g_main_context_iteration (NULL, TRUE);
2289
2290 g_assert_cmpint (calls, ==, 1);
2291
2292 g_object_unref (object: task);
2293}
2294
2295/* Test that calling g_task_return_boolean() after g_task_return_error(), when
2296 * returning in an idle callback, correctly results in a critical warning. */
2297static void
2298test_return_in_idle_error_first (void)
2299{
2300 if (g_test_subprocess ())
2301 {
2302 test_return_permutation (TRUE, TRUE);
2303 return;
2304 }
2305
2306 g_test_trap_subprocess (NULL, usec_timeout: 0, test_flags: 0);
2307 g_test_trap_assert_failed ();
2308 g_test_trap_assert_stderr ("*CRITICAL*assertion '!task->ever_returned' failed*");
2309}
2310
2311/* Test that calling g_task_return_error() after g_task_return_boolean(), when
2312 * returning in an idle callback, correctly results in a critical warning. */
2313static void
2314test_return_in_idle_value_first (void)
2315{
2316 if (g_test_subprocess ())
2317 {
2318 test_return_permutation (FALSE, TRUE);
2319 return;
2320 }
2321
2322 g_test_trap_subprocess (NULL, usec_timeout: 0, test_flags: 0);
2323 g_test_trap_assert_failed ();
2324 g_test_trap_assert_stderr ("*CRITICAL*assertion '!task->ever_returned' failed*");
2325}
2326
2327/* Test that calling g_task_return_boolean() after g_task_return_error(), when
2328 * returning synchronously, correctly results in a critical warning. */
2329static void
2330test_return_error_first (void)
2331{
2332 if (g_test_subprocess ())
2333 {
2334 test_return_permutation (TRUE, FALSE);
2335 return;
2336 }
2337
2338 g_test_trap_subprocess (NULL, usec_timeout: 0, test_flags: 0);
2339 g_test_trap_assert_failed ();
2340 g_test_trap_assert_stderr ("*CRITICAL*assertion '!task->ever_returned' failed*");
2341}
2342
2343/* Test that calling g_task_return_error() after g_task_return_boolean(), when
2344 * returning synchronously, correctly results in a critical warning. */
2345static void
2346test_return_value_first (void)
2347{
2348 if (g_test_subprocess ())
2349 {
2350 test_return_permutation (FALSE, FALSE);
2351 return;
2352 }
2353
2354 g_test_trap_subprocess (NULL, usec_timeout: 0, test_flags: 0);
2355 g_test_trap_assert_failed ();
2356 g_test_trap_assert_stderr ("*CRITICAL*assertion '!task->ever_returned' failed*");
2357}
2358
2359int
2360main (int argc, char **argv)
2361{
2362 int ret;
2363
2364 g_test_init (argc: &argc, argv: &argv, NULL);
2365
2366 loop = g_main_loop_new (NULL, FALSE);
2367 main_thread = g_thread_self ();
2368 magic = g_get_monotonic_time ();
2369
2370 g_test_add_func (testpath: "/gtask/basic", test_func: test_basic);
2371 g_test_add_func (testpath: "/gtask/error", test_func: test_error);
2372 g_test_add_func (testpath: "/gtask/return-from-same-iteration", test_func: test_return_from_same_iteration);
2373 g_test_add_func (testpath: "/gtask/return-from-toplevel", test_func: test_return_from_toplevel);
2374 g_test_add_func (testpath: "/gtask/return-from-anon-thread", test_func: test_return_from_anon_thread);
2375 g_test_add_func (testpath: "/gtask/return-from-wrong-thread", test_func: test_return_from_wrong_thread);
2376 g_test_add_func (testpath: "/gtask/no-callback", test_func: test_no_callback);
2377 g_test_add_func (testpath: "/gtask/report-error", test_func: test_report_error);
2378 g_test_add_func (testpath: "/gtask/priority", test_func: test_priority);
2379 g_test_add_func (testpath: "/gtask/name", test_func: test_name);
2380 g_test_add_func (testpath: "/gtask/asynchronous-cancellation", test_func: test_asynchronous_cancellation);
2381 g_test_add_func (testpath: "/gtask/check-cancellable", test_func: test_check_cancellable);
2382 g_test_add_func (testpath: "/gtask/return-if-cancelled", test_func: test_return_if_cancelled);
2383 g_test_add_func (testpath: "/gtask/run-in-thread", test_func: test_run_in_thread);
2384 g_test_add_func (testpath: "/gtask/run-in-thread-sync", test_func: test_run_in_thread_sync);
2385 g_test_add_func (testpath: "/gtask/run-in-thread-priority", test_func: test_run_in_thread_priority);
2386 g_test_add_func (testpath: "/gtask/run-in-thread-nested", test_func: test_run_in_thread_nested);
2387 g_test_add_func (testpath: "/gtask/run-in-thread-overflow", test_func: test_run_in_thread_overflow);
2388 g_test_add_func (testpath: "/gtask/return-on-cancel", test_func: test_return_on_cancel);
2389 g_test_add_func (testpath: "/gtask/return-on-cancel-sync", test_func: test_return_on_cancel_sync);
2390 g_test_add_func (testpath: "/gtask/return-on-cancel-atomic", test_func: test_return_on_cancel_atomic);
2391 g_test_add_func (testpath: "/gtask/return-pointer", test_func: test_return_pointer);
2392 g_test_add_func (testpath: "/gtask/return-value", test_func: test_return_value);
2393 g_test_add_func (testpath: "/gtask/object-keepalive", test_func: test_object_keepalive);
2394 g_test_add_func (testpath: "/gtask/legacy-error", test_func: test_legacy_error);
2395 g_test_add_func (testpath: "/gtask/return/in-idle/error-first", test_func: test_return_in_idle_error_first);
2396 g_test_add_func (testpath: "/gtask/return/in-idle/value-first", test_func: test_return_in_idle_value_first);
2397 g_test_add_func (testpath: "/gtask/return/error-first", test_func: test_return_error_first);
2398 g_test_add_func (testpath: "/gtask/return/value-first", test_func: test_return_value_first);
2399
2400 ret = g_test_run();
2401
2402 g_main_loop_unref (loop);
2403
2404 return ret;
2405}
2406

source code of gtk/subprojects/glib/gio/tests/task.c