LCOV - code coverage report
Current view: top level - gio/tests - task.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 96.5 % 1382 1334
Test Date: 2024-11-26 05:23:01 Functions: 93.4 % 91 85
Branches: - 0 0

             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, &notification_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, &notification_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, &notification_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, &notification_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, &notification_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, &notification_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                 :             :                     &notification_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, &notification_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, &notification_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, &notification_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, &notification_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, &notification_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, &notification_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                 :             : }
        

Generated by: LCOV version 2.0-1