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