• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 static GMainLoop *loop;
16 static GThread *main_thread;
17 static 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 
24 static gboolean
idle_quit_loop(gpointer user_data)25 idle_quit_loop (gpointer user_data)
26 {
27   g_main_loop_quit (loop);
28   return FALSE;
29 }
30 
31 static void
completed_cb(GObject * gobject,GParamSpec * pspec,gpointer user_data)32 completed_cb (GObject    *gobject,
33               GParamSpec *pspec,
34               gpointer    user_data)
35 {
36 	gboolean *notification_emitted = user_data;
37 	*notification_emitted = TRUE;
38 }
39 
40 static void
wait_for_completed_notification(GTask * task)41 wait_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 (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), "completed", &is_completed, NULL);
57   g_assert_true (is_completed);
58 
59   g_object_unref (task);
60 }
61 
62 /* test_basic */
63 
64 static void
basic_callback(GObject * object,GAsyncResult * result,gpointer user_data)65 basic_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);
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 
86 static gboolean
basic_return(gpointer user_data)87 basic_return (gpointer user_data)
88 {
89   GTask *task = user_data;
90 
91   g_task_return_int (task, magic);
92   g_object_unref (task);
93 
94   return FALSE;
95 }
96 
97 static void
basic_destroy_notify(gpointer user_data)98 basic_destroy_notify (gpointer user_data)
99 {
100   gboolean *destroyed = user_data;
101 
102   *destroyed = TRUE;
103 }
104 
105 static void
test_basic(void)106 test_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, basic_callback, &result);
114   g_task_set_task_data (task, &task_data_destroyed, basic_destroy_notify);
115   g_object_add_weak_pointer (G_OBJECT (task), (gpointer *)&task);
116   g_signal_connect (task, "notify::completed",
117                     (GCallback) completed_cb, &notification_emitted);
118 
119   g_idle_add (basic_return, 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 
130 static void
error_callback(GObject * object,GAsyncResult * result,gpointer user_data)131 error_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);
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 
153 static gboolean
error_return(gpointer user_data)154 error_return (gpointer user_data)
155 {
156   GTask *task = user_data;
157 
158   g_task_return_new_error (task,
159                            G_IO_ERROR, G_IO_ERROR_FAILED,
160                            "Failed");
161   g_object_unref (task);
162 
163   return FALSE;
164 }
165 
166 static void
error_destroy_notify(gpointer user_data)167 error_destroy_notify (gpointer user_data)
168 {
169   gboolean *destroyed = user_data;
170 
171   *destroyed = TRUE;
172 }
173 
174 static void
test_error(void)175 test_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, error_callback, &result);
184   g_object_add_weak_pointer (G_OBJECT (task), (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, &first_task_data_destroyed, 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, &second_task_data_destroyed, error_destroy_notify);
194   g_assert (first_task_data_destroyed == TRUE);
195   g_assert (second_task_data_destroyed == FALSE);
196 
197   g_idle_add (error_return, 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  */
210 gboolean same_result = FALSE;
211 gboolean same_notification_emitted = FALSE;
212 
213 static void
same_callback(GObject * object,GAsyncResult * result,gpointer user_data)214 same_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);
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 
235 static gboolean
same_start(gpointer user_data)236 same_start (gpointer user_data)
237 {
238   gpointer *weak_pointer = user_data;
239   GTask *task;
240 
241   task = g_task_new (NULL, NULL, same_callback, &same_result);
242   *weak_pointer = task;
243   g_object_add_weak_pointer (G_OBJECT (task), 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 (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 
258 static void
test_return_from_same_iteration(void)259 test_return_from_same_iteration (void)
260 {
261   gpointer weak_pointer;
262 
263   g_idle_add (same_start, &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  */
274 gboolean toplevel_notification_emitted = FALSE;
275 
276 static void
toplevel_callback(GObject * object,GAsyncResult * result,gpointer user_data)277 toplevel_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);
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 
298 static void
test_return_from_toplevel(void)299 test_return_from_toplevel (void)
300 {
301   GTask *task;
302   gboolean result = FALSE;
303 
304   task = g_task_new (NULL, NULL, toplevel_callback, &result);
305   g_object_add_weak_pointer (G_OBJECT (task), (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 (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 
329 gboolean anon_thread_notification_emitted = FALSE;
330 GThread *anon_thread;
331 
332 static void
anon_callback(GObject * object,GAsyncResult * result,gpointer user_data)333 anon_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);
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 
356 static gpointer
anon_thread_func(gpointer user_data)357 anon_thread_func (gpointer user_data)
358 {
359   GTask *task = user_data;
360 
361   g_task_return_int (task, magic);
362   g_object_unref (task);
363 
364   return NULL;
365 }
366 
367 static gboolean
anon_start(gpointer user_data)368 anon_start (gpointer user_data)
369 {
370   GTask *task = user_data;
371 
372   anon_thread = g_thread_new ("test_return_from_anon_thread",
373                               anon_thread_func, task);
374   return FALSE;
375 }
376 
377 static void
test_return_from_anon_thread(void)378 test_return_from_anon_thread (void)
379 {
380   GTask *task;
381   gssize result = 0;
382 
383   task = g_task_new (NULL, NULL, anon_callback, &result);
384   g_object_add_weak_pointer (G_OBJECT (task), (gpointer *)&task);
385   g_signal_connect (task, "notify::completed",
386                     (GCallback) completed_cb,
387                     &anon_thread_notification_emitted);
388 
389   g_idle_add (anon_start, task);
390   g_main_loop_run (loop);
391 
392   g_thread_join (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 
404 gboolean wrong_thread_notification_emitted = FALSE;
405 GThread *wrong_thread;
406 
407 static void
wrong_callback(GObject * object,GAsyncResult * result,gpointer user_data)408 wrong_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);
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 
431 static gpointer
wrong_thread_func(gpointer user_data)432 wrong_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, magic);
443   g_object_unref (task);
444 
445   g_main_context_pop_thread_default (context);
446   g_main_context_unref (context);
447 
448   return NULL;
449 }
450 
451 static gboolean
wrong_start(gpointer user_data)452 wrong_start (gpointer user_data)
453 {
454   GTask *task = user_data;
455 
456   wrong_thread = g_thread_new ("test_return_from_anon_thread",
457                                wrong_thread_func, task);
458   return FALSE;
459 }
460 
461 static void
test_return_from_wrong_thread(void)462 test_return_from_wrong_thread (void)
463 {
464   GTask *task;
465   gssize result = 0;
466 
467   task = g_task_new (NULL, NULL, wrong_callback, &result);
468   g_object_add_weak_pointer (G_OBJECT (task), (gpointer *)&task);
469   g_signal_connect (task, "notify::completed",
470                     (GCallback) completed_cb,
471                     &wrong_thread_notification_emitted);
472 
473   g_idle_add (wrong_start, task);
474   g_main_loop_run (loop);
475 
476   g_thread_join (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 
485 static void
test_no_callback(void)486 test_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), (gpointer *)&task);
492 
493   g_task_return_boolean (task, TRUE);
494   g_object_unref (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 
505 static void test_report_error (void);
506 gboolean error_notification_emitted = FALSE;
507 
508 static void
report_callback(GObject * object,GAsyncResult * result,gpointer user_data)509 report_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);
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);
534   g_signal_connect (result, "notify::completed",
535                     (GCallback) completed_cb, &error_notification_emitted);
536 
537   g_main_loop_quit (loop);
538 }
539 
540 static void
test_report_error(void)541 test_report_error (void)
542 {
543   gpointer weak_pointer = (gpointer)-1;
544 
545   g_task_report_new_error (NULL, report_callback, &weak_pointer,
546                            test_report_error,
547                            G_IO_ERROR, G_IO_ERROR_FAILED,
548                            "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 
557 static int counter = 0;
558 
559 static void
priority_callback(GObject * object,GAsyncResult * result,gpointer user_data)560 priority_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);
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 
584 static void
test_priority(void)585 test_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, priority_callback, &ret1);
596   g_task_set_priority (t1, G_PRIORITY_DEFAULT);
597   g_task_return_boolean (t1, TRUE);
598   g_object_unref (t1);
599 
600   t2 = g_task_new (NULL, NULL, priority_callback, &ret2);
601   g_task_set_priority (t2, G_PRIORITY_HIGH);
602   g_task_return_boolean (t2, TRUE);
603   g_object_unref (t2);
604 
605   t3 = g_task_new (NULL, NULL, priority_callback, &ret3);
606   g_task_set_priority (t3, G_PRIORITY_LOW);
607   g_task_return_boolean (t3, TRUE);
608   g_object_unref (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. */
618 static void name_callback (GObject      *object,
619                            GAsyncResult *result,
620                            gpointer      user_data);
621 
622 static void
test_name(void)623 test_name (void)
624 {
625   GTask *t1 = NULL;
626   gchar *name1 = NULL;
627 
628   t1 = g_task_new (NULL, NULL, name_callback, &name1);
629   g_task_set_name (t1, "some task");
630   g_task_return_boolean (t1, TRUE);
631   g_object_unref (t1);
632 
633   g_main_loop_run (loop);
634 
635   g_assert_cmpstr (name1, ==, "some task");
636 
637   g_free (name1);
638 }
639 
640 static void
name_callback(GObject * object,GAsyncResult * result,gpointer user_data)641 name_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 (g_task_get_name (G_TASK (result)));
650 
651   g_task_propagate_boolean (G_TASK (result), &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  */
668 static void
asynchronous_cancellation_callback(GObject * object,GAsyncResult * result,gpointer user_data)669 asynchronous_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);
686   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
687   g_clear_error (&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  */
698 static gboolean
asynchronous_cancellation_cancel_task(gpointer user_data)699 asynchronous_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  */
717 static void
asynchronous_cancellation_cancelled(GCancellable * cancellable,gpointer user_data)718 asynchronous_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 (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  */
741 static gboolean
asynchronous_cancellation_run_task(gpointer user_data)742 asynchronous_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  */
763 static void
test_asynchronous_cancellation(void)764 test_asynchronous_cancellation (void)
765 {
766   guint i;
767 
768   g_test_bug ("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, asynchronous_cancellation_callback, NULL);
783       g_cancellable_connect (cancellable, (GCallback) asynchronous_cancellation_cancelled, task, NULL);
784       g_signal_connect (task, "notify::completed", (GCallback) completed_cb, &notification_emitted);
785 
786       run_task_id = g_idle_add (asynchronous_cancellation_run_task, task);
787       g_source_set_name_by_id (run_task_id, "[test_asynchronous_cancellation] run_task");
788       g_task_set_task_data (task, GUINT_TO_POINTER (run_task_id), NULL);
789 
790       g_timeout_add (50, asynchronous_cancellation_cancel_task, 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 (cancellable);
798       g_object_unref (task);
799     }
800 }
801 
802 /* test_check_cancellable: cancellation overrides return value */
803 
804 enum {
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 
811 static void
cancel_callback(GObject * object,GAsyncResult * result,gpointer user_data)812 cancel_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))
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 
855 static void
test_check_cancellable(void)856 test_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, cancel_callback,
867                          GINT_TO_POINTER (state));
868       g_task_set_check_cancellable (task, (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 (task);
878       g_cancellable_reset (cancellable);
879     }
880 
881   g_object_unref (cancellable);
882 }
883 
884 /* test_return_if_cancelled */
885 
886 static void
return_if_cancelled_callback(GObject * object,GAsyncResult * result,gpointer user_data)887 return_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);
900   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
901   g_clear_error (&error);
902 
903   g_assert (g_task_had_error (G_TASK (result)));
904 
905   g_main_loop_quit (loop);
906 }
907 
908 static void
test_return_if_cancelled(void)909 test_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, 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 (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, 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 (task);
944   g_assert_true (notification_emitted);
945   g_object_unref (cancellable);
946 }
947 
948 /* test_run_in_thread */
949 
950 static GMutex run_in_thread_mutex;
951 static GCond run_in_thread_cond;
952 
953 static void
task_weak_notify(gpointer user_data,GObject * ex_task)954 task_weak_notify (gpointer  user_data,
955                   GObject  *ex_task)
956 {
957   gboolean *weak_notify_ran = user_data;
958 
959   g_mutex_lock (&run_in_thread_mutex);
960   g_atomic_int_set (weak_notify_ran, TRUE);
961   g_cond_signal (&run_in_thread_cond);
962   g_mutex_unlock (&run_in_thread_mutex);
963 }
964 
965 static void
run_in_thread_callback(GObject * object,GAsyncResult * result,gpointer user_data)966 run_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);
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 
993 static void
run_in_thread_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)994 run_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 (&run_in_thread_mutex);
1010   g_atomic_int_set (thread_ran, TRUE);
1011   g_cond_signal (&run_in_thread_cond);
1012   g_mutex_unlock (&run_in_thread_mutex);
1013 
1014   g_task_return_int (task, magic);
1015 }
1016 
1017 static void
test_run_in_thread(void)1018 test_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, run_in_thread_callback, &done);
1027   g_task_set_name (task, "test_run_in_thread name");
1028   g_object_weak_ref (G_OBJECT (task), task_weak_notify, (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, (gpointer)&thread_ran, NULL);
1033   g_task_run_in_thread (task, run_in_thread_thread);
1034 
1035   g_mutex_lock (&run_in_thread_mutex);
1036   while (!g_atomic_int_get (&thread_ran))
1037     g_cond_wait (&run_in_thread_cond, &run_in_thread_mutex);
1038   g_mutex_unlock (&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 (task);
1051 
1052   g_mutex_lock (&run_in_thread_mutex);
1053   while (!g_atomic_int_get (&weak_notify_ran))
1054     g_cond_wait (&run_in_thread_cond, &run_in_thread_mutex);
1055   g_mutex_unlock (&run_in_thread_mutex);
1056 }
1057 
1058 /* test_run_in_thread_sync */
1059 
1060 static void
run_in_thread_sync_callback(GObject * object,GAsyncResult * result,gpointer user_data)1061 run_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 
1069 static void
run_in_thread_sync_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1070 run_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, magic);
1086 }
1087 
1088 static void
test_run_in_thread_sync(void)1089 test_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, 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, &thread_ran, NULL);
1103   g_task_run_in_thread_sync (task, 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);
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 (task);
1118 }
1119 
1120 /* test_run_in_thread_priority */
1121 
1122 static GMutex fake_task_mutex, last_fake_task_mutex;
1123 static gint sequence_number = 0;
1124 
1125 static void
quit_main_loop_callback(GObject * object,GAsyncResult * result,gpointer user_data)1126 quit_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);
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 
1150 static void
set_sequence_number_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1151 set_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 
1162 static void
fake_task_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1163 fake_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
1176 static int fake_tasks_running;
1177 
1178 static void
fake_task_callback(GObject * source,GAsyncResult * result,gpointer user_data)1179 fake_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 
1187 static void
clog_up_thread_pool(void)1188 clog_up_thread_pool (void)
1189 {
1190   GTask *task;
1191   int i;
1192 
1193   g_thread_pool_stop_unused_threads ();
1194 
1195   g_mutex_lock (&fake_task_mutex);
1196   for (i = 0; i < G_TASK_THREAD_POOL_SIZE - 1; i++)
1197     {
1198       task = g_task_new (NULL, NULL, fake_task_callback, NULL);
1199       g_task_set_task_data (task, &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, fake_task_thread);
1204       g_object_unref (task);
1205       fake_tasks_running++;
1206     }
1207 
1208   g_mutex_lock (&last_fake_task_mutex);
1209   task = g_task_new (NULL, NULL, NULL, NULL);
1210   g_task_set_task_data (task, &last_fake_task_mutex, NULL);
1211   g_task_set_priority (task, G_PRIORITY_HIGH * 2);
1212   g_task_run_in_thread (task, fake_task_thread);
1213   g_object_unref (task);
1214 }
1215 
1216 static void
unclog_thread_pool(void)1217 unclog_thread_pool (void)
1218 {
1219   g_mutex_unlock (&fake_task_mutex);
1220   g_main_loop_run (loop);
1221 }
1222 
1223 static void
test_run_in_thread_priority(void)1224 test_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, &seq_a, NULL);
1235   g_task_run_in_thread (task, set_sequence_number_thread);
1236   g_object_unref (task);
1237 
1238   task = g_task_new (NULL, NULL, quit_main_loop_callback, NULL);
1239   g_task_set_task_data (task, &seq_b, NULL);
1240   g_task_set_priority (task, G_PRIORITY_LOW);
1241   g_task_run_in_thread (task, set_sequence_number_thread);
1242   g_object_unref (task);
1243 
1244   task = g_task_new (NULL, NULL, NULL, NULL);
1245   g_task_set_task_data (task, &seq_c, NULL);
1246   g_task_set_priority (task, G_PRIORITY_HIGH);
1247   g_task_run_in_thread (task, set_sequence_number_thread);
1248   g_object_unref (task);
1249 
1250   cancellable = g_cancellable_new ();
1251   task = g_task_new (NULL, cancellable, NULL, NULL);
1252   g_task_set_task_data (task, &seq_d, NULL);
1253   g_task_run_in_thread (task, set_sequence_number_thread);
1254   g_cancellable_cancel (cancellable);
1255   g_object_unref (cancellable);
1256   g_object_unref (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 (&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 
1277 static void
run_nested_task_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1278 run_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 (nested, nested_tasks_left, NULL);
1290       g_task_run_in_thread_sync (nested, run_nested_task_thread);
1291       g_object_unref (nested);
1292     }
1293 
1294   g_task_return_boolean (task, TRUE);
1295 }
1296 
1297 static void
test_run_in_thread_nested(void)1298 test_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, quit_main_loop_callback, NULL);
1306   g_task_set_task_data (task, &nested_tasks_left, NULL);
1307   g_task_run_in_thread (task, run_nested_task_thread);
1308   g_object_unref (task);
1309 
1310   g_mutex_unlock (&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  */
1319 static GMutex overflow_mutex;
1320 static guint overflow_completed;
1321 
1322 static void
run_overflow_task_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1323 run_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 (&overflow_mutex);
1338       g_mutex_unlock (&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 
1350 static void
test_run_in_thread_overflow(void)1351 test_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 (buf, 0, sizeof (buf));
1367   cancellable = g_cancellable_new ();
1368 
1369   g_mutex_lock (&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, buf + i, NULL);
1375       g_task_run_in_thread (task, run_overflow_task_thread);
1376       g_object_unref (task);
1377     }
1378 
1379   if (g_test_slow ())
1380     g_usleep (5000000); /* 5 s */
1381   else
1382     g_usleep (500000);  /* 0.5 s */
1383   g_cancellable_cancel (cancellable);
1384   g_object_unref (cancellable);
1385 
1386   g_mutex_unlock (&overflow_mutex);
1387 
1388   /* Wait for all tasks to complete. */
1389   while (g_atomic_int_get (&overflow_completed) != NUM_OVERFLOW_TASKS)
1390     g_usleep (1000);
1391 
1392   g_assert_cmpint (strlen (buf), ==, NUM_OVERFLOW_TASKS);
1393 
1394   i = strspn (buf, ".");
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 
1413 GMutex roc_init_mutex, roc_finish_mutex;
1414 GCond roc_init_cond, roc_finish_cond;
1415 
1416 typedef enum {
1417   THREAD_STARTING,
1418   THREAD_RUNNING,
1419   THREAD_CANCELLED,
1420   THREAD_COMPLETED
1421 } ThreadState;
1422 
1423 static void
return_on_cancel_callback(GObject * object,GAsyncResult * result,gpointer user_data)1424 return_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);
1441   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1442   g_clear_error (&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 
1451 static void
return_on_cancel_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1452 return_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 (&roc_init_mutex);
1466   *state = THREAD_RUNNING;
1467   g_cond_signal (&roc_init_cond);
1468   g_mutex_unlock (&roc_init_mutex);
1469 
1470   g_mutex_lock (&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, magic);
1477     }
1478   else
1479     *state = THREAD_CANCELLED;
1480 
1481   g_cond_signal (&roc_finish_cond);
1482   g_mutex_unlock (&roc_finish_mutex);
1483 }
1484 
1485 static void
test_return_on_cancel(void)1486 test_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, return_on_cancel_callback, &callback_ran);
1503   g_signal_connect (task, "notify::completed",
1504                     (GCallback) completed_cb, &notification_emitted);
1505 
1506   g_task_set_task_data (task, (gpointer)&thread_state, NULL);
1507   g_mutex_lock (&roc_init_mutex);
1508   g_mutex_lock (&roc_finish_mutex);
1509   g_task_run_in_thread (task, return_on_cancel_thread);
1510   g_object_unref (task);
1511 
1512   while (g_atomic_int_get (&thread_state) == THREAD_STARTING)
1513     g_cond_wait (&roc_init_cond, &roc_init_mutex);
1514   g_mutex_unlock (&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 (&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, return_on_cancel_callback, &callback_ran);
1534   g_object_weak_ref (G_OBJECT (task), task_weak_notify, (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, (gpointer)&thread_state, NULL);
1540   g_mutex_lock (&roc_init_mutex);
1541   g_mutex_lock (&roc_finish_mutex);
1542   g_task_run_in_thread (task, return_on_cancel_thread);
1543   g_object_unref (task);
1544 
1545   while (g_atomic_int_get (&thread_state) == THREAD_STARTING)
1546     g_cond_wait (&roc_init_cond, &roc_init_mutex);
1547   g_mutex_unlock (&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 (&roc_finish_cond, &roc_finish_mutex);
1561   g_mutex_unlock (&roc_finish_mutex);
1562 
1563   g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_CANCELLED);
1564   g_mutex_lock (&run_in_thread_mutex);
1565   while (!g_atomic_int_get (&weak_notify_ran))
1566     g_cond_wait (&run_in_thread_cond, &run_in_thread_mutex);
1567   g_mutex_unlock (&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, return_on_cancel_callback, &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, (gpointer)&thread_state, NULL);
1586   g_mutex_lock (&roc_init_mutex);
1587   g_mutex_lock (&roc_finish_mutex);
1588   g_task_run_in_thread (task, return_on_cancel_thread);
1589   g_object_unref (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 (&roc_init_cond, &roc_init_mutex);
1596   g_mutex_unlock (&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 (&roc_finish_cond, &roc_finish_mutex);
1602   g_mutex_unlock (&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 (cancellable);
1608 }
1609 
1610 /* test_return_on_cancel_sync */
1611 
1612 static gpointer
cancel_sync_runner_thread(gpointer task)1613 cancel_sync_runner_thread (gpointer task)
1614 {
1615   g_task_run_in_thread_sync (task, return_on_cancel_thread);
1616   return NULL;
1617 }
1618 
1619 static void
test_return_on_cancel_sync(void)1620 test_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, run_in_thread_sync_callback, NULL);
1635 
1636   g_task_set_task_data (task, (gpointer)&thread_state, NULL);
1637   g_mutex_lock (&roc_init_mutex);
1638   g_mutex_lock (&roc_finish_mutex);
1639   runner_thread = g_thread_new ("return-on-cancel-sync runner thread",
1640                                 cancel_sync_runner_thread, task);
1641 
1642   while (g_atomic_int_get (&thread_state) == THREAD_STARTING)
1643     g_cond_wait (&roc_init_cond, &roc_init_mutex);
1644   g_mutex_unlock (&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 (&roc_finish_mutex);
1650   g_thread_join (runner_thread);
1651   g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_COMPLETED);
1652 
1653   ret = g_task_propagate_int (task, &error);
1654   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1655   g_clear_error (&error);
1656   g_assert_cmpint (ret, ==, -1);
1657 
1658   g_object_unref (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, run_in_thread_sync_callback, NULL);
1665   g_task_set_return_on_cancel (task, TRUE);
1666 
1667   g_task_set_task_data (task, (gpointer)&thread_state, NULL);
1668   g_mutex_lock (&roc_init_mutex);
1669   g_mutex_lock (&roc_finish_mutex);
1670   runner_thread = g_thread_new ("return-on-cancel-sync runner thread",
1671                                 cancel_sync_runner_thread, task);
1672 
1673   while (g_atomic_int_get (&thread_state) == THREAD_STARTING)
1674     g_cond_wait (&roc_init_cond, &roc_init_mutex);
1675   g_mutex_unlock (&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 (runner_thread);
1681   g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_RUNNING);
1682 
1683   ret = g_task_propagate_int (task, &error);
1684   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1685   g_clear_error (&error);
1686   g_assert_cmpint (ret, ==, -1);
1687 
1688   g_object_unref (task);
1689 
1690   while (g_atomic_int_get (&thread_state) == THREAD_RUNNING)
1691     g_cond_wait (&roc_finish_cond, &roc_finish_mutex);
1692   g_mutex_unlock (&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, 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, (gpointer)&thread_state, NULL);
1708   g_mutex_lock (&roc_init_mutex);
1709   g_mutex_lock (&roc_finish_mutex);
1710   runner_thread = g_thread_new ("return-on-cancel-sync runner thread",
1711                                 cancel_sync_runner_thread, task);
1712 
1713   g_thread_join (runner_thread);
1714   g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_STARTING);
1715 
1716   ret = g_task_propagate_int (task, &error);
1717   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1718   g_clear_error (&error);
1719   g_assert_cmpint (ret, ==, -1);
1720 
1721   g_object_unref (task);
1722 
1723   while (g_atomic_int_get (&thread_state) == THREAD_STARTING)
1724     g_cond_wait (&roc_init_cond, &roc_init_mutex);
1725   g_mutex_unlock (&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 (&roc_finish_cond, &roc_finish_mutex);
1731   g_mutex_unlock (&roc_finish_mutex);
1732 
1733   g_assert_cmpint (g_atomic_int_get (&thread_state), ==, THREAD_CANCELLED);
1734 
1735   g_object_unref (cancellable);
1736 }
1737 
1738 /* test_return_on_cancel_atomic: turning return-on-cancel on/off is
1739  * non-racy
1740  */
1741 
1742 GMutex roca_mutex_1, roca_mutex_2;
1743 GCond roca_cond_1, roca_cond_2;
1744 
1745 static void
return_on_cancel_atomic_callback(GObject * object,GAsyncResult * result,gpointer user_data)1746 return_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);
1763   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1764   g_clear_error (&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 
1773 static void
return_on_cancel_atomic_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1774 return_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 (&roca_mutex_1);
1790   g_atomic_int_set (state, 1);
1791   g_cond_signal (&roca_cond_1);
1792   g_mutex_unlock (&roca_mutex_1);
1793 
1794   g_mutex_lock (&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 (&roca_cond_2);
1800   g_mutex_unlock (&roca_mutex_2);
1801 
1802   g_mutex_lock (&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 (&roca_cond_1);
1808   g_mutex_unlock (&roca_mutex_1);
1809 
1810   g_mutex_lock (&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 (&roca_cond_2);
1816   g_mutex_unlock (&roca_mutex_2);
1817 
1818   g_task_return_int (task, magic);
1819 }
1820 
1821 static void
test_return_on_cancel_atomic(void)1822 test_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 (&roca_mutex_1);
1832   g_mutex_lock (&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, return_on_cancel_atomic_callback, &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, (gpointer)&state, NULL);
1843   g_task_run_in_thread (task, return_on_cancel_atomic_thread);
1844   g_object_unref (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 (&roca_cond_1, &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 (&roca_cond_2, &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 (&roca_cond_1, &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 (&roca_cond_2, &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, return_on_cancel_atomic_callback, &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, (gpointer)&state, NULL);
1888   g_task_run_in_thread (task, 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 (&roca_cond_1, &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 (&roca_cond_2, &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 (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 (&roca_cond_1, &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 (&roca_cond_2, &roca_mutex_2);
1918   g_assert_cmpint (g_atomic_int_get (&state), ==, 7);
1919 
1920   g_object_unref (cancellable);
1921   g_mutex_unlock (&roca_mutex_1);
1922   g_mutex_unlock (&roca_mutex_2);
1923   g_object_unref (task);
1924 }
1925 
1926 /* test_return_pointer: memory management of pointer returns */
1927 
1928 static void
test_return_pointer(void)1929 test_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, (gpointer *)&object);
1942 
1943   task = g_task_new (NULL, NULL, NULL, NULL);
1944   g_object_add_weak_pointer (G_OBJECT (task), (gpointer *)&task);
1945   g_task_return_pointer (task, object, 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 (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, (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), (gpointer *)&task);
1966   g_task_return_pointer (task, object, 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);
1972   g_assert (ret == NULL);
1973   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1974   g_clear_error (&error);
1975   g_assert_cmpint (object->ref_count, ==, 1);
1976 
1977   g_object_unref (task);
1978   g_object_unref (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, (gpointer *)&object);
1991 
1992   task = g_task_new (NULL, NULL, NULL, NULL);
1993   g_object_add_weak_pointer (G_OBJECT (task), (gpointer *)&task);
1994   g_task_return_pointer (task, object, g_object_unref);
1995   g_assert_cmpint (object->ref_count, ==, 1);
1996 
1997   ret = g_task_propagate_pointer (task, &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 (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 
2012 static void
test_return_value(void)2013 test_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, (gpointer *)&object);
2024 
2025   g_value_init (&value, G_TYPE_OBJECT);
2026   g_value_set_object (&value, 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), (gpointer *)&task);
2031   g_task_return_value (task, &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 (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 (&ret);
2046   g_assert_cmpint (object->ref_count, ==, 2);
2047   g_value_unset (&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 
2055 static GObject *keepalive_object;
2056 
2057 static void
keepalive_callback(GObject * object,GAsyncResult * result,gpointer user_data)2058 keepalive_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);
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 
2079 static void
test_object_keepalive(void)2080 test_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, (gpointer *)&object);
2090 
2091   task = g_task_new (object, NULL, keepalive_callback, &result);
2092   g_object_add_weak_pointer (G_OBJECT (task), (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, 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 (task);
2115   g_assert (task == NULL);
2116   g_assert (object == NULL);
2117 }
2118 
2119 /* test_legacy_error: legacy GSimpleAsyncResult handling */
2120 static void test_legacy_error (void);
2121 
2122 static void
legacy_error_callback(GObject * object,GAsyncResult * result,gpointer user_data)2123 legacy_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 (result, &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 (&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 
2156 static gboolean
legacy_error_return(gpointer user_data)2157 legacy_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, magic);
2164       g_object_unref (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                                        G_IO_ERROR_FAILED,
2174                                        "Failed");
2175       g_simple_async_result_complete (simple);
2176       G_GNUC_END_IGNORE_DEPRECATIONS;
2177       g_object_unref (simple);
2178     }
2179 
2180   return FALSE;
2181 }
2182 
2183 static void
test_legacy_error(void)2184 test_legacy_error (void)
2185 {
2186   GTask *task;
2187   GSimpleAsyncResult *simple;
2188   gssize result;
2189 
2190   /* GTask success */
2191   task = g_task_new (NULL, NULL, legacy_error_callback, &result);
2192   g_task_set_source_tag (task, test_legacy_error);
2193   g_object_add_weak_pointer (G_OBJECT (task), (gpointer *)&task);
2194 
2195   g_idle_add (legacy_error_return, 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, legacy_error_callback, &result);
2203   g_task_set_source_tag (task, test_legacy_error);
2204   g_object_add_weak_pointer (G_OBJECT (task), (gpointer *)&task);
2205 
2206   g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
2207                            "Failed");
2208   g_object_unref (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, legacy_error_callback, &result,
2217                                       test_legacy_error);
2218   G_GNUC_END_IGNORE_DEPRECATIONS;
2219   g_object_add_weak_pointer (G_OBJECT (simple), (gpointer *)&simple);
2220 
2221   g_idle_add (legacy_error_return, 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. */
2229 static void
task_complete_cb(GObject * source,GAsyncResult * result,gpointer user_data)2230 task_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 
2243 static void
return_twice(GTask * task)2244 return_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, G_IO_ERROR_UNKNOWN, "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, G_IO_ERROR_UNKNOWN, "oh no");
2257     }
2258 }
2259 
2260 static gboolean
idle_cb(gpointer user_data)2261 idle_cb (gpointer user_data)
2262 {
2263   GTask *task = user_data;
2264   return_twice (task);
2265   g_object_unref (task);
2266 
2267   return G_SOURCE_REMOVE;
2268 }
2269 
2270 static void
test_return_permutation(gboolean error_first,gboolean return_in_idle)2271 test_return_permutation (gboolean error_first,
2272                          gboolean return_in_idle)
2273 {
2274   guint calls = 0;
2275   GTask *task = NULL;
2276 
2277   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1525");
2278 
2279   task = g_task_new (NULL, NULL, task_complete_cb, &calls);
2280   g_task_set_task_data (task, GUINT_TO_POINTER (error_first), NULL);
2281 
2282   if (return_in_idle)
2283     g_idle_add (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 (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. */
2297 static void
test_return_in_idle_error_first(void)2298 test_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, 0, 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. */
2313 static void
test_return_in_idle_value_first(void)2314 test_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, 0, 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. */
2329 static void
test_return_error_first(void)2330 test_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, 0, 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. */
2345 static void
test_return_value_first(void)2346 test_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, 0, 0);
2355   g_test_trap_assert_failed ();
2356   g_test_trap_assert_stderr ("*CRITICAL*assertion '!task->ever_returned' failed*");
2357 }
2358 
2359 int
main(int argc,char ** argv)2360 main (int argc, char **argv)
2361 {
2362   int ret;
2363 
2364   g_test_init (&argc, &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 ("/gtask/basic", test_basic);
2371   g_test_add_func ("/gtask/error", test_error);
2372   g_test_add_func ("/gtask/return-from-same-iteration", test_return_from_same_iteration);
2373   g_test_add_func ("/gtask/return-from-toplevel", test_return_from_toplevel);
2374   g_test_add_func ("/gtask/return-from-anon-thread", test_return_from_anon_thread);
2375   g_test_add_func ("/gtask/return-from-wrong-thread", test_return_from_wrong_thread);
2376   g_test_add_func ("/gtask/no-callback", test_no_callback);
2377   g_test_add_func ("/gtask/report-error", test_report_error);
2378   g_test_add_func ("/gtask/priority", test_priority);
2379   g_test_add_func ("/gtask/name", test_name);
2380   g_test_add_func ("/gtask/asynchronous-cancellation", test_asynchronous_cancellation);
2381   g_test_add_func ("/gtask/check-cancellable", test_check_cancellable);
2382   g_test_add_func ("/gtask/return-if-cancelled", test_return_if_cancelled);
2383   g_test_add_func ("/gtask/run-in-thread", test_run_in_thread);
2384   g_test_add_func ("/gtask/run-in-thread-sync", test_run_in_thread_sync);
2385   g_test_add_func ("/gtask/run-in-thread-priority", test_run_in_thread_priority);
2386   g_test_add_func ("/gtask/run-in-thread-nested", test_run_in_thread_nested);
2387   g_test_add_func ("/gtask/run-in-thread-overflow", test_run_in_thread_overflow);
2388   g_test_add_func ("/gtask/return-on-cancel", test_return_on_cancel);
2389   g_test_add_func ("/gtask/return-on-cancel-sync", test_return_on_cancel_sync);
2390   g_test_add_func ("/gtask/return-on-cancel-atomic", test_return_on_cancel_atomic);
2391   g_test_add_func ("/gtask/return-pointer", test_return_pointer);
2392   g_test_add_func ("/gtask/return-value", test_return_value);
2393   g_test_add_func ("/gtask/object-keepalive", test_object_keepalive);
2394   g_test_add_func ("/gtask/legacy-error", test_legacy_error);
2395   g_test_add_func ("/gtask/return/in-idle/error-first", test_return_in_idle_error_first);
2396   g_test_add_func ("/gtask/return/in-idle/value-first", test_return_in_idle_value_first);
2397   g_test_add_func ("/gtask/return/error-first", test_return_error_first);
2398   g_test_add_func ("/gtask/return/value-first", test_return_value_first);
2399 
2400   ret = g_test_run();
2401 
2402   g_main_loop_unref (loop);
2403 
2404   return ret;
2405 }
2406