LCOV - code coverage report
Current view: top level - glib/glib/tests - mainloop.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 1147 1198 95.7 %
Date: 2024-04-16 05:15:53 Functions: 75 82 91.5 %
Branches: 136 176 77.3 %

           Branch data     Line data    Source code
       1                 :            : /* Unit tests for GMainLoop
       2                 :            :  * Copyright (C) 2011 Red Hat, Inc
       3                 :            :  * Author: Matthias Clasen
       4                 :            :  *
       5                 :            :  * SPDX-License-Identifier: LicenseRef-old-glib-tests
       6                 :            :  *
       7                 :            :  * This work is provided "as is"; redistribution and modification
       8                 :            :  * in whole or in part, in any medium, physical or electronic is
       9                 :            :  * permitted without restriction.
      10                 :            :  *
      11                 :            :  * This work is distributed in the hope that it will be useful,
      12                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      14                 :            :  *
      15                 :            :  * In no event shall the authors or contributors be liable for any
      16                 :            :  * direct, indirect, incidental, special, exemplary, or consequential
      17                 :            :  * damages (including, but not limited to, procurement of substitute
      18                 :            :  * goods or services; loss of use, data, or profits; or business
      19                 :            :  * interruption) however caused and on any theory of liability, whether
      20                 :            :  * in contract, strict liability, or tort (including negligence or
      21                 :            :  * otherwise) arising in any way out of the use of this software, even
      22                 :            :  * if advised of the possibility of such damage.
      23                 :            :  */
      24                 :            : 
      25                 :            : #include <glib.h>
      26                 :            : #include <glib/gstdio.h>
      27                 :            : #include "glib-private.h"
      28                 :            : #include <stdio.h>
      29                 :            : #include <string.h>
      30                 :            : 
      31                 :            : static gboolean
      32                 :          0 : cb (gpointer data)
      33                 :            : {
      34                 :          0 :   return FALSE;
      35                 :            : }
      36                 :            : 
      37                 :            : static gboolean
      38                 :          0 : prepare (GSource *source, gint *time)
      39                 :            : {
      40                 :          0 :   g_assert_nonnull (time);
      41                 :          0 :   g_assert_cmpint (*time, ==, -1);
      42                 :          0 :   return FALSE;
      43                 :            : }
      44                 :            : static gboolean
      45                 :          0 : check (GSource *source)
      46                 :            : {
      47                 :          0 :   return FALSE;
      48                 :            : }
      49                 :            : static gboolean
      50                 :          0 : dispatch (GSource *source, GSourceFunc cb, gpointer date)
      51                 :            : {
      52                 :          0 :   return FALSE;
      53                 :            : }
      54                 :            : 
      55                 :            : static GSourceFuncs global_funcs = {
      56                 :            :   prepare,
      57                 :            :   check,
      58                 :            :   dispatch,
      59                 :            :   NULL,
      60                 :            :   NULL,
      61                 :            :   NULL
      62                 :            : };
      63                 :            : 
      64                 :            : static void
      65                 :          1 : test_maincontext_basic (void)
      66                 :            : {
      67                 :            :   GMainContext *ctx;
      68                 :            :   GSource *source;
      69                 :            :   guint id;
      70                 :          1 :   gpointer data = &global_funcs;
      71                 :            : 
      72                 :          1 :   ctx = g_main_context_new ();
      73                 :            : 
      74                 :          1 :   g_assert_false (g_main_context_pending (ctx));
      75                 :          1 :   g_assert_false (g_main_context_iteration (ctx, FALSE));
      76                 :            : 
      77                 :          1 :   source = g_source_new (&global_funcs, sizeof (GSource));
      78                 :          1 :   g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_DEFAULT);
      79                 :          1 :   g_assert_false (g_source_is_destroyed (source));
      80                 :            : 
      81                 :          1 :   g_assert_false (g_source_get_can_recurse (source));
      82                 :          1 :   g_assert_null (g_source_get_name (source));
      83                 :            : 
      84                 :          1 :   g_source_set_can_recurse (source, TRUE);
      85                 :          1 :   g_source_set_static_name (source, "d");
      86                 :            : 
      87                 :          1 :   g_assert_true (g_source_get_can_recurse (source));
      88                 :          1 :   g_assert_cmpstr (g_source_get_name (source), ==, "d");
      89                 :            : 
      90                 :          1 :   g_source_set_static_name (source, "still d");
      91                 :          1 :   g_assert_cmpstr (g_source_get_name (source), ==, "still d");
      92                 :            : 
      93                 :          1 :   g_assert_null (g_main_context_find_source_by_user_data (ctx, NULL));
      94                 :          1 :   g_assert_null (g_main_context_find_source_by_funcs_user_data (ctx, &global_funcs, NULL));
      95                 :            : 
      96                 :          1 :   id = g_source_attach (source, ctx);
      97                 :          1 :   g_assert_cmpint (g_source_get_id (source), ==, id);
      98                 :          1 :   g_assert_true (g_main_context_find_source_by_id (ctx, id) == source);
      99                 :            : 
     100                 :          1 :   g_source_set_priority (source, G_PRIORITY_HIGH);
     101                 :          1 :   g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_HIGH);
     102                 :            : 
     103                 :          1 :   g_source_destroy (source);
     104                 :          1 :   g_assert_true (g_source_get_context (source) == ctx);
     105                 :          1 :   g_assert_null (g_main_context_find_source_by_id (ctx, id));
     106                 :            : 
     107                 :          1 :   g_main_context_unref (ctx);
     108                 :            : 
     109         [ +  - ]:          1 :   if (g_test_undefined ())
     110                 :            :     {
     111                 :          1 :       g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
     112                 :            :                              "*assertion*source->context != NULL*failed*");
     113                 :          1 :       g_assert_null (g_source_get_context (source));
     114                 :          1 :       g_test_assert_expected_messages ();
     115                 :            :     }
     116                 :            : 
     117                 :          1 :   g_source_unref (source);
     118                 :            : 
     119                 :          1 :   ctx = g_main_context_default ();
     120                 :          1 :   source = g_source_new (&global_funcs, sizeof (GSource));
     121                 :          1 :   g_source_set_funcs (source, &global_funcs);
     122                 :          1 :   g_source_set_callback (source, cb, data, NULL);
     123                 :          1 :   id = g_source_attach (source, ctx);
     124                 :          1 :   g_source_unref (source);
     125                 :          1 :   g_source_set_name_by_id (id, "e");
     126                 :          1 :   g_assert_cmpstr (g_source_get_name (source), ==, "e");
     127                 :          1 :   g_assert_true (g_source_get_context (source) == ctx);
     128                 :          1 :   g_assert_true (g_source_remove_by_funcs_user_data (&global_funcs, data));
     129                 :            : 
     130                 :          1 :   source = g_source_new (&global_funcs, sizeof (GSource));
     131                 :          1 :   g_source_set_funcs (source, &global_funcs);
     132                 :          1 :   g_source_set_callback (source, cb, data, NULL);
     133                 :          1 :   id = g_source_attach (source, ctx);
     134                 :          1 :   g_assert_cmpint (id, >, 0);
     135                 :          1 :   g_source_unref (source);
     136                 :          1 :   g_assert_true (g_source_remove_by_user_data (data));
     137                 :          1 :   g_assert_false (g_source_remove_by_user_data ((gpointer)0x1234));
     138                 :            : 
     139                 :          1 :   g_idle_add (cb, data);
     140                 :          1 :   g_assert_true (g_idle_remove_by_data (data));
     141                 :          1 : }
     142                 :            : 
     143                 :            : static void
     144                 :          1 : test_mainloop_basic (void)
     145                 :            : {
     146                 :            :   GMainLoop *loop;
     147                 :            :   GMainContext *ctx;
     148                 :            : 
     149                 :          1 :   loop = g_main_loop_new (NULL, FALSE);
     150                 :            : 
     151                 :          1 :   g_assert_false (g_main_loop_is_running (loop));
     152                 :            : 
     153                 :          1 :   g_main_loop_ref (loop);
     154                 :            : 
     155                 :          1 :   ctx = g_main_loop_get_context (loop);
     156                 :          1 :   g_assert_true (ctx == g_main_context_default ());
     157                 :            : 
     158                 :          1 :   g_main_loop_unref (loop);
     159                 :            : 
     160                 :          1 :   g_assert_cmpint (g_main_depth (), ==, 0);
     161                 :            : 
     162                 :          1 :   g_main_loop_unref (loop);
     163                 :          1 : }
     164                 :            : 
     165                 :            : static void
     166                 :          2 : test_ownerless_polling (gconstpointer test_data)
     167                 :            : {
     168                 :          2 :   gboolean attach_first = GPOINTER_TO_INT (test_data);
     169                 :          2 :   GMainContext *ctx = g_main_context_new_with_flags (
     170                 :            :     G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING);
     171                 :            : 
     172                 :            :   GPollFD fds[20];
     173                 :            :   gint fds_size;
     174                 :            :   gint max_priority;
     175                 :          2 :   GSource *source = NULL;
     176                 :            : 
     177                 :          2 :   g_assert_true (ctx != g_main_context_default ());
     178                 :            : 
     179                 :          2 :   g_main_context_push_thread_default (ctx);
     180                 :            : 
     181                 :            :   /* Drain events */
     182                 :            :   for (;;)
     183                 :          0 :     {
     184                 :          2 :       gboolean ready_to_dispatch = g_main_context_prepare (ctx, &max_priority);
     185                 :            :       gint timeout, nready;
     186                 :          2 :       fds_size = g_main_context_query (ctx, max_priority, &timeout, fds, G_N_ELEMENTS (fds));
     187                 :          2 :       nready = g_poll (fds, fds_size, /*timeout=*/0);
     188   [ +  -  +  - ]:          2 :       if (!ready_to_dispatch && nready == 0)
     189                 :            :         {
     190         [ +  - ]:          2 :           if (timeout == -1)
     191                 :          2 :             break;
     192                 :            :           else
     193                 :          0 :             g_usleep (timeout * 1000);
     194                 :            :         }
     195                 :          0 :       ready_to_dispatch = g_main_context_check (ctx, max_priority, fds, fds_size);
     196         [ #  # ]:          0 :       if (ready_to_dispatch)
     197                 :          0 :         g_main_context_dispatch (ctx);
     198                 :            :     }
     199                 :            : 
     200         [ +  + ]:          2 :   if (!attach_first)
     201                 :          1 :     g_main_context_pop_thread_default (ctx);
     202                 :            : 
     203                 :          2 :   source = g_idle_source_new ();
     204                 :          2 :   g_source_attach (source, ctx);
     205                 :          2 :   g_source_unref (source);
     206                 :            : 
     207         [ +  + ]:          2 :   if (attach_first)
     208                 :          1 :     g_main_context_pop_thread_default (ctx);
     209                 :            : 
     210                 :          2 :   g_assert_cmpint (g_poll (fds, fds_size, 0), >, 0);
     211                 :            : 
     212                 :          2 :   g_main_context_unref (ctx);
     213                 :          2 : }
     214                 :            : 
     215                 :            : static gint global_a;
     216                 :            : static gint global_b;
     217                 :            : static gint global_c;
     218                 :            : 
     219                 :            : static gboolean
     220                 :         32 : count_calls (gpointer data)
     221                 :            : {
     222                 :         32 :   gint *i = data;
     223                 :            : 
     224                 :         32 :   (*i)++;
     225                 :            : 
     226                 :         32 :   return TRUE;
     227                 :            : }
     228                 :            : 
     229                 :            : static void
     230                 :          1 : test_timeouts (void)
     231                 :            : {
     232                 :            :   GMainContext *ctx;
     233                 :            :   GMainLoop *loop;
     234                 :            :   GSource *source;
     235                 :            : 
     236         [ +  - ]:          1 :   if (!g_test_thorough ())
     237                 :            :     {
     238                 :          1 :       g_test_skip ("Not running timing heavy test");
     239                 :          1 :       return;
     240                 :            :     }
     241                 :            : 
     242                 :          0 :   global_a = global_b = global_c = 0;
     243                 :            : 
     244                 :          0 :   ctx = g_main_context_new ();
     245                 :          0 :   loop = g_main_loop_new (ctx, FALSE);
     246                 :            : 
     247                 :          0 :   source = g_timeout_source_new (100);
     248                 :          0 :   g_source_set_callback (source, count_calls, &global_a, NULL);
     249                 :          0 :   g_source_attach (source, ctx);
     250                 :          0 :   g_source_unref (source);
     251                 :            : 
     252                 :          0 :   source = g_timeout_source_new (250);
     253                 :          0 :   g_source_set_callback (source, count_calls, &global_b, NULL);
     254                 :          0 :   g_source_attach (source, ctx);
     255                 :          0 :   g_source_unref (source);
     256                 :            : 
     257                 :          0 :   source = g_timeout_source_new (330);
     258                 :          0 :   g_source_set_callback (source, count_calls, &global_c, NULL);
     259                 :          0 :   g_source_attach (source, ctx);
     260                 :          0 :   g_source_unref (source);
     261                 :            : 
     262                 :          0 :   source = g_timeout_source_new (1050);
     263                 :          0 :   g_source_set_callback (source, (GSourceFunc)g_main_loop_quit, loop, NULL);
     264                 :          0 :   g_source_attach (source, ctx);
     265                 :          0 :   g_source_unref (source);
     266                 :            : 
     267                 :          0 :   g_main_loop_run (loop);
     268                 :            : 
     269                 :            :   /* We may be delayed for an arbitrary amount of time - for example,
     270                 :            :    * it's possible for all timeouts to fire exactly once.
     271                 :            :    */
     272                 :          0 :   g_assert_cmpint (global_a, >, 0);
     273                 :          0 :   g_assert_cmpint (global_a, >=, global_b);
     274                 :          0 :   g_assert_cmpint (global_b, >=, global_c);
     275                 :            : 
     276                 :          0 :   g_assert_cmpint (global_a, <=, 10);
     277                 :          0 :   g_assert_cmpint (global_b, <=, 4);
     278                 :          0 :   g_assert_cmpint (global_c, <=, 3);
     279                 :            : 
     280                 :          0 :   g_main_loop_unref (loop);
     281                 :          0 :   g_main_context_unref (ctx);
     282                 :            : }
     283                 :            : 
     284                 :            : static void
     285                 :          1 : test_priorities (void)
     286                 :            : {
     287                 :            :   GMainContext *ctx;
     288                 :            :   GSource *sourcea;
     289                 :            :   GSource *sourceb;
     290                 :            : 
     291                 :          1 :   global_a = global_b = global_c = 0;
     292                 :            : 
     293                 :          1 :   ctx = g_main_context_new ();
     294                 :            : 
     295                 :          1 :   sourcea = g_idle_source_new ();
     296                 :          1 :   g_source_set_callback (sourcea, count_calls, &global_a, NULL);
     297                 :          1 :   g_source_set_priority (sourcea, 1);
     298                 :          1 :   g_source_attach (sourcea, ctx);
     299                 :          1 :   g_source_unref (sourcea);
     300                 :            : 
     301                 :          1 :   sourceb = g_idle_source_new ();
     302                 :          1 :   g_source_set_callback (sourceb, count_calls, &global_b, NULL);
     303                 :          1 :   g_source_set_priority (sourceb, 0);
     304                 :          1 :   g_source_attach (sourceb, ctx);
     305                 :          1 :   g_source_unref (sourceb);
     306                 :            : 
     307                 :          1 :   g_assert_true (g_main_context_pending (ctx));
     308                 :          1 :   g_assert_true (g_main_context_iteration (ctx, FALSE));
     309                 :          1 :   g_assert_cmpint (global_a, ==, 0);
     310                 :          1 :   g_assert_cmpint (global_b, ==, 1);
     311                 :            : 
     312                 :          1 :   g_assert_true (g_main_context_iteration (ctx, FALSE));
     313                 :          1 :   g_assert_cmpint (global_a, ==, 0);
     314                 :          1 :   g_assert_cmpint (global_b, ==, 2);
     315                 :            : 
     316                 :          1 :   g_source_destroy (sourceb);
     317                 :            : 
     318                 :          1 :   g_assert_true (g_main_context_iteration (ctx, FALSE));
     319                 :          1 :   g_assert_cmpint (global_a, ==, 1);
     320                 :          1 :   g_assert_cmpint (global_b, ==, 2);
     321                 :            : 
     322                 :          1 :   g_assert_true (g_main_context_pending (ctx));
     323                 :          1 :   g_source_destroy (sourcea);
     324                 :          1 :   g_assert_false (g_main_context_pending (ctx));
     325                 :            : 
     326                 :          1 :   g_main_context_unref (ctx);
     327                 :          1 : }
     328                 :            : 
     329                 :            : static gboolean
     330                 :          9 : quit_loop (gpointer data)
     331                 :            : {
     332                 :          9 :   GMainLoop *loop = data;
     333                 :            : 
     334                 :          9 :   g_main_loop_quit (loop);
     335                 :            : 
     336                 :          9 :   return G_SOURCE_REMOVE;
     337                 :            : }
     338                 :            : 
     339                 :            : static gint count;
     340                 :            : 
     341                 :            : static gboolean
     342                 :          3 : func (gpointer data)
     343                 :            : {
     344         [ +  - ]:          3 :   if (data != NULL)
     345                 :          3 :     g_assert_true (data == g_thread_self ());
     346                 :            : 
     347                 :          3 :   count++;
     348                 :            : 
     349                 :          3 :   return FALSE;
     350                 :            : }
     351                 :            : 
     352                 :            : static gboolean
     353                 :          1 : call_func (gpointer data)
     354                 :            : {
     355                 :          1 :   func (g_thread_self ());
     356                 :            : 
     357                 :          1 :   return G_SOURCE_REMOVE;
     358                 :            : }
     359                 :            : 
     360                 :            : static GMutex mutex;
     361                 :            : static GCond cond;
     362                 :            : static gboolean thread_ready;
     363                 :            : 
     364                 :            : static gpointer
     365                 :          1 : thread_func (gpointer data)
     366                 :            : {
     367                 :          1 :   GMainContext *ctx = data;
     368                 :            :   GMainLoop *loop;
     369                 :            :   GSource *source;
     370                 :            : 
     371                 :          1 :   g_main_context_push_thread_default (ctx);
     372                 :          1 :   loop = g_main_loop_new (ctx, FALSE);
     373                 :            : 
     374                 :          1 :   g_mutex_lock (&mutex);
     375                 :          1 :   thread_ready = TRUE;
     376                 :          1 :   g_cond_signal (&cond);
     377                 :          1 :   g_mutex_unlock (&mutex);
     378                 :            : 
     379                 :          1 :   source = g_timeout_source_new (500);
     380                 :          1 :   g_source_set_callback (source, quit_loop, loop, NULL);
     381                 :          1 :   g_source_attach (source, ctx);
     382                 :          1 :   g_source_unref (source);
     383                 :            : 
     384                 :          1 :   g_main_loop_run (loop);
     385                 :            : 
     386                 :          1 :   g_main_context_pop_thread_default (ctx);
     387                 :          1 :   g_main_loop_unref (loop);
     388                 :            : 
     389                 :          1 :   return NULL;
     390                 :            : }
     391                 :            : 
     392                 :            : static void
     393                 :          1 : test_invoke (void)
     394                 :            : {
     395                 :            :   GMainContext *ctx;
     396                 :            :   GThread *thread;
     397                 :            : 
     398                 :          1 :   count = 0;
     399                 :            : 
     400                 :            :   /* this one gets invoked directly */
     401                 :          1 :   g_main_context_invoke (NULL, func, g_thread_self ());
     402                 :          1 :   g_assert_cmpint (count, ==, 1);
     403                 :            : 
     404                 :            :   /* invoking out of an idle works too */
     405                 :          1 :   g_idle_add (call_func, NULL);
     406                 :          1 :   g_main_context_iteration (g_main_context_default (), FALSE);
     407                 :          1 :   g_assert_cmpint (count, ==, 2);
     408                 :            : 
     409                 :            :   /* test thread-default forcing the invocation to go
     410                 :            :    * to another thread
     411                 :            :    */
     412                 :          1 :   ctx = g_main_context_new ();
     413                 :          1 :   thread = g_thread_new ("worker", thread_func, ctx);
     414                 :            : 
     415                 :          1 :   g_mutex_lock (&mutex);
     416         [ +  + ]:          2 :   while (!thread_ready)
     417                 :          1 :     g_cond_wait (&cond, &mutex);
     418                 :          1 :   g_mutex_unlock (&mutex);
     419                 :            : 
     420                 :          1 :   g_main_context_invoke (ctx, func, thread);
     421                 :            : 
     422                 :          1 :   g_thread_join (thread);
     423                 :          1 :   g_assert_cmpint (count, ==, 3);
     424                 :            : 
     425                 :          1 :   g_main_context_unref (ctx);
     426                 :          1 : }
     427                 :            : 
     428                 :            : /* We can't use timeout sources here because on slow or heavily-loaded
     429                 :            :  * machines, the test program might not get enough cycles to hit the
     430                 :            :  * timeouts at the expected times. So instead we define a source that
     431                 :            :  * is based on the number of GMainContext iterations.
     432                 :            :  */
     433                 :            : 
     434                 :            : static gint counter;
     435                 :            : static gint64 last_counter_update;
     436                 :            : 
     437                 :            : typedef struct {
     438                 :            :   GSource source;
     439                 :            :   gint    interval;
     440                 :            :   gint    timeout;
     441                 :            : } CounterSource;
     442                 :            : 
     443                 :            : static gboolean
     444                 :      11304 : counter_source_prepare (GSource *source,
     445                 :            :                         gint    *timeout)
     446                 :            : {
     447                 :      11304 :   CounterSource *csource = (CounterSource *)source;
     448                 :            :   gint64 now;
     449                 :            : 
     450                 :      11304 :   now = g_source_get_time (source);
     451         [ +  + ]:      11304 :   if (now != last_counter_update)
     452                 :            :     {
     453                 :       3171 :       last_counter_update = now;
     454                 :       3171 :       counter++;
     455                 :            :     }
     456                 :            : 
     457                 :      11304 :   *timeout = 1;
     458                 :      11304 :   return counter >= csource->timeout;
     459                 :            : }
     460                 :            : 
     461                 :            : static gboolean
     462                 :         44 : counter_source_dispatch (GSource    *source,
     463                 :            :                          GSourceFunc callback,
     464                 :            :                          gpointer    user_data)
     465                 :            : {
     466                 :         44 :   CounterSource *csource = (CounterSource *) source;
     467                 :            :   gboolean again;
     468                 :            : 
     469                 :         44 :   again = callback (user_data);
     470                 :            : 
     471         [ +  + ]:         44 :   if (again)
     472                 :         37 :     csource->timeout = counter + csource->interval;
     473                 :            : 
     474                 :         44 :   return again;
     475                 :            : }
     476                 :            : 
     477                 :            : static GSourceFuncs counter_source_funcs = {
     478                 :            :   counter_source_prepare,
     479                 :            :   NULL,
     480                 :            :   counter_source_dispatch,
     481                 :            :   NULL,
     482                 :            :   NULL,
     483                 :            :   NULL
     484                 :            : };
     485                 :            : 
     486                 :            : static GSource *
     487                 :         16 : counter_source_new (gint interval)
     488                 :            : {
     489                 :         16 :   GSource *source = g_source_new (&counter_source_funcs, sizeof (CounterSource));
     490                 :         16 :   CounterSource *csource = (CounterSource *) source;
     491                 :            : 
     492                 :         16 :   csource->interval = interval;
     493                 :         16 :   csource->timeout = counter + interval;
     494                 :            : 
     495                 :         16 :   return source;
     496                 :            : }
     497                 :            : 
     498                 :            : 
     499                 :            : static gboolean
     500                 :          6 : run_inner_loop (gpointer user_data)
     501                 :            : {
     502                 :          6 :   GMainContext *ctx = user_data;
     503                 :            :   GMainLoop *inner;
     504                 :            :   GSource *timeout;
     505                 :            : 
     506                 :          6 :   global_a++;
     507                 :            : 
     508                 :          6 :   inner = g_main_loop_new (ctx, FALSE);
     509                 :          6 :   timeout = counter_source_new (100);
     510                 :          6 :   g_source_set_callback (timeout, quit_loop, inner, NULL);
     511                 :          6 :   g_source_attach (timeout, ctx);
     512                 :          6 :   g_source_unref (timeout);
     513                 :            : 
     514                 :          6 :   g_main_loop_run (inner);
     515                 :          6 :   g_main_loop_unref (inner);
     516                 :            : 
     517                 :          6 :   return G_SOURCE_CONTINUE;
     518                 :            : }
     519                 :            : 
     520                 :            : static void
     521                 :          1 : test_child_sources (void)
     522                 :            : {
     523                 :            :   GMainContext *ctx;
     524                 :            :   GMainLoop *loop;
     525                 :            :   GSource *parent, *child_b, *child_c, *end;
     526                 :            : 
     527                 :          1 :   ctx = g_main_context_new ();
     528                 :          1 :   loop = g_main_loop_new (ctx, FALSE);
     529                 :            : 
     530                 :          1 :   global_a = global_b = global_c = 0;
     531                 :            : 
     532                 :          1 :   parent = counter_source_new (2000);
     533                 :          1 :   g_source_set_callback (parent, run_inner_loop, ctx, NULL);
     534                 :          1 :   g_source_set_priority (parent, G_PRIORITY_LOW);
     535                 :          1 :   g_source_attach (parent, ctx);
     536                 :            : 
     537                 :          1 :   child_b = counter_source_new (250);
     538                 :          1 :   g_source_set_callback (child_b, count_calls, &global_b, NULL);
     539                 :          1 :   g_source_add_child_source (parent, child_b);
     540                 :            : 
     541                 :          1 :   child_c = counter_source_new (330);
     542                 :          1 :   g_source_set_callback (child_c, count_calls, &global_c, NULL);
     543                 :          1 :   g_source_set_priority (child_c, G_PRIORITY_HIGH);
     544                 :          1 :   g_source_add_child_source (parent, child_c);
     545                 :            : 
     546                 :            :   /* Child sources always have the priority of the parent */
     547                 :          1 :   g_assert_cmpint (g_source_get_priority (parent), ==, G_PRIORITY_LOW);
     548                 :          1 :   g_assert_cmpint (g_source_get_priority (child_b), ==, G_PRIORITY_LOW);
     549                 :          1 :   g_assert_cmpint (g_source_get_priority (child_c), ==, G_PRIORITY_LOW);
     550                 :          1 :   g_source_set_priority (parent, G_PRIORITY_DEFAULT);
     551                 :          1 :   g_assert_cmpint (g_source_get_priority (parent), ==, G_PRIORITY_DEFAULT);
     552                 :          1 :   g_assert_cmpint (g_source_get_priority (child_b), ==, G_PRIORITY_DEFAULT);
     553                 :          1 :   g_assert_cmpint (g_source_get_priority (child_c), ==, G_PRIORITY_DEFAULT);
     554                 :            : 
     555                 :          1 :   end = counter_source_new (1050);
     556                 :          1 :   g_source_set_callback (end, quit_loop, loop, NULL);
     557                 :          1 :   g_source_attach (end, ctx);
     558                 :          1 :   g_source_unref (end);
     559                 :            : 
     560                 :          1 :   g_main_loop_run (loop);
     561                 :            : 
     562                 :            :   /* The parent source's own timeout will never trigger, so "a" will
     563                 :            :    * only get incremented when "b" or "c" does. And when timeouts get
     564                 :            :    * blocked, they still wait the full interval next time rather than
     565                 :            :    * "catching up". So the timing is:
     566                 :            :    *
     567                 :            :    *  250 - b++ -> a++, run_inner_loop
     568                 :            :    *  330 - (c is blocked)
     569                 :            :    *  350 - inner_loop ends
     570                 :            :    *  350 - c++ belatedly -> a++, run_inner_loop
     571                 :            :    *  450 - inner loop ends
     572                 :            :    *  500 - b++ -> a++, run_inner_loop
     573                 :            :    *  600 - inner_loop ends
     574                 :            :    *  680 - c++ -> a++, run_inner_loop
     575                 :            :    *  750 - (b is blocked)
     576                 :            :    *  780 - inner loop ends
     577                 :            :    *  780 - b++ belatedly -> a++, run_inner_loop
     578                 :            :    *  880 - inner loop ends
     579                 :            :    * 1010 - c++ -> a++, run_inner_loop
     580                 :            :    * 1030 - (b is blocked)
     581                 :            :    * 1050 - end runs, quits outer loop, which has no effect yet
     582                 :            :    * 1110 - inner loop ends, a returns, outer loop exits
     583                 :            :    */
     584                 :            : 
     585                 :          1 :   g_assert_cmpint (global_a, ==, 6);
     586                 :          1 :   g_assert_cmpint (global_b, ==, 3);
     587                 :          1 :   g_assert_cmpint (global_c, ==, 3);
     588                 :            : 
     589                 :          1 :   g_source_destroy (parent);
     590                 :          1 :   g_source_unref (parent);
     591                 :          1 :   g_source_unref (child_b);
     592                 :          1 :   g_source_unref (child_c);
     593                 :            : 
     594                 :          1 :   g_main_loop_unref (loop);
     595                 :          1 :   g_main_context_unref (ctx);
     596                 :          1 : }
     597                 :            : 
     598                 :            : static void
     599                 :          1 : test_recursive_child_sources (void)
     600                 :            : {
     601                 :            :   GMainContext *ctx;
     602                 :            :   GMainLoop *loop;
     603                 :            :   GSource *parent, *child_b, *child_c, *end;
     604                 :            : 
     605                 :          1 :   ctx = g_main_context_new ();
     606                 :          1 :   loop = g_main_loop_new (ctx, FALSE);
     607                 :            : 
     608                 :          1 :   global_a = global_b = global_c = 0;
     609                 :            : 
     610                 :          1 :   parent = counter_source_new (500);
     611                 :          1 :   g_source_set_callback (parent, count_calls, &global_a, NULL);
     612                 :            : 
     613                 :          1 :   child_b = counter_source_new (220);
     614                 :          1 :   g_source_set_callback (child_b, count_calls, &global_b, NULL);
     615                 :          1 :   g_source_add_child_source (parent, child_b);
     616                 :            : 
     617                 :          1 :   child_c = counter_source_new (430);
     618                 :          1 :   g_source_set_callback (child_c, count_calls, &global_c, NULL);
     619                 :          1 :   g_source_add_child_source (child_b, child_c);
     620                 :            : 
     621                 :          1 :   g_source_attach (parent, ctx);
     622                 :            : 
     623                 :          1 :   end = counter_source_new (2010);
     624                 :          1 :   g_source_set_callback (end, (GSourceFunc)g_main_loop_quit, loop, NULL);
     625                 :          1 :   g_source_attach (end, ctx);
     626                 :          1 :   g_source_unref (end);
     627                 :            : 
     628                 :          1 :   g_main_loop_run (loop);
     629                 :            : 
     630                 :            :   /* Sequence of events:
     631                 :            :    *  220 b (b -> 440, a -> 720)
     632                 :            :    *  430 c (c -> 860, b -> 650, a -> 930)
     633                 :            :    *  650 b (b -> 870, a -> 1150)
     634                 :            :    *  860 c (c -> 1290, b -> 1080, a -> 1360)
     635                 :            :    * 1080 b (b -> 1300, a -> 1580)
     636                 :            :    * 1290 c (c -> 1720, b -> 1510, a -> 1790)
     637                 :            :    * 1510 b (b -> 1730, a -> 2010)
     638                 :            :    * 1720 c (c -> 2150, b -> 1940, a -> 2220)
     639                 :            :    * 1940 b (b -> 2160, a -> 2440)
     640                 :            :    */
     641                 :            : 
     642                 :          1 :   g_assert_cmpint (global_a, ==, 9);
     643                 :          1 :   g_assert_cmpint (global_b, ==, 9);
     644                 :          1 :   g_assert_cmpint (global_c, ==, 4);
     645                 :            : 
     646                 :          1 :   g_source_destroy (parent);
     647                 :          1 :   g_source_unref (parent);
     648                 :          1 :   g_source_unref (child_b);
     649                 :          1 :   g_source_unref (child_c);
     650                 :            : 
     651                 :          1 :   g_main_loop_unref (loop);
     652                 :          1 :   g_main_context_unref (ctx);
     653                 :          1 : }
     654                 :            : 
     655                 :            : typedef struct {
     656                 :            :   GSource *parent, *old_child, *new_child;
     657                 :            :   GMainLoop *loop;
     658                 :            : } SwappingTestData;
     659                 :            : 
     660                 :            : static gboolean
     661                 :          2 : swap_sources (gpointer user_data)
     662                 :            : {
     663                 :          2 :   SwappingTestData *data = user_data;
     664                 :            : 
     665         [ +  + ]:          2 :   if (data->old_child)
     666                 :            :     {
     667                 :          1 :       g_source_remove_child_source (data->parent, data->old_child);
     668                 :          1 :       g_clear_pointer (&data->old_child, g_source_unref);
     669                 :            :     }
     670                 :            : 
     671         [ +  + ]:          2 :   if (!data->new_child)
     672                 :            :     {
     673                 :          1 :       data->new_child = g_timeout_source_new (0);
     674                 :          1 :       g_source_set_callback (data->new_child, quit_loop, data->loop, NULL);
     675                 :          1 :       g_source_add_child_source (data->parent, data->new_child);
     676                 :            :     }
     677                 :            : 
     678                 :          2 :   return G_SOURCE_CONTINUE;
     679                 :            : }
     680                 :            : 
     681                 :            : static gboolean
     682                 :          0 : assert_not_reached_callback (gpointer user_data)
     683                 :            : {
     684                 :            :   g_assert_not_reached ();
     685                 :            : 
     686                 :            :   return G_SOURCE_REMOVE;
     687                 :            : }
     688                 :            : 
     689                 :            : static void
     690                 :          1 : test_swapping_child_sources (void)
     691                 :            : {
     692                 :            :   GMainContext *ctx;
     693                 :            :   GMainLoop *loop;
     694                 :            :   SwappingTestData data;
     695                 :            : 
     696                 :          1 :   ctx = g_main_context_new ();
     697                 :          1 :   loop = g_main_loop_new (ctx, FALSE);
     698                 :            : 
     699                 :          1 :   data.parent = counter_source_new (50);
     700                 :          1 :   data.loop = loop;
     701                 :          1 :   g_source_set_callback (data.parent, swap_sources, &data, NULL);
     702                 :          1 :   g_source_attach (data.parent, ctx);
     703                 :            : 
     704                 :          1 :   data.old_child = counter_source_new (100);
     705                 :          1 :   g_source_add_child_source (data.parent, data.old_child);
     706                 :          1 :   g_source_set_callback (data.old_child, assert_not_reached_callback, NULL, NULL);
     707                 :            : 
     708                 :          1 :   data.new_child = NULL;
     709                 :          1 :   g_main_loop_run (loop);
     710                 :            : 
     711                 :          1 :   g_source_destroy (data.parent);
     712                 :          1 :   g_source_unref (data.parent);
     713                 :          1 :   g_source_unref (data.new_child);
     714                 :            : 
     715                 :          1 :   g_main_loop_unref (loop);
     716                 :          1 :   g_main_context_unref (ctx);
     717                 :          1 : }
     718                 :            : 
     719                 :            : static gboolean
     720                 :          1 : add_source_callback (gpointer user_data)
     721                 :            : {
     722                 :          1 :   GMainLoop *loop = user_data;
     723                 :          1 :   GSource *self = g_main_current_source (), *child;
     724                 :            :   GIOChannel *io;
     725                 :            : 
     726                 :            :   /* It doesn't matter whether this is a valid fd or not; it never
     727                 :            :    * actually gets polled; the test is just checking that
     728                 :            :    * g_source_add_child_source() doesn't crash.
     729                 :            :    */
     730                 :          1 :   io = g_io_channel_unix_new (0);
     731                 :          1 :   child = g_io_create_watch (io, G_IO_IN);
     732                 :          1 :   g_source_add_child_source (self, child);
     733                 :          1 :   g_source_unref (child);
     734                 :          1 :   g_io_channel_unref (io);
     735                 :            : 
     736                 :          1 :   g_main_loop_quit (loop);
     737                 :          1 :   return FALSE;
     738                 :            : }
     739                 :            : 
     740                 :            : static void
     741                 :          1 : test_blocked_child_sources (void)
     742                 :            : {
     743                 :            :   GMainContext *ctx;
     744                 :            :   GMainLoop *loop;
     745                 :            :   GSource *source;
     746                 :            : 
     747                 :          1 :   g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=701283");
     748                 :            : 
     749                 :          1 :   ctx = g_main_context_new ();
     750                 :          1 :   loop = g_main_loop_new (ctx, FALSE);
     751                 :            : 
     752                 :          1 :   source = g_idle_source_new ();
     753                 :          1 :   g_source_set_callback (source, add_source_callback, loop, NULL);
     754                 :          1 :   g_source_attach (source, ctx);
     755                 :            : 
     756                 :          1 :   g_main_loop_run (loop);
     757                 :            : 
     758                 :          1 :   g_source_destroy (source);
     759                 :          1 :   g_source_unref (source);
     760                 :            : 
     761                 :          1 :   g_main_loop_unref (loop);
     762                 :          1 :   g_main_context_unref (ctx);
     763                 :          1 : }
     764                 :            : 
     765                 :            : typedef struct {
     766                 :            :   GMainContext *ctx;
     767                 :            :   GMainLoop *loop;
     768                 :            : 
     769                 :            :   GSource *timeout1, *timeout2;
     770                 :            :   gint64 time1;
     771                 :            : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     772                 :            :   GTimeVal tv;  /* needed for g_source_get_current_time() */
     773                 :            : G_GNUC_END_IGNORE_DEPRECATIONS
     774                 :            : } TimeTestData;
     775                 :            : 
     776                 :            : static gboolean
     777                 :          2 : timeout1_callback (gpointer user_data)
     778                 :            : {
     779                 :          2 :   TimeTestData *data = user_data;
     780                 :            :   GSource *source;
     781                 :            :   gint64 mtime1, mtime2, time2;
     782                 :            : 
     783                 :          2 :   source = g_main_current_source ();
     784                 :          2 :   g_assert_true (source == data->timeout1);
     785                 :            : 
     786         [ +  + ]:          2 :   if (data->time1 == -1)
     787                 :            :     {
     788                 :            :       /* First iteration */
     789                 :          1 :       g_assert_false (g_source_is_destroyed (data->timeout2));
     790                 :            : 
     791                 :          1 :       mtime1 = g_get_monotonic_time ();
     792                 :          1 :       data->time1 = g_source_get_time (source);
     793                 :            : 
     794                 :            : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     795                 :          1 :       g_source_get_current_time (source, &data->tv);
     796                 :            : G_GNUC_END_IGNORE_DEPRECATIONS
     797                 :            : 
     798                 :            :       /* g_source_get_time() does not change during a single callback */
     799                 :          1 :       g_usleep (1000000);
     800                 :          1 :       mtime2 = g_get_monotonic_time ();
     801                 :          1 :       time2 = g_source_get_time (source);
     802                 :            : 
     803                 :          1 :       g_assert_cmpint (mtime1, <, mtime2);
     804                 :          1 :       g_assert_cmpint (data->time1, ==, time2);
     805                 :            :     }
     806                 :            :   else
     807                 :            :     {
     808                 :            : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     809                 :            :       GTimeVal tv;
     810                 :            : G_GNUC_END_IGNORE_DEPRECATIONS
     811                 :            : 
     812                 :            :       /* Second iteration */
     813                 :          1 :       g_assert_true (g_source_is_destroyed (data->timeout2));
     814                 :            : 
     815                 :            :       /* g_source_get_time() MAY change between iterations; in this
     816                 :            :        * case we know for sure that it did because of the g_usleep()
     817                 :            :        * last time.
     818                 :            :        */
     819                 :          1 :       time2 = g_source_get_time (source);
     820                 :          1 :       g_assert_cmpint (data->time1, <, time2);
     821                 :            : 
     822                 :            : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     823                 :          1 :       g_source_get_current_time (source, &tv);
     824                 :            : G_GNUC_END_IGNORE_DEPRECATIONS
     825                 :            : 
     826                 :          1 :       g_assert_true (tv.tv_sec > data->tv.tv_sec ||
     827                 :            :                      (tv.tv_sec == data->tv.tv_sec &&
     828                 :            :                       tv.tv_usec > data->tv.tv_usec));
     829                 :            : 
     830                 :          1 :       g_main_loop_quit (data->loop);
     831                 :            :     }
     832                 :            : 
     833                 :          2 :   return TRUE;
     834                 :            : }
     835                 :            : 
     836                 :            : static gboolean
     837                 :          1 : timeout2_callback (gpointer user_data)
     838                 :            : {
     839                 :          1 :   TimeTestData *data = user_data;
     840                 :            :   GSource *source;
     841                 :            :   gint64 time2, time3;
     842                 :            : 
     843                 :          1 :   source = g_main_current_source ();
     844                 :          1 :   g_assert_true (source == data->timeout2);
     845                 :            : 
     846                 :          1 :   g_assert_false (g_source_is_destroyed (data->timeout1));
     847                 :            : 
     848                 :            :   /* g_source_get_time() does not change between different sources in
     849                 :            :    * a single iteration of the mainloop.
     850                 :            :    */
     851                 :          1 :   time2 = g_source_get_time (source);
     852                 :          1 :   g_assert_cmpint (data->time1, ==, time2);
     853                 :            : 
     854                 :            :   /* The source should still have a valid time even after being
     855                 :            :    * destroyed, since it's currently running.
     856                 :            :    */
     857                 :          1 :   g_source_destroy (source);
     858                 :          1 :   time3 = g_source_get_time (source);
     859                 :          1 :   g_assert_cmpint (time2, ==, time3);
     860                 :            : 
     861                 :          1 :   return FALSE;
     862                 :            : }
     863                 :            : 
     864                 :            : static void
     865                 :          1 : test_source_time (void)
     866                 :            : {
     867                 :            :   TimeTestData data;
     868                 :            : 
     869                 :          1 :   data.ctx = g_main_context_new ();
     870                 :          1 :   data.loop = g_main_loop_new (data.ctx, FALSE);
     871                 :            : 
     872                 :          1 :   data.timeout1 = g_timeout_source_new (0);
     873                 :          1 :   g_source_set_callback (data.timeout1, timeout1_callback, &data, NULL);
     874                 :          1 :   g_source_attach (data.timeout1, data.ctx);
     875                 :            : 
     876                 :          1 :   data.timeout2 = g_timeout_source_new (0);
     877                 :          1 :   g_source_set_callback (data.timeout2, timeout2_callback, &data, NULL);
     878                 :          1 :   g_source_attach (data.timeout2, data.ctx);
     879                 :            : 
     880                 :          1 :   data.time1 = -1;
     881                 :            : 
     882                 :          1 :   g_main_loop_run (data.loop);
     883                 :            : 
     884                 :          1 :   g_assert_false (g_source_is_destroyed (data.timeout1));
     885                 :          1 :   g_assert_true (g_source_is_destroyed (data.timeout2));
     886                 :            : 
     887                 :          1 :   g_source_destroy (data.timeout1);
     888                 :          1 :   g_source_unref (data.timeout1);
     889                 :          1 :   g_source_unref (data.timeout2);
     890                 :            : 
     891                 :          1 :   g_main_loop_unref (data.loop);
     892                 :          1 :   g_main_context_unref (data.ctx);
     893                 :          1 : }
     894                 :            : 
     895                 :            : typedef struct {
     896                 :            :   guint outstanding_ops;
     897                 :            :   GMainLoop *loop;
     898                 :            : } TestOverflowData;
     899                 :            : 
     900                 :            : static gboolean
     901                 :         53 : on_source_fired_cb (gpointer user_data)
     902                 :            : {
     903                 :         53 :   TestOverflowData *data = user_data;
     904                 :            :   GSource *current_source;
     905                 :            :   GMainContext *current_context;
     906                 :            :   guint source_id;
     907                 :            : 
     908                 :         53 :   data->outstanding_ops--;
     909                 :            : 
     910                 :         53 :   current_source = g_main_current_source ();
     911                 :         53 :   current_context = g_source_get_context (current_source);
     912                 :         53 :   source_id = g_source_get_id (current_source);
     913                 :         53 :   g_assert_nonnull (g_main_context_find_source_by_id (current_context, source_id));
     914                 :         53 :   g_source_destroy (current_source);
     915                 :         53 :   g_assert_null (g_main_context_find_source_by_id (current_context, source_id));
     916                 :            : 
     917         [ +  + ]:         53 :   if (data->outstanding_ops == 0)
     918                 :          1 :     g_main_loop_quit (data->loop);
     919                 :         53 :   return FALSE;
     920                 :            : }
     921                 :            : 
     922                 :            : static GSource *
     923                 :         53 : add_idle_source (GMainContext *ctx,
     924                 :            :                  TestOverflowData *data)
     925                 :            : {
     926                 :            :   GSource *source;
     927                 :            : 
     928                 :         53 :   source = g_idle_source_new ();
     929                 :         53 :   g_source_set_callback (source, on_source_fired_cb, data, NULL);
     930                 :         53 :   g_source_attach (source, ctx);
     931                 :         53 :   g_source_unref (source);
     932                 :         53 :   data->outstanding_ops++;
     933                 :            : 
     934                 :         53 :   return source;
     935                 :            : }
     936                 :            : 
     937                 :            : static void
     938                 :          1 : test_mainloop_overflow (void)
     939                 :            : {
     940                 :            :   GMainContext *ctx;
     941                 :            :   GMainLoop *loop;
     942                 :            :   GSource *source;
     943                 :            :   TestOverflowData data;
     944                 :            :   guint i;
     945                 :            : 
     946                 :          1 :   g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=687098");
     947                 :            : 
     948                 :          1 :   memset (&data, 0, sizeof (data));
     949                 :            : 
     950                 :          1 :   ctx = GLIB_PRIVATE_CALL (g_main_context_new_with_next_id) (G_MAXUINT-1);
     951                 :            : 
     952                 :          1 :   loop = g_main_loop_new (ctx, TRUE);
     953                 :          1 :   data.outstanding_ops = 0;
     954                 :          1 :   data.loop = loop;
     955                 :            : 
     956                 :          1 :   source = add_idle_source (ctx, &data);
     957                 :          1 :   g_assert_cmpint (source->source_id, ==, G_MAXUINT-1);
     958                 :            : 
     959                 :          1 :   source = add_idle_source (ctx, &data);
     960                 :          1 :   g_assert_cmpint (source->source_id, ==, G_MAXUINT);
     961                 :            : 
     962                 :          1 :   source = add_idle_source (ctx, &data);
     963                 :          1 :   g_assert_cmpint (source->source_id, !=, 0);
     964                 :            : 
     965                 :            :   /* Now, a lot more sources */
     966         [ +  + ]:         51 :   for (i = 0; i < 50; i++)
     967                 :            :     {
     968                 :         50 :       source = add_idle_source (ctx, &data);
     969                 :         50 :       g_assert_cmpint (source->source_id, !=, 0);
     970                 :            :     }
     971                 :            : 
     972                 :          1 :   g_main_loop_run (loop);
     973                 :          1 :   g_assert_cmpint (data.outstanding_ops, ==, 0);
     974                 :            : 
     975                 :          1 :   g_main_loop_unref (loop);
     976                 :          1 :   g_main_context_unref (ctx);
     977                 :          1 : }
     978                 :            : 
     979                 :            : static gint ready_time_dispatched;  /* (atomic) */
     980                 :            : 
     981                 :            : static gboolean
     982                 :          5 : ready_time_dispatch (GSource     *source,
     983                 :            :                      GSourceFunc  callback,
     984                 :            :                      gpointer     user_data)
     985                 :            : {
     986                 :          5 :   g_atomic_int_set (&ready_time_dispatched, TRUE);
     987                 :            : 
     988                 :          5 :   g_source_set_ready_time (source, -1);
     989                 :            : 
     990                 :          5 :   return TRUE;
     991                 :            : }
     992                 :            : 
     993                 :            : static gpointer
     994                 :          1 : run_context (gpointer user_data)
     995                 :            : {
     996                 :          1 :   g_main_loop_run (user_data);
     997                 :            : 
     998                 :          1 :   return NULL;
     999                 :            : }
    1000                 :            : 
    1001                 :            : static void
    1002                 :          1 : test_ready_time (void)
    1003                 :            : {
    1004                 :            :   GThread *thread;
    1005                 :            :   GSource *source;
    1006                 :          1 :   GSourceFuncs source_funcs = {
    1007                 :            :     NULL, NULL, ready_time_dispatch, NULL, NULL, NULL
    1008                 :            :   };
    1009                 :            :   GMainLoop *loop;
    1010                 :            : 
    1011                 :          1 :   source = g_source_new (&source_funcs, sizeof (GSource));
    1012                 :          1 :   g_source_attach (source, NULL);
    1013                 :          1 :   g_source_unref (source);
    1014                 :            : 
    1015                 :            :   /* Unfortunately we can't do too many things with respect to timing
    1016                 :            :    * without getting into trouble on slow systems or heavily loaded
    1017                 :            :    * builders.
    1018                 :            :    *
    1019                 :            :    * We can test that the basics are working, though.
    1020                 :            :    */
    1021                 :            : 
    1022                 :            :   /* A source with no ready time set should not fire */
    1023                 :          1 :   g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
    1024         [ -  + ]:          1 :   while (g_main_context_iteration (NULL, FALSE));
    1025                 :          1 :   g_assert_false (g_atomic_int_get (&ready_time_dispatched));
    1026                 :            : 
    1027                 :            :   /* The ready time should not have been changed */
    1028                 :          1 :   g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
    1029                 :            : 
    1030                 :            :   /* Of course this shouldn't change anything either */
    1031                 :          1 :   g_source_set_ready_time (source, -1);
    1032                 :          1 :   g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
    1033                 :            : 
    1034                 :            :   /* A source with a ready time set to tomorrow should not fire on any
    1035                 :            :    * builder, no matter how badly loaded...
    1036                 :            :    */
    1037                 :          1 :   g_source_set_ready_time (source, g_get_monotonic_time () + G_TIME_SPAN_DAY);
    1038         [ -  + ]:          1 :   while (g_main_context_iteration (NULL, FALSE));
    1039                 :          1 :   g_assert_false (g_atomic_int_get (&ready_time_dispatched));
    1040                 :            :   /* Make sure it didn't get reset */
    1041                 :          1 :   g_assert_cmpint (g_source_get_ready_time (source), !=, -1);
    1042                 :            : 
    1043                 :            :   /* Ready time of -1 -> don't fire */
    1044                 :          1 :   g_source_set_ready_time (source, -1);
    1045         [ -  + ]:          1 :   while (g_main_context_iteration (NULL, FALSE));
    1046                 :          1 :   g_assert_false (g_atomic_int_get (&ready_time_dispatched));
    1047                 :            :   /* Not reset, but should still be -1 from above */
    1048                 :          1 :   g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
    1049                 :            : 
    1050                 :            :   /* A ready time of the current time should fire immediately */
    1051                 :          1 :   g_source_set_ready_time (source, g_get_monotonic_time ());
    1052         [ +  + ]:          2 :   while (g_main_context_iteration (NULL, FALSE));
    1053                 :          1 :   g_assert_true (g_atomic_int_get (&ready_time_dispatched));
    1054                 :          1 :   g_atomic_int_set (&ready_time_dispatched, FALSE);
    1055                 :            :   /* Should have gotten reset by the handler function */
    1056                 :          1 :   g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
    1057                 :            : 
    1058                 :            :   /* As well as one in the recent past... */
    1059                 :          1 :   g_source_set_ready_time (source, g_get_monotonic_time () - G_TIME_SPAN_SECOND);
    1060         [ +  + ]:          2 :   while (g_main_context_iteration (NULL, FALSE));
    1061                 :          1 :   g_assert_true (g_atomic_int_get (&ready_time_dispatched));
    1062                 :          1 :   g_atomic_int_set (&ready_time_dispatched, FALSE);
    1063                 :          1 :   g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
    1064                 :            : 
    1065                 :            :   /* Zero is the 'official' way to get a source to fire immediately */
    1066                 :          1 :   g_source_set_ready_time (source, 0);
    1067         [ +  + ]:          2 :   while (g_main_context_iteration (NULL, FALSE));
    1068                 :          1 :   g_assert_true (g_atomic_int_get (&ready_time_dispatched));
    1069                 :          1 :   g_atomic_int_set (&ready_time_dispatched, FALSE);
    1070                 :          1 :   g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
    1071                 :            : 
    1072                 :            :   /* Now do some tests of cross-thread wakeups.
    1073                 :            :    *
    1074                 :            :    * Make sure it wakes up right away from the start.
    1075                 :            :    */
    1076                 :          1 :   g_source_set_ready_time (source, 0);
    1077                 :          1 :   loop = g_main_loop_new (NULL, FALSE);
    1078                 :          1 :   thread = g_thread_new ("context thread", run_context, loop);
    1079         [ +  + ]:     109158 :   while (!g_atomic_int_get (&ready_time_dispatched));
    1080                 :            : 
    1081                 :            :   /* Now let's see if it can wake up from sleeping. */
    1082                 :          1 :   g_usleep (G_TIME_SPAN_SECOND / 2);
    1083                 :          1 :   g_atomic_int_set (&ready_time_dispatched, FALSE);
    1084                 :          1 :   g_source_set_ready_time (source, 0);
    1085         [ +  + ]:     560028 :   while (!g_atomic_int_get (&ready_time_dispatched));
    1086                 :            : 
    1087                 :            :   /* kill the thread */
    1088                 :          1 :   g_main_loop_quit (loop);
    1089                 :          1 :   g_thread_join (thread);
    1090                 :          1 :   g_main_loop_unref (loop);
    1091                 :            : 
    1092                 :          1 :   g_source_destroy (source);
    1093                 :          1 : }
    1094                 :            : 
    1095                 :            : static void
    1096                 :          1 : test_wakeup(void)
    1097                 :            : {
    1098                 :            :   GMainContext *ctx;
    1099                 :            :   int i;
    1100                 :            : 
    1101                 :          1 :   ctx = g_main_context_new ();
    1102                 :            : 
    1103                 :            :   /* run a random large enough number of times because 
    1104                 :            :    * main contexts tend to wake up a few times after creation.
    1105                 :            :    */
    1106         [ +  + ]:        101 :   for (i = 0; i < 100; i++)
    1107                 :            :     {
    1108                 :            :       /* This is the invariant we care about:
    1109                 :            :        * g_main_context_wakeup(ctx,) ensures that the next call to
    1110                 :            :        * g_main_context_iteration (ctx, TRUE) returns and doesn't
    1111                 :            :        * block.
    1112                 :            :        * This is important in threaded apps where we might not know
    1113                 :            :        * if the thread calls g_main_context_wakeup() before or after
    1114                 :            :        * we enter g_main_context_iteration().
    1115                 :            :        */
    1116                 :        100 :       g_main_context_wakeup (ctx);
    1117                 :        100 :       g_main_context_iteration (ctx, TRUE);
    1118                 :            :     }
    1119                 :            : 
    1120                 :          1 :   g_main_context_unref (ctx);
    1121                 :          1 : }
    1122                 :            : 
    1123                 :            : static void
    1124                 :          1 : test_remove_invalid (void)
    1125                 :            : {
    1126                 :          1 :   g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "Source ID 3000000000 was not found*");
    1127                 :          1 :   g_source_remove (3000000000u);
    1128                 :          1 :   g_test_assert_expected_messages ();
    1129                 :          1 : }
    1130                 :            : 
    1131                 :            : static gboolean
    1132                 :          1 : trivial_prepare (GSource *source,
    1133                 :            :                  gint    *timeout)
    1134                 :            : {
    1135                 :          1 :   *timeout = 0;
    1136                 :          1 :   return TRUE;
    1137                 :            : }
    1138                 :            : 
    1139                 :            : static gint n_finalized;
    1140                 :            : 
    1141                 :            : static void
    1142                 :          1 : trivial_finalize (GSource *source)
    1143                 :            : {
    1144                 :          1 :   n_finalized++;
    1145                 :          1 : }
    1146                 :            : 
    1147                 :            : static void
    1148                 :          1 : test_unref_while_pending (void)
    1149                 :            : {
    1150                 :            :   static GSourceFuncs funcs = {
    1151                 :            :     trivial_prepare, NULL, NULL, trivial_finalize, NULL, NULL
    1152                 :            :   };
    1153                 :            :   GMainContext *context;
    1154                 :            :   GSource *source;
    1155                 :            : 
    1156                 :          1 :   context = g_main_context_new ();
    1157                 :            : 
    1158                 :          1 :   source = g_source_new (&funcs, sizeof (GSource));
    1159                 :          1 :   g_source_attach (source, context);
    1160                 :          1 :   g_source_unref (source);
    1161                 :            : 
    1162                 :            :   /* Do incomplete main iteration -- get a pending source but don't dispatch it. */
    1163                 :          1 :   g_main_context_prepare (context, NULL);
    1164                 :          1 :   g_main_context_query (context, 0, NULL, NULL, 0);
    1165                 :          1 :   g_main_context_check (context, 1000, NULL, 0);
    1166                 :            : 
    1167                 :            :   /* Destroy the context */
    1168                 :          1 :   g_main_context_unref (context);
    1169                 :            : 
    1170                 :            :   /* Make sure we didn't leak the source */
    1171                 :          1 :   g_assert_cmpint (n_finalized, ==, 1);
    1172                 :          1 : }
    1173                 :            : 
    1174                 :            : typedef struct {
    1175                 :            :   GSource parent;
    1176                 :            :   GMainLoop *loop;
    1177                 :            : } LoopedSource;
    1178                 :            : 
    1179                 :            : static gboolean
    1180                 :          1 : prepare_loop_run (GSource *source, gint *time)
    1181                 :            : {
    1182                 :          1 :   LoopedSource *looped_source = (LoopedSource*) source;
    1183                 :          1 :   *time = 0;
    1184                 :            : 
    1185                 :          1 :   g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
    1186                 :            :                          "*called recursively from within a source's check() "
    1187                 :            :                          "or prepare() member*");
    1188                 :          1 :   g_main_loop_run (looped_source->loop);
    1189                 :          1 :   g_test_assert_expected_messages ();
    1190                 :            : 
    1191                 :          1 :   return FALSE;
    1192                 :            : }
    1193                 :            : 
    1194                 :            : static gboolean
    1195                 :          1 : check_loop_run (GSource *source)
    1196                 :            : {
    1197                 :          1 :   LoopedSource *looped_source = (LoopedSource*) source;
    1198                 :            : 
    1199                 :          1 :   g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
    1200                 :            :                          "*called recursively from within a source's check() "
    1201                 :            :                          "or prepare() member*");
    1202                 :          1 :   g_main_loop_run (looped_source->loop);
    1203                 :          1 :   g_test_assert_expected_messages ();
    1204                 :            : 
    1205                 :          1 :   return TRUE;
    1206                 :            : }
    1207                 :            : 
    1208                 :            : static gboolean
    1209                 :          1 : dispatch_loop_run (GSource    *source,
    1210                 :            :                    GSourceFunc callback,
    1211                 :            :                    gpointer    user_data)
    1212                 :            : {
    1213                 :          1 :   LoopedSource *looped_source = (LoopedSource*) source;
    1214                 :            : 
    1215                 :          1 :   g_main_loop_quit (looped_source->loop);
    1216                 :            : 
    1217                 :          1 :   return FALSE;
    1218                 :            : }
    1219                 :            : 
    1220                 :            : static void
    1221                 :          1 : test_recursive_loop_child_sources (void)
    1222                 :            : {
    1223                 :            :   GMainLoop *loop;
    1224                 :            :   GSource *source;
    1225                 :          1 :   GSourceFuncs loop_run_funcs = {
    1226                 :            :     prepare_loop_run, check_loop_run, dispatch_loop_run, NULL, NULL, NULL,
    1227                 :            :   };
    1228                 :            : 
    1229                 :          1 :   loop = g_main_loop_new (NULL, FALSE);
    1230                 :            : 
    1231                 :          1 :   source = g_source_new (&loop_run_funcs, sizeof (LoopedSource));
    1232                 :          1 :   ((LoopedSource*)source)->loop = loop;
    1233                 :            : 
    1234                 :          1 :   g_source_attach (source, NULL);
    1235                 :            : 
    1236                 :          1 :   g_main_loop_run (loop);
    1237                 :          1 :   g_source_unref (source);
    1238                 :            : 
    1239                 :          1 :   g_main_loop_unref (loop);
    1240                 :          1 : }
    1241                 :            : 
    1242                 :            : 
    1243                 :            : #ifdef G_OS_UNIX
    1244                 :            : 
    1245                 :            : #include <glib-unix.h>
    1246                 :            : #include <unistd.h>
    1247                 :            : 
    1248                 :            : static gchar zeros[1024];
    1249                 :            : 
    1250                 :            : static gsize
    1251                 :          1 : fill_a_pipe (gint fd)
    1252                 :            : {
    1253                 :          1 :   gsize written = 0;
    1254                 :            :   GPollFD pfd;
    1255                 :            : 
    1256                 :          1 :   pfd.fd = fd;
    1257                 :          1 :   pfd.events = G_IO_OUT;
    1258         [ +  + ]:         62 :   while (g_poll (&pfd, 1, 0) == 1)
    1259                 :            :     /* we should never see -1 here */
    1260                 :         61 :     written += write (fd, zeros, sizeof zeros);
    1261                 :            : 
    1262                 :          1 :   return written;
    1263                 :            : }
    1264                 :            : 
    1265                 :            : static gboolean
    1266                 :     131073 : write_bytes (gint         fd,
    1267                 :            :              GIOCondition condition,
    1268                 :            :              gpointer     user_data)
    1269                 :            : {
    1270                 :     131073 :   gssize *to_write = user_data;
    1271                 :            :   gint limit;
    1272                 :            : 
    1273         [ +  + ]:     131073 :   if (*to_write == 0)
    1274                 :          1 :     return FALSE;
    1275                 :            : 
    1276                 :            :   /* Detect if we run before we should */
    1277                 :     131072 :   g_assert_cmpint (*to_write, >=, 0);
    1278                 :            : 
    1279                 :     131072 :   limit = MIN ((gsize) *to_write, sizeof zeros);
    1280                 :     131072 :   *to_write -= write (fd, zeros, limit);
    1281                 :            : 
    1282                 :     131072 :   return TRUE;
    1283                 :            : }
    1284                 :            : 
    1285                 :            : static gboolean
    1286                 :     131133 : read_bytes (gint         fd,
    1287                 :            :             GIOCondition condition,
    1288                 :            :             gpointer     user_data)
    1289                 :            : {
    1290                 :            :   static gchar buffer[1024];
    1291                 :     131133 :   gssize *to_read = user_data;
    1292                 :            : 
    1293                 :     131133 :   *to_read -= read (fd, buffer, sizeof buffer);
    1294                 :            : 
    1295                 :            :   /* The loop will exit when there is nothing else to read, then we will
    1296                 :            :    * use g_source_remove() to destroy this source.
    1297                 :            :    */
    1298                 :     131133 :   return TRUE;
    1299                 :            : }
    1300                 :            : 
    1301                 :            : #ifdef G_OS_UNIX
    1302                 :            : static void
    1303                 :          1 : test_unix_fd (void)
    1304                 :            : {
    1305                 :          1 :   gssize to_write = -1;
    1306                 :            :   gssize to_read;
    1307                 :            :   gint fds[2];
    1308                 :            :   gint a, b;
    1309                 :            :   gint s;
    1310                 :            :   GSource *source_a;
    1311                 :            :   GSource *source_b;
    1312                 :            : 
    1313                 :          1 :   s = pipe (fds);
    1314                 :          1 :   g_assert_cmpint (s, ==, 0);
    1315                 :            : 
    1316                 :          1 :   to_read = fill_a_pipe (fds[1]);
    1317                 :            :   /* write at higher priority to keep the pipe full... */
    1318                 :          1 :   a = g_unix_fd_add_full (G_PRIORITY_HIGH, fds[1], G_IO_OUT, write_bytes, &to_write, NULL);
    1319                 :          1 :   source_a = g_source_ref (g_main_context_find_source_by_id (NULL, a));
    1320                 :            :   /* make sure no 'writes' get dispatched yet */
    1321         [ -  + ]:          1 :   while (g_main_context_iteration (NULL, FALSE));
    1322                 :            : 
    1323                 :          1 :   to_read += 128 * 1024 * 1024;
    1324                 :          1 :   to_write = 128 * 1024 * 1024;
    1325                 :          1 :   b = g_unix_fd_add (fds[0], G_IO_IN, read_bytes, &to_read);
    1326                 :          1 :   source_b = g_source_ref (g_main_context_find_source_by_id (NULL, b));
    1327                 :            : 
    1328                 :            :   /* Assuming the kernel isn't internally 'laggy' then there will always
    1329                 :            :    * be either data to read or room in which to write.  That will keep
    1330                 :            :    * the loop running until all data has been read and written.
    1331                 :            :    */
    1332                 :            :   while (TRUE)
    1333                 :     262206 :     {
    1334                 :     262207 :       gssize to_write_was = to_write;
    1335                 :     262207 :       gssize to_read_was = to_read;
    1336                 :            : 
    1337         [ +  + ]:     262207 :       if (!g_main_context_iteration (NULL, FALSE))
    1338                 :          1 :         break;
    1339                 :            : 
    1340                 :            :       /* Since the sources are at different priority, only one of them
    1341                 :            :        * should possibly have run.
    1342                 :            :        */
    1343                 :     262206 :       g_assert_true (to_write == to_write_was || to_read == to_read_was);
    1344                 :            :     }
    1345                 :            : 
    1346                 :          1 :   g_assert_cmpint (to_write, ==, 0);
    1347                 :          1 :   g_assert_cmpint (to_read, ==, 0);
    1348                 :            : 
    1349                 :            :   /* 'a' is already removed by itself */
    1350                 :          1 :   g_assert_true (g_source_is_destroyed (source_a));
    1351                 :          1 :   g_source_unref (source_a);
    1352                 :          1 :   g_source_remove (b);
    1353                 :          1 :   g_assert_true (g_source_is_destroyed (source_b));
    1354                 :          1 :   g_source_unref (source_b);
    1355                 :          1 :   close (fds[1]);
    1356                 :          1 :   close (fds[0]);
    1357                 :          1 : }
    1358                 :            : #endif
    1359                 :            : 
    1360                 :            : static void
    1361                 :         14 : assert_main_context_state (gint n_to_poll,
    1362                 :            :                            ...)
    1363                 :            : {
    1364                 :            :   GMainContext *context;
    1365                 :         14 :   gboolean consumed[10] = { };
    1366                 :            :   GPollFD poll_fds[10];
    1367                 :            :   gboolean acquired;
    1368                 :            :   gboolean immediate;
    1369                 :            :   gint max_priority;
    1370                 :            :   gint timeout;
    1371                 :            :   gint n;
    1372                 :            :   gint i, j;
    1373                 :            :   va_list ap;
    1374                 :            : 
    1375                 :         14 :   context = g_main_context_default ();
    1376                 :            : 
    1377                 :         14 :   acquired = g_main_context_acquire (context);
    1378                 :         14 :   g_assert_true (acquired);
    1379                 :            : 
    1380                 :         14 :   immediate = g_main_context_prepare (context, &max_priority);
    1381                 :         14 :   g_assert_false (immediate);
    1382                 :         14 :   n = g_main_context_query (context, max_priority, &timeout, poll_fds, 10);
    1383                 :         14 :   g_assert_cmpint (n, ==, n_to_poll + 1); /* one will be the gwakeup */
    1384                 :            : 
    1385                 :         14 :   va_start (ap, n_to_poll);
    1386         [ +  + ]:         42 :   for (i = 0; i < n_to_poll; i++)
    1387                 :            :     {
    1388                 :         28 :       gint expected_fd = va_arg (ap, gint);
    1389                 :         28 :       GIOCondition expected_events = va_arg (ap, GIOCondition);
    1390                 :         28 :       GIOCondition report_events = va_arg (ap, GIOCondition);
    1391                 :            : 
    1392         [ +  - ]:         83 :       for (j = 0; j < n; j++)
    1393   [ +  +  +  +  :         83 :         if (!consumed[j] && poll_fds[j].fd == expected_fd && poll_fds[j].events == expected_events)
                   +  - ]
    1394                 :            :           {
    1395                 :         28 :             poll_fds[j].revents = report_events;
    1396                 :         28 :             consumed[j] = TRUE;
    1397                 :         28 :             break;
    1398                 :            :           }
    1399                 :            : 
    1400         [ -  + ]:         28 :       if (j == n)
    1401                 :          0 :         g_error ("Unable to find fd %d (index %d) with events 0x%x", expected_fd, i, (guint) expected_events);
    1402                 :            :     }
    1403                 :         14 :   va_end (ap);
    1404                 :            : 
    1405                 :            :   /* find the gwakeup, flag as non-ready */
    1406         [ +  + ]:         56 :   for (i = 0; i < n; i++)
    1407         [ +  + ]:         42 :     if (!consumed[i])
    1408                 :         14 :       poll_fds[i].revents = 0;
    1409                 :            : 
    1410         [ +  + ]:         14 :   if (g_main_context_check (context, max_priority, poll_fds, n))
    1411                 :          7 :     g_main_context_dispatch (context);
    1412                 :            : 
    1413                 :         14 :   g_main_context_release (context);
    1414                 :         14 : }
    1415                 :            : 
    1416                 :            : static gboolean
    1417                 :          5 : flag_bool (gint         fd,
    1418                 :            :            GIOCondition condition,
    1419                 :            :            gpointer     user_data)
    1420                 :            : {
    1421                 :          5 :   gboolean *flag = user_data;
    1422                 :            : 
    1423                 :          5 :   *flag = TRUE;
    1424                 :            : 
    1425                 :          5 :   return TRUE;
    1426                 :            : }
    1427                 :            : 
    1428                 :            : static void
    1429                 :          1 : test_unix_fd_source (void)
    1430                 :            : {
    1431                 :            :   GSource *out_source;
    1432                 :            :   GSource *in_source;
    1433                 :            :   GSource *source;
    1434                 :            :   gboolean out, in;
    1435                 :            :   gint fds[2];
    1436                 :            :   gint s;
    1437                 :            : 
    1438                 :          1 :   assert_main_context_state (0);
    1439                 :            : 
    1440                 :          1 :   s = pipe (fds);
    1441                 :          1 :   g_assert_cmpint (s, ==, 0);
    1442                 :            : 
    1443                 :          1 :   source = g_unix_fd_source_new (fds[1], G_IO_OUT);
    1444                 :          1 :   g_source_attach (source, NULL);
    1445                 :            : 
    1446                 :            :   /* Check that a source with no callback gets successfully detached
    1447                 :            :    * with a warning printed.
    1448                 :            :    */
    1449                 :          1 :   g_test_expect_message ("GLib", G_LOG_LEVEL_WARNING, "*GUnixFDSource dispatched without callback*");
    1450         [ +  + ]:          2 :   while (g_main_context_iteration (NULL, FALSE));
    1451                 :          1 :   g_test_assert_expected_messages ();
    1452                 :          1 :   g_assert_true (g_source_is_destroyed (source));
    1453                 :          1 :   g_source_unref (source);
    1454                 :            : 
    1455                 :          1 :   out = in = FALSE;
    1456                 :          1 :   out_source = g_unix_fd_source_new (fds[1], G_IO_OUT);
    1457                 :            :   /* -Wcast-function-type complains about casting 'flag_bool' to GSourceFunc.
    1458                 :            :    * GCC has no way of knowing that it will be cast back to GUnixFDSourceFunc
    1459                 :            :    * before being called. Although GLib itself is not compiled with
    1460                 :            :    * -Wcast-function-type, applications that use GLib may well be (since
    1461                 :            :    * -Wextra includes it), so we provide a G_SOURCE_FUNC() macro to suppress
    1462                 :            :    * the warning. We check that it works here.
    1463                 :            :    */
    1464                 :            : #if G_GNUC_CHECK_VERSION(8, 0)
    1465                 :            : #pragma GCC diagnostic push
    1466                 :            : #pragma GCC diagnostic error "-Wcast-function-type"
    1467                 :            : #endif
    1468                 :          1 :   g_source_set_callback (out_source, G_SOURCE_FUNC (flag_bool), &out, NULL);
    1469                 :            : #if G_GNUC_CHECK_VERSION(8, 0)
    1470                 :            : #pragma GCC diagnostic pop
    1471                 :            : #endif
    1472                 :          1 :   g_source_attach (out_source, NULL);
    1473                 :          1 :   assert_main_context_state (1,
    1474                 :            :                              fds[1], G_IO_OUT, 0);
    1475                 :          1 :   g_assert_true (!in && !out);
    1476                 :            : 
    1477                 :          1 :   in_source = g_unix_fd_source_new (fds[0], G_IO_IN);
    1478                 :          1 :   g_source_set_callback (in_source, (GSourceFunc) flag_bool, &in, NULL);
    1479                 :          1 :   g_source_set_priority (in_source, G_PRIORITY_DEFAULT_IDLE);
    1480                 :          1 :   g_source_attach (in_source, NULL);
    1481                 :          1 :   assert_main_context_state (2,
    1482                 :            :                              fds[0], G_IO_IN, G_IO_IN,
    1483                 :            :                              fds[1], G_IO_OUT, G_IO_OUT);
    1484                 :            :   /* out is higher priority so only it should fire */
    1485                 :          1 :   g_assert_true (!in && out);
    1486                 :            : 
    1487                 :            :   /* raise the priority of the in source to higher than out*/
    1488                 :          1 :   in = out = FALSE;
    1489                 :          1 :   g_source_set_priority (in_source, G_PRIORITY_HIGH);
    1490                 :          1 :   assert_main_context_state (2,
    1491                 :            :                              fds[0], G_IO_IN, G_IO_IN,
    1492                 :            :                              fds[1], G_IO_OUT, G_IO_OUT);
    1493                 :          1 :   g_assert_true (in && !out);
    1494                 :            : 
    1495                 :            :   /* now, let them be equal */
    1496                 :          1 :   in = out = FALSE;
    1497                 :          1 :   g_source_set_priority (in_source, G_PRIORITY_DEFAULT);
    1498                 :          1 :   assert_main_context_state (2,
    1499                 :            :                              fds[0], G_IO_IN, G_IO_IN,
    1500                 :            :                              fds[1], G_IO_OUT, G_IO_OUT);
    1501                 :          1 :   g_assert_true (in && out);
    1502                 :            : 
    1503                 :          1 :   g_source_destroy (out_source);
    1504                 :          1 :   g_source_unref (out_source);
    1505                 :          1 :   g_source_destroy (in_source);
    1506                 :          1 :   g_source_unref (in_source);
    1507                 :          1 :   close (fds[1]);
    1508                 :          1 :   close (fds[0]);
    1509                 :          1 : }
    1510                 :            : 
    1511                 :            : typedef struct
    1512                 :            : {
    1513                 :            :   GSource parent;
    1514                 :            :   gboolean flagged;
    1515                 :            : } FlagSource;
    1516                 :            : 
    1517                 :            : static gboolean
    1518                 :          4 : return_true (GSource *source, GSourceFunc callback, gpointer user_data)
    1519                 :            : {
    1520                 :          4 :   FlagSource *flag_source = (FlagSource *) source;
    1521                 :            : 
    1522                 :          4 :   flag_source->flagged = TRUE;
    1523                 :            : 
    1524                 :          4 :   return TRUE;
    1525                 :            : }
    1526                 :            : 
    1527                 :            : #define assert_flagged(s) g_assert_true (((FlagSource *) (s))->flagged);
    1528                 :            : #define assert_not_flagged(s) g_assert_true (!((FlagSource *) (s))->flagged);
    1529                 :            : #define clear_flag(s) ((FlagSource *) (s))->flagged = 0
    1530                 :            : 
    1531                 :            : static void
    1532                 :          1 : test_source_unix_fd_api (void)
    1533                 :            : {
    1534                 :          1 :   GSourceFuncs no_funcs = {
    1535                 :            :     NULL, NULL, return_true, NULL, NULL, NULL
    1536                 :            :   };
    1537                 :            :   GSource *source_a;
    1538                 :            :   GSource *source_b;
    1539                 :            :   gpointer tag1, tag2;
    1540                 :            :   gint fds_a[2];
    1541                 :            :   gint fds_b[2];
    1542                 :            : 
    1543                 :          1 :   g_assert_cmpint (pipe (fds_a), ==, 0);
    1544                 :          1 :   g_assert_cmpint (pipe (fds_b), ==, 0);
    1545                 :            : 
    1546                 :          1 :   source_a = g_source_new (&no_funcs, sizeof (FlagSource));
    1547                 :          1 :   source_b = g_source_new (&no_funcs, sizeof (FlagSource));
    1548                 :            : 
    1549                 :            :   /* attach a source with more than one fd */
    1550                 :          1 :   g_source_add_unix_fd (source_a, fds_a[0], G_IO_IN);
    1551                 :          1 :   g_source_add_unix_fd (source_a, fds_a[1], G_IO_OUT);
    1552                 :          1 :   g_source_attach (source_a, NULL);
    1553                 :          1 :   assert_main_context_state (2,
    1554                 :            :                              fds_a[0], G_IO_IN, 0,
    1555                 :            :                              fds_a[1], G_IO_OUT, 0);
    1556         [ -  + ]:          1 :   assert_not_flagged (source_a);
    1557                 :            : 
    1558                 :            :   /* attach a higher priority source with no fds */
    1559                 :          1 :   g_source_set_priority (source_b, G_PRIORITY_HIGH);
    1560                 :          1 :   g_source_attach (source_b, NULL);
    1561                 :          1 :   assert_main_context_state (2,
    1562                 :            :                              fds_a[0], G_IO_IN, G_IO_IN,
    1563                 :            :                              fds_a[1], G_IO_OUT, 0);
    1564         [ -  + ]:          1 :   assert_flagged (source_a);
    1565         [ -  + ]:          1 :   assert_not_flagged (source_b);
    1566                 :          1 :   clear_flag (source_a);
    1567                 :            : 
    1568                 :            :   /* add some fds to the second source, while attached */
    1569                 :          1 :   tag1 = g_source_add_unix_fd (source_b, fds_b[0], G_IO_IN);
    1570                 :          1 :   tag2 = g_source_add_unix_fd (source_b, fds_b[1], G_IO_OUT);
    1571                 :          1 :   assert_main_context_state (4,
    1572                 :            :                              fds_a[0], G_IO_IN, 0,
    1573                 :            :                              fds_a[1], G_IO_OUT, G_IO_OUT,
    1574                 :            :                              fds_b[0], G_IO_IN, 0,
    1575                 :            :                              fds_b[1], G_IO_OUT, G_IO_OUT);
    1576                 :            :   /* only 'b' (higher priority) should have dispatched */
    1577         [ -  + ]:          1 :   assert_not_flagged (source_a);
    1578         [ -  + ]:          1 :   assert_flagged (source_b);
    1579                 :          1 :   clear_flag (source_b);
    1580                 :            : 
    1581                 :            :   /* change our events on b to the same as they were before */
    1582                 :          1 :   g_source_modify_unix_fd (source_b, tag1, G_IO_IN);
    1583                 :          1 :   g_source_modify_unix_fd (source_b, tag2, G_IO_OUT);
    1584                 :          1 :   assert_main_context_state (4,
    1585                 :            :                              fds_a[0], G_IO_IN, 0,
    1586                 :            :                              fds_a[1], G_IO_OUT, G_IO_OUT,
    1587                 :            :                              fds_b[0], G_IO_IN, 0,
    1588                 :            :                              fds_b[1], G_IO_OUT, G_IO_OUT);
    1589         [ -  + ]:          1 :   assert_not_flagged (source_a);
    1590         [ -  + ]:          1 :   assert_flagged (source_b);
    1591                 :          1 :   clear_flag (source_b);
    1592                 :            : 
    1593                 :            :   /* now reverse them */
    1594                 :          1 :   g_source_modify_unix_fd (source_b, tag1, G_IO_OUT);
    1595                 :          1 :   g_source_modify_unix_fd (source_b, tag2, G_IO_IN);
    1596                 :          1 :   assert_main_context_state (4,
    1597                 :            :                              fds_a[0], G_IO_IN, 0,
    1598                 :            :                              fds_a[1], G_IO_OUT, G_IO_OUT,
    1599                 :            :                              fds_b[0], G_IO_OUT, 0,
    1600                 :            :                              fds_b[1], G_IO_IN, 0);
    1601                 :            :   /* 'b' had no events, so 'a' can go this time */
    1602         [ -  + ]:          1 :   assert_flagged (source_a);
    1603         [ -  + ]:          1 :   assert_not_flagged (source_b);
    1604                 :          1 :   clear_flag (source_a);
    1605                 :            : 
    1606                 :            :   /* remove one of the fds from 'b' */
    1607                 :          1 :   g_source_remove_unix_fd (source_b, tag1);
    1608                 :          1 :   assert_main_context_state (3,
    1609                 :            :                              fds_a[0], G_IO_IN, 0,
    1610                 :            :                              fds_a[1], G_IO_OUT, 0,
    1611                 :            :                              fds_b[1], G_IO_IN, 0);
    1612         [ -  + ]:          1 :   assert_not_flagged (source_a);
    1613         [ -  + ]:          1 :   assert_not_flagged (source_b);
    1614                 :            : 
    1615                 :            :   /* remove the other */
    1616                 :          1 :   g_source_remove_unix_fd (source_b, tag2);
    1617                 :          1 :   assert_main_context_state (2,
    1618                 :            :                              fds_a[0], G_IO_IN, 0,
    1619                 :            :                              fds_a[1], G_IO_OUT, 0);
    1620         [ -  + ]:          1 :   assert_not_flagged (source_a);
    1621         [ -  + ]:          1 :   assert_not_flagged (source_b);
    1622                 :            : 
    1623                 :            :   /* destroy the sources */
    1624                 :          1 :   g_source_destroy (source_a);
    1625                 :          1 :   g_source_destroy (source_b);
    1626                 :          1 :   assert_main_context_state (0);
    1627                 :            : 
    1628                 :          1 :   g_source_unref (source_a);
    1629                 :          1 :   g_source_unref (source_b);
    1630                 :          1 :   close (fds_a[0]);
    1631                 :          1 :   close (fds_a[1]);
    1632                 :          1 :   close (fds_b[0]);
    1633                 :          1 :   close (fds_b[1]);
    1634                 :          1 : }
    1635                 :            : 
    1636                 :            : static gboolean
    1637                 :          1 : unixfd_quit_loop (gint         fd,
    1638                 :            :                   GIOCondition condition,
    1639                 :            :                   gpointer     user_data)
    1640                 :            : {
    1641                 :          1 :   GMainLoop *loop = user_data;
    1642                 :            : 
    1643                 :          1 :   g_main_loop_quit (loop);
    1644                 :            : 
    1645                 :          1 :   return FALSE;
    1646                 :            : }
    1647                 :            : 
    1648                 :            : static void
    1649                 :          1 : test_unix_file_poll (void)
    1650                 :            : {
    1651                 :            :   gint fd;
    1652                 :            :   GSource *source;
    1653                 :            :   GMainLoop *loop;
    1654                 :            : 
    1655                 :          1 :   fd = open ("/dev/null", O_RDONLY);
    1656                 :          1 :   g_assert_cmpint (fd, >=, 0);
    1657                 :            : 
    1658                 :          1 :   loop = g_main_loop_new (NULL, FALSE);
    1659                 :            : 
    1660                 :          1 :   source = g_unix_fd_source_new (fd, G_IO_IN);
    1661                 :          1 :   g_source_set_callback (source, (GSourceFunc) unixfd_quit_loop, loop, NULL);
    1662                 :          1 :   g_source_attach (source, NULL);
    1663                 :            : 
    1664                 :            :   /* Should not block */
    1665                 :          1 :   g_main_loop_run (loop);
    1666                 :            : 
    1667                 :          1 :   g_source_destroy (source);
    1668                 :            : 
    1669                 :          1 :   assert_main_context_state (0);
    1670                 :            : 
    1671                 :          1 :   g_source_unref (source);
    1672                 :            : 
    1673                 :          1 :   g_main_loop_unref (loop);
    1674                 :            : 
    1675                 :          1 :   close (fd);
    1676                 :          1 : }
    1677                 :            : 
    1678                 :            : static void
    1679                 :          1 : test_unix_fd_priority (void)
    1680                 :            : {
    1681                 :            :   gint fd1, fd2;
    1682                 :            :   GMainLoop *loop;
    1683                 :            :   GSource *source;
    1684                 :            : 
    1685                 :          1 :   gint s1 = 0;
    1686                 :          1 :   gboolean s2 = FALSE, s3 = FALSE;
    1687                 :            : 
    1688                 :          1 :   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/1592");
    1689                 :            : 
    1690                 :          1 :   loop = g_main_loop_new (NULL, FALSE);
    1691                 :            : 
    1692                 :          1 :   source = g_idle_source_new ();
    1693                 :          1 :   g_source_set_callback (source, count_calls, &s1, NULL);
    1694                 :          1 :   g_source_set_priority (source, 0);
    1695                 :          1 :   g_source_attach (source, NULL);
    1696                 :          1 :   g_source_unref (source);
    1697                 :            : 
    1698                 :          1 :   fd1 = open ("/dev/random", O_RDONLY);
    1699                 :          1 :   g_assert_cmpint (fd1, >=, 0);
    1700                 :          1 :   source = g_unix_fd_source_new (fd1, G_IO_IN);
    1701                 :          1 :   g_source_set_callback (source, G_SOURCE_FUNC (flag_bool), &s2, NULL);
    1702                 :          1 :   g_source_set_priority (source, 10);
    1703                 :          1 :   g_source_attach (source, NULL);
    1704                 :          1 :   g_source_unref (source);
    1705                 :            : 
    1706                 :          1 :   fd2 = open ("/dev/random", O_RDONLY);
    1707                 :          1 :   g_assert_cmpint (fd2, >=, 0);
    1708                 :          1 :   source = g_unix_fd_source_new (fd2, G_IO_IN);
    1709                 :          1 :   g_source_set_callback (source, G_SOURCE_FUNC (flag_bool), &s3, NULL);
    1710                 :          1 :   g_source_set_priority (source, 0);
    1711                 :          1 :   g_source_attach (source, NULL);
    1712                 :          1 :   g_source_unref (source);
    1713                 :            : 
    1714                 :            :   /* This tests a bug that depends on the source with the lowest FD
    1715                 :            :      identifier to have the lowest priority. Make sure that this is
    1716                 :            :      the case. */
    1717                 :          1 :   g_assert_cmpint (fd1, <, fd2);
    1718                 :            : 
    1719                 :          1 :   g_assert_true (g_main_context_iteration (NULL, FALSE));
    1720                 :            : 
    1721                 :            :   /* Idle source should have been dispatched. */
    1722                 :          1 :   g_assert_cmpint (s1, ==, 1);
    1723                 :            :   /* Low priority FD source shouldn't have been dispatched. */
    1724                 :          1 :   g_assert_false (s2);
    1725                 :            :   /* Default priority FD source should have been dispatched. */
    1726                 :          1 :   g_assert_true (s3);
    1727                 :            : 
    1728                 :          1 :   g_main_loop_unref (loop);
    1729                 :            : 
    1730                 :          1 :   close (fd1);
    1731                 :          1 :   close (fd2);
    1732                 :          1 : }
    1733                 :            : 
    1734                 :            : #endif
    1735                 :            : 
    1736                 :            : #ifdef G_OS_UNIX
    1737                 :            : static gboolean
    1738                 :          2 : timeout_cb (gpointer data)
    1739                 :            : {
    1740                 :          2 :   GMainLoop *loop = data;
    1741                 :            :   GMainContext *context;
    1742                 :            : 
    1743                 :          2 :   context = g_main_loop_get_context (loop);
    1744                 :          2 :   g_assert_true (g_main_loop_is_running (loop));
    1745                 :          2 :   g_assert_true (g_main_context_is_owner (context));
    1746                 :            : 
    1747                 :          2 :   g_main_loop_quit (loop);
    1748                 :            : 
    1749                 :          2 :   return G_SOURCE_REMOVE;
    1750                 :            : }
    1751                 :            : 
    1752                 :            : static gpointer
    1753                 :          2 : threadf (gpointer data)
    1754                 :            : {
    1755                 :          2 :   GMainContext *context = data;
    1756                 :            :   GMainLoop *loop;
    1757                 :            :   GSource *source;
    1758                 :            : 
    1759                 :          2 :   loop = g_main_loop_new (context, FALSE);
    1760                 :          2 :   source = g_timeout_source_new (250);
    1761                 :          2 :   g_source_set_callback (source, timeout_cb, loop, NULL);
    1762                 :          2 :   g_source_attach (source, context);
    1763                 :            :  
    1764                 :          2 :   g_main_loop_run (loop);
    1765                 :            : 
    1766                 :          2 :   g_source_destroy (source);
    1767                 :          2 :   g_source_unref (source);
    1768                 :          2 :   g_main_loop_unref (loop);
    1769                 :            : 
    1770                 :          2 :   return NULL;
    1771                 :            : }
    1772                 :            : 
    1773                 :            : static void
    1774                 :          1 : test_mainloop_wait (void)
    1775                 :            : {
    1776                 :            :   GMainContext *context;
    1777                 :            :   GThread *t1, *t2;
    1778                 :            : 
    1779                 :          1 :   context = g_main_context_new ();
    1780                 :            : 
    1781                 :          1 :   t1 = g_thread_new ("t1", threadf, context);
    1782                 :          1 :   t2 = g_thread_new ("t2", threadf, context);
    1783                 :            : 
    1784                 :          1 :   g_thread_join (t1);
    1785                 :          1 :   g_thread_join (t2);
    1786                 :            : 
    1787                 :          1 :   g_main_context_unref (context);
    1788                 :          1 : }
    1789                 :            : #endif
    1790                 :            : 
    1791                 :            : static gboolean
    1792                 :          1 : nfds_in_cb (GIOChannel   *io,
    1793                 :            :             GIOCondition  condition,
    1794                 :            :             gpointer      user_data)
    1795                 :            : {
    1796                 :          1 :   gboolean *in_cb_ran = user_data;
    1797                 :            : 
    1798                 :          1 :   *in_cb_ran = TRUE;
    1799                 :          1 :   g_assert_cmpint (condition, ==, G_IO_IN);
    1800                 :          1 :   return FALSE;
    1801                 :            : }
    1802                 :            : 
    1803                 :            : static gboolean
    1804                 :          1 : nfds_out_cb (GIOChannel   *io,
    1805                 :            :              GIOCondition  condition,
    1806                 :            :              gpointer      user_data)
    1807                 :            : {
    1808                 :          1 :   gboolean *out_cb_ran = user_data;
    1809                 :            : 
    1810                 :          1 :   *out_cb_ran = TRUE;
    1811                 :          1 :   g_assert_cmpint (condition, ==, G_IO_OUT);
    1812                 :          1 :   return FALSE;
    1813                 :            : }
    1814                 :            : 
    1815                 :            : static gboolean
    1816                 :          0 : nfds_out_low_cb (GIOChannel   *io,
    1817                 :            :                  GIOCondition  condition,
    1818                 :            :                  gpointer      user_data)
    1819                 :            : {
    1820                 :            :   g_assert_not_reached ();
    1821                 :            :   return FALSE;
    1822                 :            : }
    1823                 :            : 
    1824                 :            : static void
    1825                 :          1 : test_nfds (void)
    1826                 :            : {
    1827                 :            :   GMainContext *ctx;
    1828                 :            :   GPollFD out_fds[3];
    1829                 :            :   gint fd, nfds;
    1830                 :            :   GIOChannel *io;
    1831                 :            :   GSource *source1, *source2, *source3;
    1832                 :          1 :   gboolean source1_ran = FALSE, source3_ran = FALSE;
    1833                 :            :   gchar *tmpfile;
    1834                 :          1 :   GError *error = NULL;
    1835                 :            : 
    1836                 :          1 :   ctx = g_main_context_new ();
    1837                 :          1 :   nfds = g_main_context_query (ctx, G_MAXINT, NULL,
    1838                 :            :                                out_fds, G_N_ELEMENTS (out_fds));
    1839                 :            :   /* An "empty" GMainContext will have a single GPollFD, for its
    1840                 :            :    * internal GWakeup.
    1841                 :            :    */
    1842                 :          1 :   g_assert_cmpint (nfds, ==, 1);
    1843                 :            : 
    1844                 :          1 :   fd = g_file_open_tmp (NULL, &tmpfile, &error);
    1845                 :          1 :   g_assert_no_error (error);
    1846                 :            : 
    1847                 :          1 :   io = g_io_channel_unix_new (fd);
    1848                 :            : #ifdef G_OS_WIN32
    1849                 :            :   /* The fd in the pollfds won't be the same fd we passed in */
    1850                 :            :   g_io_channel_win32_make_pollfd (io, G_IO_IN, out_fds);
    1851                 :            :   fd = out_fds[0].fd;
    1852                 :            : #endif
    1853                 :            : 
    1854                 :            :   /* Add our first pollfd */
    1855                 :          1 :   source1 = g_io_create_watch (io, G_IO_IN);
    1856                 :          1 :   g_source_set_priority (source1, G_PRIORITY_DEFAULT);
    1857                 :          1 :   g_source_set_callback (source1, (GSourceFunc) nfds_in_cb,
    1858                 :            :                          &source1_ran, NULL);
    1859                 :          1 :   g_source_attach (source1, ctx);
    1860                 :            : 
    1861                 :          1 :   nfds = g_main_context_query (ctx, G_MAXINT, NULL,
    1862                 :            :                                out_fds, G_N_ELEMENTS (out_fds));
    1863                 :          1 :   g_assert_cmpint (nfds, ==, 2);
    1864         [ -  + ]:          1 :   if (out_fds[0].fd == fd)
    1865                 :          0 :     g_assert_cmpint (out_fds[0].events, ==, G_IO_IN);
    1866         [ +  - ]:          1 :   else if (out_fds[1].fd == fd)
    1867                 :          1 :     g_assert_cmpint (out_fds[1].events, ==, G_IO_IN);
    1868                 :            :   else
    1869                 :            :     g_assert_not_reached ();
    1870                 :            : 
    1871                 :            :   /* Add a second pollfd with the same fd but different event, and
    1872                 :            :    * lower priority.
    1873                 :            :    */
    1874                 :          1 :   source2 = g_io_create_watch (io, G_IO_OUT);
    1875                 :          1 :   g_source_set_priority (source2, G_PRIORITY_LOW);
    1876                 :          1 :   g_source_set_callback (source2, (GSourceFunc) nfds_out_low_cb,
    1877                 :            :                          NULL, NULL);
    1878                 :          1 :   g_source_attach (source2, ctx);
    1879                 :            : 
    1880                 :            :   /* g_main_context_query() should still return only 2 pollfds,
    1881                 :            :    * one of which has our fd, and a combined events field.
    1882                 :            :    */
    1883                 :          1 :   nfds = g_main_context_query (ctx, G_MAXINT, NULL,
    1884                 :            :                                out_fds, G_N_ELEMENTS (out_fds));
    1885                 :          1 :   g_assert_cmpint (nfds, ==, 2);
    1886         [ -  + ]:          1 :   if (out_fds[0].fd == fd)
    1887                 :          0 :     g_assert_cmpint (out_fds[0].events, ==, G_IO_IN | G_IO_OUT);
    1888         [ +  - ]:          1 :   else if (out_fds[1].fd == fd)
    1889                 :          1 :     g_assert_cmpint (out_fds[1].events, ==, G_IO_IN | G_IO_OUT);
    1890                 :            :   else
    1891                 :            :     g_assert_not_reached ();
    1892                 :            : 
    1893                 :            :   /* But if we query with a max priority, we won't see the
    1894                 :            :    * lower-priority one.
    1895                 :            :    */
    1896                 :          1 :   nfds = g_main_context_query (ctx, G_PRIORITY_DEFAULT, NULL,
    1897                 :            :                                out_fds, G_N_ELEMENTS (out_fds));
    1898                 :          1 :   g_assert_cmpint (nfds, ==, 2);
    1899         [ -  + ]:          1 :   if (out_fds[0].fd == fd)
    1900                 :          0 :     g_assert_cmpint (out_fds[0].events, ==, G_IO_IN);
    1901         [ +  - ]:          1 :   else if (out_fds[1].fd == fd)
    1902                 :          1 :     g_assert_cmpint (out_fds[1].events, ==, G_IO_IN);
    1903                 :            :   else
    1904                 :            :     g_assert_not_reached ();
    1905                 :            : 
    1906                 :            :   /* Third pollfd */
    1907                 :          1 :   source3 = g_io_create_watch (io, G_IO_OUT);
    1908                 :          1 :   g_source_set_priority (source3, G_PRIORITY_DEFAULT);
    1909                 :          1 :   g_source_set_callback (source3, (GSourceFunc) nfds_out_cb,
    1910                 :            :                          &source3_ran, NULL);
    1911                 :          1 :   g_source_attach (source3, ctx);
    1912                 :            : 
    1913                 :          1 :   nfds = g_main_context_query (ctx, G_MAXINT, NULL,
    1914                 :            :                                out_fds, G_N_ELEMENTS (out_fds));
    1915                 :          1 :   g_assert_cmpint (nfds, ==, 2);
    1916         [ -  + ]:          1 :   if (out_fds[0].fd == fd)
    1917                 :          0 :     g_assert_cmpint (out_fds[0].events, ==, G_IO_IN | G_IO_OUT);
    1918         [ +  - ]:          1 :   else if (out_fds[1].fd == fd)
    1919                 :          1 :     g_assert_cmpint (out_fds[1].events, ==, G_IO_IN | G_IO_OUT);
    1920                 :            :   else
    1921                 :            :     g_assert_not_reached ();
    1922                 :            : 
    1923                 :            :   /* Now actually iterate the loop; the fd should be readable and
    1924                 :            :    * writable, so source1 and source3 should be triggered, but *not*
    1925                 :            :    * source2, since it's lower priority than them.
    1926                 :            :    */
    1927                 :          1 :   g_main_context_iteration (ctx, FALSE);
    1928                 :            : 
    1929                 :            :   /* FIXME:
    1930                 :            :    * On win32, giowin32.c uses blocking threads for read/write on channels. They
    1931                 :            :    * may not have yet triggered an event after one loop iteration. Hence, the
    1932                 :            :    * following asserts are racy and disabled.
    1933                 :            :    */
    1934                 :            : #ifndef G_OS_WIN32
    1935                 :          1 :   g_assert_true (source1_ran);
    1936                 :          1 :   g_assert_true (source3_ran);
    1937                 :            : #endif
    1938                 :            : 
    1939                 :          1 :   g_source_destroy (source1);
    1940                 :          1 :   g_source_unref (source1);
    1941                 :          1 :   g_source_destroy (source2);
    1942                 :          1 :   g_source_unref (source2);
    1943                 :          1 :   g_source_destroy (source3);
    1944                 :          1 :   g_source_unref (source3);
    1945                 :            : 
    1946                 :          1 :   g_io_channel_unref (io);
    1947                 :          1 :   remove (tmpfile);
    1948                 :          1 :   g_free (tmpfile);
    1949                 :            : 
    1950                 :          1 :   g_main_context_unref (ctx);
    1951                 :          1 : }
    1952                 :            : 
    1953                 :            : static gboolean
    1954                 :          0 : nsources_cb (gpointer user_data)
    1955                 :            : {
    1956                 :            :   g_assert_not_reached ();
    1957                 :            :   return FALSE;
    1958                 :            : }
    1959                 :            : 
    1960                 :            : static void
    1961                 :          2 : shuffle_nsources (GSource **sources, int num)
    1962                 :            : {
    1963                 :            :   int i, a, b;
    1964                 :            :   GSource *tmp;
    1965                 :            : 
    1966         [ +  + ]:    1000002 :   for (i = 0; i < num * 10; i++)
    1967                 :            :     {
    1968                 :    1000000 :       a = g_random_int_range (0, num);
    1969                 :    1000000 :       b = g_random_int_range (0, num);
    1970                 :    1000000 :       tmp = sources[a];
    1971                 :    1000000 :       sources[a] = sources[b];
    1972                 :    1000000 :       sources[b] = tmp;
    1973                 :            :     }
    1974                 :          2 : }
    1975                 :            : 
    1976                 :            : static void
    1977                 :          1 : test_nsources_same_priority (void)
    1978                 :            : {
    1979                 :            :   GMainContext *context;
    1980                 :            :   GSource **sources;
    1981                 :            :   gint64 start, end;
    1982                 :          1 :   gsize n_sources = 50000, i;
    1983                 :            : 
    1984                 :          1 :   context = g_main_context_default ();
    1985                 :          1 :   sources = g_new0 (GSource *, n_sources);
    1986                 :            : 
    1987                 :          1 :   start = g_get_monotonic_time ();
    1988         [ +  + ]:      50001 :   for (i = 0; i < n_sources; i++)
    1989                 :            :     {
    1990                 :      50000 :       sources[i] = g_idle_source_new ();
    1991                 :      50000 :       g_source_set_callback (sources[i], nsources_cb, NULL, NULL);
    1992                 :      50000 :       g_source_attach (sources[i], context);
    1993                 :            :     }
    1994                 :          1 :   end = g_get_monotonic_time ();
    1995                 :          1 :   g_test_message ("Add same-priority sources: %" G_GINT64_FORMAT,
    1996                 :          1 :                   (end - start) / 1000);
    1997                 :            : 
    1998                 :          1 :   start = g_get_monotonic_time ();
    1999         [ +  + ]:      50001 :   for (i = 0; i < n_sources; i++)
    2000                 :      50000 :     g_assert_true (sources[i] == g_main_context_find_source_by_id (context, g_source_get_id (sources[i])));
    2001                 :          1 :   end = g_get_monotonic_time ();
    2002                 :          1 :   g_test_message ("Find each source: %" G_GINT64_FORMAT,
    2003                 :          1 :                   (end - start) / 1000);
    2004                 :            : 
    2005                 :          1 :   shuffle_nsources (sources, n_sources);
    2006                 :            : 
    2007                 :          1 :   start = g_get_monotonic_time ();
    2008         [ +  + ]:      50001 :   for (i = 0; i < n_sources; i++)
    2009                 :            :     {
    2010                 :      50000 :       g_source_destroy (sources[i]);
    2011                 :      50000 :       g_source_unref (sources[i]);
    2012                 :            :     }
    2013                 :          1 :   end = g_get_monotonic_time ();
    2014                 :          1 :   g_test_message ("Remove in random order: %" G_GINT64_FORMAT,
    2015                 :          1 :                   (end - start) / 1000);
    2016                 :            : 
    2017                 :            :   /* Make sure they really did get removed */
    2018                 :          1 :   g_main_context_iteration (context, FALSE);
    2019                 :            : 
    2020                 :          1 :   g_free (sources);
    2021                 :          1 : }
    2022                 :            : 
    2023                 :            : static void
    2024                 :          1 : test_nsources_different_priority (void)
    2025                 :            : {
    2026                 :            :   GMainContext *context;
    2027                 :            :   GSource **sources;
    2028                 :            :   gint64 start, end;
    2029                 :          1 :   gsize n_sources = 50000, i;
    2030                 :            : 
    2031                 :          1 :   context = g_main_context_default ();
    2032                 :          1 :   sources = g_new0 (GSource *, n_sources);
    2033                 :            : 
    2034                 :          1 :   start = g_get_monotonic_time ();
    2035         [ +  + ]:      50001 :   for (i = 0; i < n_sources; i++)
    2036                 :            :     {
    2037                 :      50000 :       sources[i] = g_idle_source_new ();
    2038                 :      50000 :       g_source_set_callback (sources[i], nsources_cb, NULL, NULL);
    2039                 :      50000 :       g_source_set_priority (sources[i], i % 100);
    2040                 :      50000 :       g_source_attach (sources[i], context);
    2041                 :            :     }
    2042                 :          1 :   end = g_get_monotonic_time ();
    2043                 :          1 :   g_test_message ("Add different-priority sources: %" G_GINT64_FORMAT,
    2044                 :          1 :                   (end - start) / 1000);
    2045                 :            : 
    2046                 :          1 :   start = g_get_monotonic_time ();
    2047         [ +  + ]:      50001 :   for (i = 0; i < n_sources; i++)
    2048                 :      50000 :     g_assert_true (sources[i] == g_main_context_find_source_by_id (context, g_source_get_id (sources[i])));
    2049                 :          1 :   end = g_get_monotonic_time ();
    2050                 :          1 :   g_test_message ("Find each source: %" G_GINT64_FORMAT,
    2051                 :          1 :                   (end - start) / 1000);
    2052                 :            : 
    2053                 :          1 :   shuffle_nsources (sources, n_sources);
    2054                 :            : 
    2055                 :          1 :   start = g_get_monotonic_time ();
    2056         [ +  + ]:      50001 :   for (i = 0; i < n_sources; i++)
    2057                 :            :     {
    2058                 :      50000 :       g_source_destroy (sources[i]);
    2059                 :      50000 :       g_source_unref (sources[i]);
    2060                 :            :     }
    2061                 :          1 :   end = g_get_monotonic_time ();
    2062                 :          1 :   g_test_message ("Remove in random order: %" G_GINT64_FORMAT,
    2063                 :          1 :                   (end - start) / 1000);
    2064                 :            : 
    2065                 :            :   /* Make sure they really did get removed */
    2066                 :          1 :   g_main_context_iteration (context, FALSE);
    2067                 :            : 
    2068                 :          1 :   g_free (sources);
    2069                 :          1 : }
    2070                 :            : 
    2071                 :            : static void
    2072                 :      50000 : thread_pool_attach_func (gpointer data,
    2073                 :            :                          gpointer user_data)
    2074                 :            : {
    2075                 :      50000 :   GMainContext *context = user_data;
    2076                 :      50000 :   GSource *source = data;
    2077                 :            : 
    2078                 :      50000 :   g_source_attach (source, context);
    2079                 :      50000 :   g_source_unref (source);
    2080                 :      50000 : }
    2081                 :            : 
    2082                 :            : static void
    2083                 :      50000 : thread_pool_destroy_func (gpointer data,
    2084                 :            :                           gpointer user_data)
    2085                 :            : {
    2086                 :      50000 :   GSource *source = data;
    2087                 :            : 
    2088                 :      50000 :   g_source_destroy (source);
    2089                 :      50000 : }
    2090                 :            : 
    2091                 :            : static void
    2092                 :          1 : test_nsources_threadpool (void)
    2093                 :            : {
    2094                 :            :   GMainContext *context;
    2095                 :            :   GSource **sources;
    2096                 :            :   GThreadPool *pool;
    2097                 :          1 :   GError *error = NULL;
    2098                 :            :   gint64 start, end;
    2099                 :          1 :   gsize n_sources = 50000, i;
    2100                 :            : 
    2101                 :          1 :   context = g_main_context_default ();
    2102                 :          1 :   sources = g_new0 (GSource *, n_sources);
    2103                 :            : 
    2104                 :          1 :   pool = g_thread_pool_new (thread_pool_attach_func, context,
    2105                 :            :                             20, TRUE, NULL);
    2106                 :          1 :   start = g_get_monotonic_time ();
    2107         [ +  + ]:      50001 :   for (i = 0; i < n_sources; i++)
    2108                 :            :     {
    2109                 :      50000 :       sources[i] = g_idle_source_new ();
    2110                 :      50000 :       g_source_set_callback (sources[i], nsources_cb, NULL, NULL);
    2111                 :      50000 :       g_thread_pool_push (pool, sources[i], &error);
    2112                 :      50000 :       g_assert_no_error (error);
    2113                 :            :     }
    2114                 :          1 :   g_thread_pool_free (pool, FALSE, TRUE);
    2115                 :          1 :   end = g_get_monotonic_time ();
    2116                 :          1 :   g_test_message ("Add sources from threads: %" G_GINT64_FORMAT,
    2117                 :          1 :                   (end - start) / 1000);
    2118                 :            : 
    2119                 :          1 :   pool = g_thread_pool_new (thread_pool_destroy_func, context,
    2120                 :            :                             20, TRUE, NULL);
    2121                 :          1 :   start = g_get_monotonic_time ();
    2122         [ +  + ]:      50001 :   for (i = 0; i < n_sources; i++)
    2123                 :            :     {
    2124                 :      50000 :       g_thread_pool_push (pool, sources[i], &error);
    2125                 :      50000 :       g_assert_no_error (error);
    2126                 :            :     }
    2127                 :          1 :   g_thread_pool_free (pool, FALSE, TRUE);
    2128                 :          1 :   end = g_get_monotonic_time ();
    2129                 :          1 :   g_test_message ("Remove sources from threads: %" G_GINT64_FORMAT,
    2130                 :          1 :                   (end - start) / 1000);
    2131                 :            : 
    2132                 :            :   /* Make sure they really did get removed */
    2133                 :          1 :   g_main_context_iteration (context, FALSE);
    2134                 :            : 
    2135                 :          1 :   g_free (sources);
    2136                 :          1 : }
    2137                 :            : 
    2138                 :            : static gboolean source_finalize_called = FALSE;
    2139                 :            : static guint source_dispose_called = 0;
    2140                 :            : static gboolean source_dispose_recycle = FALSE;
    2141                 :            : 
    2142                 :            : static void
    2143                 :          3 : finalize (GSource *source)
    2144                 :            : {
    2145                 :          3 :   g_assert_false (source_finalize_called);
    2146                 :          3 :   source_finalize_called = TRUE;
    2147                 :          3 : }
    2148                 :            : 
    2149                 :            : static void
    2150                 :          3 : dispose (GSource *source)
    2151                 :            : {
    2152                 :            :   /* Dispose must always be called before finalize */
    2153                 :          3 :   g_assert_false (source_finalize_called);
    2154                 :            : 
    2155         [ +  + ]:          3 :   if (source_dispose_recycle)
    2156                 :          1 :     g_source_ref (source);
    2157                 :          3 :   source_dispose_called++;
    2158                 :          3 : }
    2159                 :            : 
    2160                 :            : static GSourceFuncs source_funcs = {
    2161                 :            :   prepare,
    2162                 :            :   check,
    2163                 :            :   dispatch,
    2164                 :            :   finalize,
    2165                 :            :   NULL,
    2166                 :            :   NULL
    2167                 :            : };
    2168                 :            : 
    2169                 :            : static void
    2170                 :          1 : test_maincontext_source_finalization (void)
    2171                 :            : {
    2172                 :            :   GSource *source;
    2173                 :            : 
    2174                 :            :   /* Check if GSource destruction without dispose function works and calls the
    2175                 :            :    * finalize function as expected */
    2176                 :          1 :   source_finalize_called = FALSE;
    2177                 :          1 :   source_dispose_called = 0;
    2178                 :          1 :   source_dispose_recycle = FALSE;
    2179                 :          1 :   source = g_source_new (&source_funcs, sizeof (GSource));
    2180                 :          1 :   g_source_unref (source);
    2181                 :          1 :   g_assert_cmpint (source_dispose_called, ==, 0);
    2182                 :          1 :   g_assert_true (source_finalize_called);
    2183                 :            : 
    2184                 :            :   /* Check if GSource destruction with dispose function works and calls the
    2185                 :            :    * dispose and finalize function as expected */
    2186                 :          1 :   source_finalize_called = FALSE;
    2187                 :          1 :   source_dispose_called = 0;
    2188                 :          1 :   source_dispose_recycle = FALSE;
    2189                 :          1 :   source = g_source_new (&source_funcs, sizeof (GSource));
    2190                 :          1 :   g_source_set_dispose_function (source, dispose);
    2191                 :          1 :   g_source_unref (source);
    2192                 :          1 :   g_assert_cmpint (source_dispose_called, ==, 1);
    2193                 :          1 :   g_assert_true (source_finalize_called);
    2194                 :            : 
    2195                 :            :   /* Check if GSource destruction with dispose function works and recycling
    2196                 :            :    * the source from dispose works without calling the finalize function */
    2197                 :          1 :   source_finalize_called = FALSE;
    2198                 :          1 :   source_dispose_called = 0;
    2199                 :          1 :   source_dispose_recycle = TRUE;
    2200                 :          1 :   source = g_source_new (&source_funcs, sizeof (GSource));
    2201                 :          1 :   g_source_set_dispose_function (source, dispose);
    2202                 :          1 :   g_source_unref (source);
    2203                 :          1 :   g_assert_cmpint (source_dispose_called, ==, 1);
    2204                 :          1 :   g_assert_false (source_finalize_called);
    2205                 :            : 
    2206                 :            :   /* Check if the source is properly recycled */
    2207                 :          1 :   g_assert_cmpint (source->ref_count, ==, 1);
    2208                 :            : 
    2209                 :            :   /* And then get rid of it properly */
    2210                 :          1 :   source_dispose_recycle = FALSE;
    2211                 :          1 :   g_source_unref (source);
    2212                 :          1 :   g_assert_cmpint (source_dispose_called, ==, 2);
    2213                 :          1 :   g_assert_true (source_finalize_called);
    2214                 :          1 : }
    2215                 :            : 
    2216                 :            : /* GSource implementation which optionally keeps a strong reference to another
    2217                 :            :  * GSource until finalization, when it destroys and unrefs the other source.
    2218                 :            :  */
    2219                 :            : typedef struct {
    2220                 :            :   GSource source;
    2221                 :            : 
    2222                 :            :   GSource *other_source;
    2223                 :            : } SourceWithSource;
    2224                 :            : 
    2225                 :            : static void
    2226                 :         26 : finalize_source_with_source (GSource *source)
    2227                 :            : {
    2228                 :         26 :   SourceWithSource *s = (SourceWithSource *) source;
    2229                 :            : 
    2230         [ +  + ]:         26 :   if (s->other_source)
    2231                 :            :     {
    2232                 :         13 :       g_source_destroy (s->other_source);
    2233                 :         13 :       g_source_unref (s->other_source);
    2234                 :         13 :       s->other_source = NULL;
    2235                 :            :     }
    2236                 :         26 : }
    2237                 :            : 
    2238                 :            : static GSourceFuncs source_with_source_funcs = {
    2239                 :            :   NULL,
    2240                 :            :   NULL,
    2241                 :            :   NULL,
    2242                 :            :   finalize_source_with_source,
    2243                 :            :   NULL,
    2244                 :            :   NULL
    2245                 :            : };
    2246                 :            : 
    2247                 :            : static void
    2248                 :         10 : test_maincontext_source_finalization_from_source (gconstpointer user_data)
    2249                 :            : {
    2250                 :         10 :   GMainContext *c = g_main_context_new ();
    2251                 :            :   GSource *s1, *s2;
    2252                 :            : 
    2253                 :         10 :   g_test_summary ("Tests if freeing a GSource as part of another GSource "
    2254                 :            :                   "during main context destruction works.");
    2255                 :         10 :   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/merge_requests/1353");
    2256                 :            : 
    2257                 :         10 :   s1 = g_source_new (&source_with_source_funcs, sizeof (SourceWithSource));
    2258                 :         10 :   s2 = g_source_new (&source_with_source_funcs, sizeof (SourceWithSource));
    2259                 :         10 :   ((SourceWithSource *)s1)->other_source = g_source_ref (s2);
    2260                 :            : 
    2261                 :            :   /* Attach sources in a different order so they end up being destroyed
    2262                 :            :    * in a different order by the main context */
    2263         [ +  + ]:         10 :   if (GPOINTER_TO_INT (user_data) < 5)
    2264                 :            :     {
    2265                 :          5 :       g_source_attach (s1, c);
    2266                 :          5 :       g_source_attach (s2, c);
    2267                 :            :     }
    2268                 :            :   else
    2269                 :            :     {
    2270                 :          5 :       g_source_attach (s2, c);
    2271                 :          5 :       g_source_attach (s1, c);
    2272                 :            :     }
    2273                 :            : 
    2274                 :            :   /* Test a few different permutations here */
    2275         [ +  + ]:         10 :   if (GPOINTER_TO_INT (user_data) % 5 == 0)
    2276                 :            :     {
    2277                 :            :       /* Get rid of our references so that destroying the context
    2278                 :            :        * will unref them immediately */
    2279                 :          2 :       g_source_unref (s1);
    2280                 :          2 :       g_source_unref (s2);
    2281                 :          2 :       g_main_context_unref (c);
    2282                 :            :     }
    2283         [ +  + ]:          8 :   else if (GPOINTER_TO_INT (user_data) % 5 == 1)
    2284                 :            :     {
    2285                 :            :       /* Destroy and free the sources before the context */
    2286                 :          2 :       g_source_destroy (s1);
    2287                 :          2 :       g_source_unref (s1);
    2288                 :          2 :       g_source_destroy (s2);
    2289                 :          2 :       g_source_unref (s2);
    2290                 :          2 :       g_main_context_unref (c);
    2291                 :            :     }
    2292         [ +  + ]:          6 :   else if (GPOINTER_TO_INT (user_data) % 5 == 2)
    2293                 :            :     {
    2294                 :            :       /* Destroy and free the sources before the context */
    2295                 :          2 :       g_source_destroy (s2);
    2296                 :          2 :       g_source_unref (s2);
    2297                 :          2 :       g_source_destroy (s1);
    2298                 :          2 :       g_source_unref (s1);
    2299                 :          2 :       g_main_context_unref (c);
    2300                 :            :     }
    2301         [ +  + ]:          4 :   else if (GPOINTER_TO_INT (user_data) % 5 == 3)
    2302                 :            :     {
    2303                 :            :       /* Destroy and free the context before the sources */
    2304                 :          2 :       g_main_context_unref (c);
    2305                 :          2 :       g_source_unref (s2);
    2306                 :          2 :       g_source_unref (s1);
    2307                 :            :     }
    2308         [ +  - ]:          2 :   else if (GPOINTER_TO_INT (user_data) % 5 == 4)
    2309                 :            :     {
    2310                 :            :       /* Destroy and free the context before the sources */
    2311                 :          2 :       g_main_context_unref (c);
    2312                 :          2 :       g_source_unref (s1);
    2313                 :          2 :       g_source_unref (s2);
    2314                 :            :     }
    2315                 :         10 : }
    2316                 :            : 
    2317                 :            : static gboolean
    2318                 :          3 : dispatch_source_with_source (GSource *source, GSourceFunc callback, gpointer user_data)
    2319                 :            : {
    2320                 :          3 :   return G_SOURCE_REMOVE;
    2321                 :            : }
    2322                 :            : 
    2323                 :            : static GSourceFuncs source_with_source_funcs_dispatch = {
    2324                 :            :   NULL,
    2325                 :            :   NULL,
    2326                 :            :   dispatch_source_with_source,
    2327                 :            :   finalize_source_with_source,
    2328                 :            :   NULL,
    2329                 :            :   NULL
    2330                 :            : };
    2331                 :            : 
    2332                 :            : static void
    2333                 :          3 : test_maincontext_source_finalization_from_dispatch (gconstpointer user_data)
    2334                 :            : {
    2335                 :          3 :   GMainContext *c = g_main_context_new ();
    2336                 :            :   GSource *s1, *s2;
    2337                 :            : 
    2338                 :          3 :   g_test_summary ("Tests if freeing a GSource as part of another GSource "
    2339                 :            :                   "during main context iteration works.");
    2340                 :            : 
    2341                 :          3 :   s1 = g_source_new (&source_with_source_funcs_dispatch, sizeof (SourceWithSource));
    2342                 :          3 :   s2 = g_source_new (&source_with_source_funcs_dispatch, sizeof (SourceWithSource));
    2343                 :          3 :   ((SourceWithSource *)s1)->other_source = g_source_ref (s2);
    2344                 :            : 
    2345                 :          3 :   g_source_attach (s1, c);
    2346                 :          3 :   g_source_attach (s2, c);
    2347                 :            : 
    2348         [ +  + ]:          3 :   if (GPOINTER_TO_INT (user_data) == 0)
    2349                 :            :     {
    2350                 :            :       /* This finalizes s1 as part of the iteration, which then destroys and
    2351                 :            :        * frees s2 too */
    2352                 :          1 :       g_source_set_ready_time (s1, 0);
    2353                 :            :     }
    2354         [ +  + ]:          2 :   else if (GPOINTER_TO_INT (user_data) == 1)
    2355                 :            :     {
    2356                 :            :       /* This destroys s2 as part of the iteration but does not free it as
    2357                 :            :        * it's still referenced by s1 */
    2358                 :          1 :       g_source_set_ready_time (s2, 0);
    2359                 :            :     }
    2360         [ +  - ]:          1 :   else if (GPOINTER_TO_INT (user_data) == 2)
    2361                 :            :     {
    2362                 :            :       /* This destroys both s1 and s2 as part of the iteration */
    2363                 :          1 :       g_source_set_ready_time (s1, 0);
    2364                 :          1 :       g_source_set_ready_time (s2, 0);
    2365                 :            :     }
    2366                 :            : 
    2367                 :            :   /* Get rid of our references so only the main context has one now */
    2368                 :          3 :   g_source_unref (s1);
    2369                 :          3 :   g_source_unref (s2);
    2370                 :            : 
    2371                 :            :   /* Iterate as long as there are sources to dispatch */
    2372         [ +  + ]:          6 :   while (g_main_context_iteration (c, FALSE))
    2373                 :            :     {
    2374                 :            :       /* Do nothing here */
    2375                 :            :     }
    2376                 :            : 
    2377                 :          3 :   g_main_context_unref (c);
    2378                 :          3 : }
    2379                 :            : 
    2380                 :            : static void
    2381                 :          3 : once_cb (gpointer user_data)
    2382                 :            : {
    2383                 :          3 :   guint *counter = user_data;
    2384                 :            : 
    2385                 :          3 :   *counter = *counter + 1;
    2386                 :          3 : }
    2387                 :            : 
    2388                 :            : static void
    2389                 :          1 : test_maincontext_idle_once (void)
    2390                 :            : {
    2391                 :          1 :   guint counter = 0;
    2392                 :            :   guint source_id;
    2393                 :            :   GSource *source;
    2394                 :            : 
    2395                 :          1 :   g_test_summary ("Test g_idle_add_once() works");
    2396                 :            : 
    2397                 :          1 :   source_id = g_idle_add_once (once_cb, &counter);
    2398                 :          1 :   source = g_main_context_find_source_by_id (NULL, source_id);
    2399                 :          1 :   g_assert_nonnull (source);
    2400                 :          1 :   g_source_ref (source);
    2401                 :            : 
    2402                 :            :   /* Iterating the main context should dispatch the source. */
    2403                 :          1 :   g_assert_cmpuint (counter, ==, 0);
    2404                 :          1 :   g_main_context_iteration (NULL, FALSE);
    2405                 :          1 :   g_assert_cmpuint (counter, ==, 1);
    2406                 :            : 
    2407                 :            :   /* Iterating it again should not dispatch the source again. */
    2408                 :          1 :   g_main_context_iteration (NULL, FALSE);
    2409                 :          1 :   g_assert_cmpuint (counter, ==, 1);
    2410                 :          1 :   g_assert_true (g_source_is_destroyed (source));
    2411                 :            : 
    2412                 :          1 :   g_clear_pointer (&source, g_source_unref);
    2413                 :          1 : }
    2414                 :            : 
    2415                 :            : static void
    2416                 :          1 : test_maincontext_timeout_once (void)
    2417                 :            : {
    2418                 :          1 :   guint counter = 0, check_counter = 0;
    2419                 :            :   guint source_id;
    2420                 :            :   gint64 t;
    2421                 :            :   GSource *source;
    2422                 :            : 
    2423                 :          1 :   g_test_summary ("Test g_timeout_add_once() works");
    2424                 :            : 
    2425                 :          1 :   source_id = g_timeout_add_once (10 /* ms */, once_cb, &counter);
    2426                 :          1 :   source = g_main_context_find_source_by_id (NULL, source_id);
    2427                 :          1 :   g_assert_nonnull (source);
    2428                 :          1 :   g_source_ref (source);
    2429                 :            : 
    2430                 :            :   /* Iterating the main context should dispatch the source, though we have to block. */
    2431                 :          1 :   g_assert_cmpuint (counter, ==, 0);
    2432                 :          1 :   t = g_get_monotonic_time ();
    2433   [ +  -  +  + ]:          2 :   while (g_get_monotonic_time () - t < 50 * 1000 && counter == 0)
    2434                 :          1 :     g_main_context_iteration (NULL, TRUE);
    2435                 :          1 :   g_assert_cmpuint (counter, ==, 1);
    2436                 :            : 
    2437                 :            :   /* Iterating it again should not dispatch the source again. We add a second
    2438                 :            :    * timeout and block until that is dispatched. Given the ordering guarantees,
    2439                 :            :    * we should then know whether the first one would have re-dispatched by then. */
    2440                 :          1 :   g_timeout_add_once (30 /* ms */, once_cb, &check_counter);
    2441                 :          1 :   t = g_get_monotonic_time ();
    2442   [ +  -  +  + ]:          2 :   while (g_get_monotonic_time () - t < 50 * 1000 && check_counter == 0)
    2443                 :          1 :     g_main_context_iteration (NULL, TRUE);
    2444                 :          1 :   g_assert_cmpuint (check_counter, ==, 1);
    2445                 :          1 :   g_assert_cmpuint (counter, ==, 1);
    2446                 :          1 :   g_assert_true (g_source_is_destroyed (source));
    2447                 :            : 
    2448                 :          1 :   g_clear_pointer (&source, g_source_unref);
    2449                 :          1 : }
    2450                 :            : 
    2451                 :            : static void
    2452                 :          1 : test_steal_fd (void)
    2453                 :            : {
    2454                 :          1 :   GError *error = NULL;
    2455                 :          1 :   gchar *tmpfile = NULL;
    2456                 :          1 :   int fd = -42;
    2457                 :            :   int borrowed;
    2458                 :            :   int stolen;
    2459                 :            : 
    2460                 :          1 :   g_assert_cmpint (g_steal_fd (&fd), ==, -42);
    2461                 :          1 :   g_assert_cmpint (fd, ==, -1);
    2462                 :          1 :   g_assert_cmpint (g_steal_fd (&fd), ==, -1);
    2463                 :          1 :   g_assert_cmpint (fd, ==, -1);
    2464                 :            : 
    2465                 :          1 :   fd = g_file_open_tmp (NULL, &tmpfile, &error);
    2466                 :          1 :   g_assert_cmpint (fd, >=, 0);
    2467                 :          1 :   g_assert_no_error (error);
    2468                 :          1 :   borrowed = fd;
    2469                 :          1 :   stolen = g_steal_fd (&fd);
    2470                 :          1 :   g_assert_cmpint (fd, ==, -1);
    2471                 :          1 :   g_assert_cmpint (borrowed, ==, stolen);
    2472                 :            : 
    2473                 :          1 :   g_close (g_steal_fd (&stolen), &error);
    2474                 :          1 :   g_assert_no_error (error);
    2475                 :          1 :   g_assert_cmpint (stolen, ==, -1);
    2476                 :            : 
    2477                 :          1 :   g_assert_no_errno (remove (tmpfile));
    2478                 :          1 :   g_free (tmpfile);
    2479                 :          1 : }
    2480                 :            : 
    2481                 :            : int
    2482                 :          1 : main (int argc, char *argv[])
    2483                 :            : {
    2484                 :            :   gint i;
    2485                 :            : 
    2486                 :          1 :   g_test_init (&argc, &argv, NULL);
    2487                 :            : 
    2488                 :          1 :   g_test_add_func ("/maincontext/basic", test_maincontext_basic);
    2489                 :          1 :   g_test_add_func ("/maincontext/nsources_same_priority", test_nsources_same_priority);
    2490                 :          1 :   g_test_add_func ("/maincontext/nsources_different_priority", test_nsources_different_priority);
    2491                 :          1 :   g_test_add_func ("/maincontext/nsources_threadpool", test_nsources_threadpool);
    2492                 :          1 :   g_test_add_func ("/maincontext/source_finalization", test_maincontext_source_finalization);
    2493         [ +  + ]:         11 :   for (i = 0; i < 10; i++)
    2494                 :            :     {
    2495                 :         10 :       gchar *name = g_strdup_printf ("/maincontext/source_finalization_from_source/%d", i);
    2496                 :         10 :       g_test_add_data_func (name, GINT_TO_POINTER (i), test_maincontext_source_finalization_from_source);
    2497                 :         10 :       g_free (name);
    2498                 :            :     }
    2499         [ +  + ]:          4 :   for (i = 0; i < 3; i++)
    2500                 :            :     {
    2501                 :          3 :       gchar *name = g_strdup_printf ("/maincontext/source_finalization_from_dispatch/%d", i);
    2502                 :          3 :       g_test_add_data_func (name, GINT_TO_POINTER (i), test_maincontext_source_finalization_from_dispatch);
    2503                 :          3 :       g_free (name);
    2504                 :            :     }
    2505                 :          1 :   g_test_add_func ("/maincontext/idle-once", test_maincontext_idle_once);
    2506                 :          1 :   g_test_add_func ("/maincontext/timeout-once", test_maincontext_timeout_once);
    2507                 :            : 
    2508                 :          1 :   g_test_add_func ("/mainloop/basic", test_mainloop_basic);
    2509                 :          1 :   g_test_add_func ("/mainloop/timeouts", test_timeouts);
    2510                 :          1 :   g_test_add_func ("/mainloop/priorities", test_priorities);
    2511                 :          1 :   g_test_add_func ("/mainloop/invoke", test_invoke);
    2512                 :          1 :   g_test_add_func ("/mainloop/child_sources", test_child_sources);
    2513                 :          1 :   g_test_add_func ("/mainloop/recursive_child_sources", test_recursive_child_sources);
    2514                 :          1 :   g_test_add_func ("/mainloop/recursive_loop_child_sources", test_recursive_loop_child_sources);
    2515                 :          1 :   g_test_add_func ("/mainloop/swapping_child_sources", test_swapping_child_sources);
    2516                 :          1 :   g_test_add_func ("/mainloop/blocked_child_sources", test_blocked_child_sources);
    2517                 :          1 :   g_test_add_func ("/mainloop/source_time", test_source_time);
    2518                 :          1 :   g_test_add_func ("/mainloop/overflow", test_mainloop_overflow);
    2519                 :          1 :   g_test_add_func ("/mainloop/ready-time", test_ready_time);
    2520                 :          1 :   g_test_add_func ("/mainloop/wakeup", test_wakeup);
    2521                 :          1 :   g_test_add_func ("/mainloop/remove-invalid", test_remove_invalid);
    2522                 :          1 :   g_test_add_func ("/mainloop/unref-while-pending", test_unref_while_pending);
    2523                 :            : #ifdef G_OS_UNIX
    2524                 :          1 :   g_test_add_func ("/mainloop/unix-fd", test_unix_fd);
    2525                 :          1 :   g_test_add_func ("/mainloop/unix-fd-source", test_unix_fd_source);
    2526                 :          1 :   g_test_add_func ("/mainloop/source-unix-fd-api", test_source_unix_fd_api);
    2527                 :          1 :   g_test_add_func ("/mainloop/wait", test_mainloop_wait);
    2528                 :          1 :   g_test_add_func ("/mainloop/unix-file-poll", test_unix_file_poll);
    2529                 :          1 :   g_test_add_func ("/mainloop/unix-fd-priority", test_unix_fd_priority);
    2530                 :            : #endif
    2531                 :          1 :   g_test_add_func ("/mainloop/nfds", test_nfds);
    2532                 :          1 :   g_test_add_func ("/mainloop/steal-fd", test_steal_fd);
    2533                 :          1 :   g_test_add_data_func ("/mainloop/ownerless-polling/attach-first", GINT_TO_POINTER (TRUE), test_ownerless_polling);
    2534                 :          1 :   g_test_add_data_func ("/mainloop/ownerless-polling/pop-first", GINT_TO_POINTER (FALSE), test_ownerless_polling);
    2535                 :            : 
    2536                 :          1 :   return g_test_run ();
    2537                 :            : }

Generated by: LCOV version 1.14