Change LGPL-2.1+ to LGPL-2.1-or-later
[platform/upstream/glib.git] / glib / tests / mainloop.c
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 cb (gpointer data)
33 {
34   return FALSE;
35 }
36
37 static gboolean
38 prepare (GSource *source, gint *time)
39 {
40   g_assert_nonnull (time);
41   g_assert_cmpint (*time, ==, -1);
42   return FALSE;
43 }
44 static gboolean
45 check (GSource *source)
46 {
47   return FALSE;
48 }
49 static gboolean
50 dispatch (GSource *source, GSourceFunc cb, gpointer date)
51 {
52   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 test_maincontext_basic (void)
66 {
67   GMainContext *ctx;
68   GSource *source;
69   guint id;
70   gpointer data = &global_funcs;
71
72   ctx = g_main_context_new ();
73
74   g_assert_false (g_main_context_pending (ctx));
75   g_assert_false (g_main_context_iteration (ctx, FALSE));
76
77   source = g_source_new (&global_funcs, sizeof (GSource));
78   g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_DEFAULT);
79   g_assert_false (g_source_is_destroyed (source));
80
81   g_assert_false (g_source_get_can_recurse (source));
82   g_assert_null (g_source_get_name (source));
83
84   g_source_set_can_recurse (source, TRUE);
85   g_source_set_static_name (source, "d");
86
87   g_assert_true (g_source_get_can_recurse (source));
88   g_assert_cmpstr (g_source_get_name (source), ==, "d");
89
90   g_source_set_static_name (source, "still d");
91   g_assert_cmpstr (g_source_get_name (source), ==, "still d");
92
93   g_assert_null (g_main_context_find_source_by_user_data (ctx, NULL));
94   g_assert_null (g_main_context_find_source_by_funcs_user_data (ctx, &global_funcs, NULL));
95
96   id = g_source_attach (source, ctx);
97   g_assert_cmpint (g_source_get_id (source), ==, id);
98   g_assert_true (g_main_context_find_source_by_id (ctx, id) == source);
99
100   g_source_set_priority (source, G_PRIORITY_HIGH);
101   g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_HIGH);
102
103   g_source_destroy (source);
104   g_assert_true (g_source_get_context (source) == ctx);
105   g_assert_null (g_main_context_find_source_by_id (ctx, id));
106
107   g_main_context_unref (ctx);
108
109   if (g_test_undefined ())
110     {
111       g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
112                              "*assertion*source->context != NULL*failed*");
113       g_assert_null (g_source_get_context (source));
114       g_test_assert_expected_messages ();
115     }
116
117   g_source_unref (source);
118
119   ctx = g_main_context_default ();
120   source = g_source_new (&global_funcs, sizeof (GSource));
121   g_source_set_funcs (source, &global_funcs);
122   g_source_set_callback (source, cb, data, NULL);
123   id = g_source_attach (source, ctx);
124   g_source_unref (source);
125   g_source_set_name_by_id (id, "e");
126   g_assert_cmpstr (g_source_get_name (source), ==, "e");
127   g_assert_true (g_source_get_context (source) == ctx);
128   g_assert_true (g_source_remove_by_funcs_user_data (&global_funcs, data));
129
130   source = g_source_new (&global_funcs, sizeof (GSource));
131   g_source_set_funcs (source, &global_funcs);
132   g_source_set_callback (source, cb, data, NULL);
133   id = g_source_attach (source, ctx);
134   g_assert_cmpint (id, >, 0);
135   g_source_unref (source);
136   g_assert_true (g_source_remove_by_user_data (data));
137   g_assert_false (g_source_remove_by_user_data ((gpointer)0x1234));
138
139   g_idle_add (cb, data);
140   g_assert_true (g_idle_remove_by_data (data));
141 }
142
143 static void
144 test_mainloop_basic (void)
145 {
146   GMainLoop *loop;
147   GMainContext *ctx;
148
149   loop = g_main_loop_new (NULL, FALSE);
150
151   g_assert_false (g_main_loop_is_running (loop));
152
153   g_main_loop_ref (loop);
154
155   ctx = g_main_loop_get_context (loop);
156   g_assert_true (ctx == g_main_context_default ());
157
158   g_main_loop_unref (loop);
159
160   g_assert_cmpint (g_main_depth (), ==, 0);
161
162   g_main_loop_unref (loop);
163 }
164
165 static void
166 test_ownerless_polling (gconstpointer test_data)
167 {
168   gboolean attach_first = GPOINTER_TO_INT (test_data);
169   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   GSource *source = NULL;
176
177   g_assert_true (ctx != g_main_context_default ());
178
179   g_main_context_push_thread_default (ctx);
180
181   /* Drain events */
182   for (;;)
183     {
184       gboolean ready_to_dispatch = g_main_context_prepare (ctx, &max_priority);
185       gint timeout, nready;
186       fds_size = g_main_context_query (ctx, max_priority, &timeout, fds, G_N_ELEMENTS (fds));
187       nready = g_poll (fds, fds_size, /*timeout=*/0);
188       if (!ready_to_dispatch && nready == 0)
189         {
190           if (timeout == -1)
191             break;
192           else
193             g_usleep (timeout * 1000);
194         }
195       ready_to_dispatch = g_main_context_check (ctx, max_priority, fds, fds_size);
196       if (ready_to_dispatch)
197         g_main_context_dispatch (ctx);
198     }
199
200   if (!attach_first)
201     g_main_context_pop_thread_default (ctx);
202
203   source = g_idle_source_new ();
204   g_source_attach (source, ctx);
205   g_source_unref (source);
206
207   if (attach_first)
208     g_main_context_pop_thread_default (ctx);
209
210   g_assert_cmpint (g_poll (fds, fds_size, 0), >, 0);
211
212   g_main_context_unref (ctx);
213 }
214
215 static gint global_a;
216 static gint global_b;
217 static gint global_c;
218
219 static gboolean
220 count_calls (gpointer data)
221 {
222   gint *i = data;
223
224   (*i)++;
225
226   return TRUE;
227 }
228
229 static void
230 test_timeouts (void)
231 {
232   GMainContext *ctx;
233   GMainLoop *loop;
234   GSource *source;
235
236   if (!g_test_thorough ())
237     {
238       g_test_skip ("Not running timing heavy test");
239       return;
240     }
241
242   global_a = global_b = global_c = 0;
243
244   ctx = g_main_context_new ();
245   loop = g_main_loop_new (ctx, FALSE);
246
247   source = g_timeout_source_new (100);
248   g_source_set_callback (source, count_calls, &global_a, NULL);
249   g_source_attach (source, ctx);
250   g_source_unref (source);
251
252   source = g_timeout_source_new (250);
253   g_source_set_callback (source, count_calls, &global_b, NULL);
254   g_source_attach (source, ctx);
255   g_source_unref (source);
256
257   source = g_timeout_source_new (330);
258   g_source_set_callback (source, count_calls, &global_c, NULL);
259   g_source_attach (source, ctx);
260   g_source_unref (source);
261
262   source = g_timeout_source_new (1050);
263   g_source_set_callback (source, (GSourceFunc)g_main_loop_quit, loop, NULL);
264   g_source_attach (source, ctx);
265   g_source_unref (source);
266
267   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   g_assert_cmpint (global_a, >, 0);
273   g_assert_cmpint (global_a, >=, global_b);
274   g_assert_cmpint (global_b, >=, global_c);
275
276   g_assert_cmpint (global_a, <=, 10);
277   g_assert_cmpint (global_b, <=, 4);
278   g_assert_cmpint (global_c, <=, 3);
279
280   g_main_loop_unref (loop);
281   g_main_context_unref (ctx);
282 }
283
284 static void
285 test_priorities (void)
286 {
287   GMainContext *ctx;
288   GSource *sourcea;
289   GSource *sourceb;
290
291   global_a = global_b = global_c = 0;
292
293   ctx = g_main_context_new ();
294
295   sourcea = g_idle_source_new ();
296   g_source_set_callback (sourcea, count_calls, &global_a, NULL);
297   g_source_set_priority (sourcea, 1);
298   g_source_attach (sourcea, ctx);
299   g_source_unref (sourcea);
300
301   sourceb = g_idle_source_new ();
302   g_source_set_callback (sourceb, count_calls, &global_b, NULL);
303   g_source_set_priority (sourceb, 0);
304   g_source_attach (sourceb, ctx);
305   g_source_unref (sourceb);
306
307   g_assert_true (g_main_context_pending (ctx));
308   g_assert_true (g_main_context_iteration (ctx, FALSE));
309   g_assert_cmpint (global_a, ==, 0);
310   g_assert_cmpint (global_b, ==, 1);
311
312   g_assert_true (g_main_context_iteration (ctx, FALSE));
313   g_assert_cmpint (global_a, ==, 0);
314   g_assert_cmpint (global_b, ==, 2);
315
316   g_source_destroy (sourceb);
317
318   g_assert_true (g_main_context_iteration (ctx, FALSE));
319   g_assert_cmpint (global_a, ==, 1);
320   g_assert_cmpint (global_b, ==, 2);
321
322   g_assert_true (g_main_context_pending (ctx));
323   g_source_destroy (sourcea);
324   g_assert_false (g_main_context_pending (ctx));
325
326   g_main_context_unref (ctx);
327 }
328
329 static gboolean
330 quit_loop (gpointer data)
331 {
332   GMainLoop *loop = data;
333
334   g_main_loop_quit (loop);
335
336   return G_SOURCE_REMOVE;
337 }
338
339 static gint count;
340
341 static gboolean
342 func (gpointer data)
343 {
344   if (data != NULL)
345     g_assert_true (data == g_thread_self ());
346
347   count++;
348
349   return FALSE;
350 }
351
352 static gboolean
353 call_func (gpointer data)
354 {
355   func (g_thread_self ());
356
357   return G_SOURCE_REMOVE;
358 }
359
360 static GMutex mutex;
361 static GCond cond;
362 static gboolean thread_ready;
363
364 static gpointer
365 thread_func (gpointer data)
366 {
367   GMainContext *ctx = data;
368   GMainLoop *loop;
369   GSource *source;
370
371   g_main_context_push_thread_default (ctx);
372   loop = g_main_loop_new (ctx, FALSE);
373
374   g_mutex_lock (&mutex);
375   thread_ready = TRUE;
376   g_cond_signal (&cond);
377   g_mutex_unlock (&mutex);
378
379   source = g_timeout_source_new (500);
380   g_source_set_callback (source, quit_loop, loop, NULL);
381   g_source_attach (source, ctx);
382   g_source_unref (source);
383
384   g_main_loop_run (loop);
385
386   g_main_context_pop_thread_default (ctx);
387   g_main_loop_unref (loop);
388
389   return NULL;
390 }
391
392 static void
393 test_invoke (void)
394 {
395   GMainContext *ctx;
396   GThread *thread;
397
398   count = 0;
399
400   /* this one gets invoked directly */
401   g_main_context_invoke (NULL, func, g_thread_self ());
402   g_assert_cmpint (count, ==, 1);
403
404   /* invoking out of an idle works too */
405   g_idle_add (call_func, NULL);
406   g_main_context_iteration (g_main_context_default (), FALSE);
407   g_assert_cmpint (count, ==, 2);
408
409   /* test thread-default forcing the invocation to go
410    * to another thread
411    */
412   ctx = g_main_context_new ();
413   thread = g_thread_new ("worker", thread_func, ctx);
414
415   g_mutex_lock (&mutex);
416   while (!thread_ready)
417     g_cond_wait (&cond, &mutex);
418   g_mutex_unlock (&mutex);
419
420   g_main_context_invoke (ctx, func, thread);
421
422   g_thread_join (thread);
423   g_assert_cmpint (count, ==, 3);
424
425   g_main_context_unref (ctx);
426 }
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 counter_source_prepare (GSource *source,
445                         gint    *timeout)
446 {
447   CounterSource *csource = (CounterSource *)source;
448   gint64 now;
449
450   now = g_source_get_time (source);
451   if (now != last_counter_update)
452     {
453       last_counter_update = now;
454       counter++;
455     }
456
457   *timeout = 1;
458   return counter >= csource->timeout;
459 }
460
461 static gboolean
462 counter_source_dispatch (GSource    *source,
463                          GSourceFunc callback,
464                          gpointer    user_data)
465 {
466   CounterSource *csource = (CounterSource *) source;
467   gboolean again;
468
469   again = callback (user_data);
470
471   if (again)
472     csource->timeout = counter + csource->interval;
473
474   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 counter_source_new (gint interval)
488 {
489   GSource *source = g_source_new (&counter_source_funcs, sizeof (CounterSource));
490   CounterSource *csource = (CounterSource *) source;
491
492   csource->interval = interval;
493   csource->timeout = counter + interval;
494
495   return source;
496 }
497
498
499 static gboolean
500 run_inner_loop (gpointer user_data)
501 {
502   GMainContext *ctx = user_data;
503   GMainLoop *inner;
504   GSource *timeout;
505
506   global_a++;
507
508   inner = g_main_loop_new (ctx, FALSE);
509   timeout = counter_source_new (100);
510   g_source_set_callback (timeout, quit_loop, inner, NULL);
511   g_source_attach (timeout, ctx);
512   g_source_unref (timeout);
513
514   g_main_loop_run (inner);
515   g_main_loop_unref (inner);
516
517   return G_SOURCE_CONTINUE;
518 }
519
520 static void
521 test_child_sources (void)
522 {
523   GMainContext *ctx;
524   GMainLoop *loop;
525   GSource *parent, *child_b, *child_c, *end;
526
527   ctx = g_main_context_new ();
528   loop = g_main_loop_new (ctx, FALSE);
529
530   global_a = global_b = global_c = 0;
531
532   parent = counter_source_new (2000);
533   g_source_set_callback (parent, run_inner_loop, ctx, NULL);
534   g_source_set_priority (parent, G_PRIORITY_LOW);
535   g_source_attach (parent, ctx);
536
537   child_b = counter_source_new (250);
538   g_source_set_callback (child_b, count_calls, &global_b, NULL);
539   g_source_add_child_source (parent, child_b);
540
541   child_c = counter_source_new (330);
542   g_source_set_callback (child_c, count_calls, &global_c, NULL);
543   g_source_set_priority (child_c, G_PRIORITY_HIGH);
544   g_source_add_child_source (parent, child_c);
545
546   /* Child sources always have the priority of the parent */
547   g_assert_cmpint (g_source_get_priority (parent), ==, G_PRIORITY_LOW);
548   g_assert_cmpint (g_source_get_priority (child_b), ==, G_PRIORITY_LOW);
549   g_assert_cmpint (g_source_get_priority (child_c), ==, G_PRIORITY_LOW);
550   g_source_set_priority (parent, G_PRIORITY_DEFAULT);
551   g_assert_cmpint (g_source_get_priority (parent), ==, G_PRIORITY_DEFAULT);
552   g_assert_cmpint (g_source_get_priority (child_b), ==, G_PRIORITY_DEFAULT);
553   g_assert_cmpint (g_source_get_priority (child_c), ==, G_PRIORITY_DEFAULT);
554
555   end = counter_source_new (1050);
556   g_source_set_callback (end, quit_loop, loop, NULL);
557   g_source_attach (end, ctx);
558   g_source_unref (end);
559
560   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   g_assert_cmpint (global_a, ==, 6);
586   g_assert_cmpint (global_b, ==, 3);
587   g_assert_cmpint (global_c, ==, 3);
588
589   g_source_destroy (parent);
590   g_source_unref (parent);
591   g_source_unref (child_b);
592   g_source_unref (child_c);
593
594   g_main_loop_unref (loop);
595   g_main_context_unref (ctx);
596 }
597
598 static void
599 test_recursive_child_sources (void)
600 {
601   GMainContext *ctx;
602   GMainLoop *loop;
603   GSource *parent, *child_b, *child_c, *end;
604
605   ctx = g_main_context_new ();
606   loop = g_main_loop_new (ctx, FALSE);
607
608   global_a = global_b = global_c = 0;
609
610   parent = counter_source_new (500);
611   g_source_set_callback (parent, count_calls, &global_a, NULL);
612
613   child_b = counter_source_new (220);
614   g_source_set_callback (child_b, count_calls, &global_b, NULL);
615   g_source_add_child_source (parent, child_b);
616
617   child_c = counter_source_new (430);
618   g_source_set_callback (child_c, count_calls, &global_c, NULL);
619   g_source_add_child_source (child_b, child_c);
620
621   g_source_attach (parent, ctx);
622
623   end = counter_source_new (2010);
624   g_source_set_callback (end, (GSourceFunc)g_main_loop_quit, loop, NULL);
625   g_source_attach (end, ctx);
626   g_source_unref (end);
627
628   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   g_assert_cmpint (global_a, ==, 9);
643   g_assert_cmpint (global_b, ==, 9);
644   g_assert_cmpint (global_c, ==, 4);
645
646   g_source_destroy (parent);
647   g_source_unref (parent);
648   g_source_unref (child_b);
649   g_source_unref (child_c);
650
651   g_main_loop_unref (loop);
652   g_main_context_unref (ctx);
653 }
654
655 typedef struct {
656   GSource *parent, *old_child, *new_child;
657   GMainLoop *loop;
658 } SwappingTestData;
659
660 static gboolean
661 swap_sources (gpointer user_data)
662 {
663   SwappingTestData *data = user_data;
664
665   if (data->old_child)
666     {
667       g_source_remove_child_source (data->parent, data->old_child);
668       g_clear_pointer (&data->old_child, g_source_unref);
669     }
670
671   if (!data->new_child)
672     {
673       data->new_child = g_timeout_source_new (0);
674       g_source_set_callback (data->new_child, quit_loop, data->loop, NULL);
675       g_source_add_child_source (data->parent, data->new_child);
676     }
677
678   return G_SOURCE_CONTINUE;
679 }
680
681 static gboolean
682 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 test_swapping_child_sources (void)
691 {
692   GMainContext *ctx;
693   GMainLoop *loop;
694   SwappingTestData data;
695
696   ctx = g_main_context_new ();
697   loop = g_main_loop_new (ctx, FALSE);
698
699   data.parent = counter_source_new (50);
700   data.loop = loop;
701   g_source_set_callback (data.parent, swap_sources, &data, NULL);
702   g_source_attach (data.parent, ctx);
703
704   data.old_child = counter_source_new (100);
705   g_source_add_child_source (data.parent, data.old_child);
706   g_source_set_callback (data.old_child, assert_not_reached_callback, NULL, NULL);
707
708   data.new_child = NULL;
709   g_main_loop_run (loop);
710
711   g_source_destroy (data.parent);
712   g_source_unref (data.parent);
713   g_source_unref (data.new_child);
714
715   g_main_loop_unref (loop);
716   g_main_context_unref (ctx);
717 }
718
719 static gboolean
720 add_source_callback (gpointer user_data)
721 {
722   GMainLoop *loop = user_data;
723   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   io = g_io_channel_unix_new (0);
731   child = g_io_create_watch (io, G_IO_IN);
732   g_source_add_child_source (self, child);
733   g_source_unref (child);
734   g_io_channel_unref (io);
735
736   g_main_loop_quit (loop);
737   return FALSE;
738 }
739
740 static void
741 test_blocked_child_sources (void)
742 {
743   GMainContext *ctx;
744   GMainLoop *loop;
745   GSource *source;
746
747   g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=701283");
748
749   ctx = g_main_context_new ();
750   loop = g_main_loop_new (ctx, FALSE);
751
752   source = g_idle_source_new ();
753   g_source_set_callback (source, add_source_callback, loop, NULL);
754   g_source_attach (source, ctx);
755
756   g_main_loop_run (loop);
757
758   g_source_destroy (source);
759   g_source_unref (source);
760
761   g_main_loop_unref (loop);
762   g_main_context_unref (ctx);
763 }
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 timeout1_callback (gpointer user_data)
778 {
779   TimeTestData *data = user_data;
780   GSource *source;
781   gint64 mtime1, mtime2, time2;
782
783   source = g_main_current_source ();
784   g_assert_true (source == data->timeout1);
785
786   if (data->time1 == -1)
787     {
788       /* First iteration */
789       g_assert_false (g_source_is_destroyed (data->timeout2));
790
791       mtime1 = g_get_monotonic_time ();
792       data->time1 = g_source_get_time (source);
793
794 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
795       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       g_usleep (1000000);
800       mtime2 = g_get_monotonic_time ();
801       time2 = g_source_get_time (source);
802
803       g_assert_cmpint (mtime1, <, mtime2);
804       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       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       time2 = g_source_get_time (source);
820       g_assert_cmpint (data->time1, <, time2);
821
822 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
823       g_source_get_current_time (source, &tv);
824 G_GNUC_END_IGNORE_DEPRECATIONS
825
826       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       g_main_loop_quit (data->loop);
831     }
832
833   return TRUE;
834 }
835
836 static gboolean
837 timeout2_callback (gpointer user_data)
838 {
839   TimeTestData *data = user_data;
840   GSource *source;
841   gint64 time2, time3;
842
843   source = g_main_current_source ();
844   g_assert_true (source == data->timeout2);
845
846   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   time2 = g_source_get_time (source);
852   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   g_source_destroy (source);
858   time3 = g_source_get_time (source);
859   g_assert_cmpint (time2, ==, time3);
860
861   return FALSE;
862 }
863
864 static void
865 test_source_time (void)
866 {
867   TimeTestData data;
868
869   data.ctx = g_main_context_new ();
870   data.loop = g_main_loop_new (data.ctx, FALSE);
871
872   data.timeout1 = g_timeout_source_new (0);
873   g_source_set_callback (data.timeout1, timeout1_callback, &data, NULL);
874   g_source_attach (data.timeout1, data.ctx);
875
876   data.timeout2 = g_timeout_source_new (0);
877   g_source_set_callback (data.timeout2, timeout2_callback, &data, NULL);
878   g_source_attach (data.timeout2, data.ctx);
879
880   data.time1 = -1;
881
882   g_main_loop_run (data.loop);
883
884   g_assert_false (g_source_is_destroyed (data.timeout1));
885   g_assert_true (g_source_is_destroyed (data.timeout2));
886
887   g_source_destroy (data.timeout1);
888   g_source_unref (data.timeout1);
889   g_source_unref (data.timeout2);
890
891   g_main_loop_unref (data.loop);
892   g_main_context_unref (data.ctx);
893 }
894
895 typedef struct {
896   guint outstanding_ops;
897   GMainLoop *loop;
898 } TestOverflowData;
899
900 static gboolean
901 on_source_fired_cb (gpointer user_data)
902 {
903   TestOverflowData *data = user_data;
904   GSource *current_source;
905   GMainContext *current_context;
906   guint source_id;
907
908   data->outstanding_ops--;
909
910   current_source = g_main_current_source ();
911   current_context = g_source_get_context (current_source);
912   source_id = g_source_get_id (current_source);
913   g_assert_nonnull (g_main_context_find_source_by_id (current_context, source_id));
914   g_source_destroy (current_source);
915   g_assert_null (g_main_context_find_source_by_id (current_context, source_id));
916
917   if (data->outstanding_ops == 0)
918     g_main_loop_quit (data->loop);
919   return FALSE;
920 }
921
922 static GSource *
923 add_idle_source (GMainContext *ctx,
924                  TestOverflowData *data)
925 {
926   GSource *source;
927
928   source = g_idle_source_new ();
929   g_source_set_callback (source, on_source_fired_cb, data, NULL);
930   g_source_attach (source, ctx);
931   g_source_unref (source);
932   data->outstanding_ops++;
933
934   return source;
935 }
936
937 static void
938 test_mainloop_overflow (void)
939 {
940   GMainContext *ctx;
941   GMainLoop *loop;
942   GSource *source;
943   TestOverflowData data;
944   guint i;
945
946   g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=687098");
947
948   memset (&data, 0, sizeof (data));
949
950   ctx = GLIB_PRIVATE_CALL (g_main_context_new_with_next_id) (G_MAXUINT-1);
951
952   loop = g_main_loop_new (ctx, TRUE);
953   data.outstanding_ops = 0;
954   data.loop = loop;
955
956   source = add_idle_source (ctx, &data);
957   g_assert_cmpint (source->source_id, ==, G_MAXUINT-1);
958
959   source = add_idle_source (ctx, &data);
960   g_assert_cmpint (source->source_id, ==, G_MAXUINT);
961
962   source = add_idle_source (ctx, &data);
963   g_assert_cmpint (source->source_id, !=, 0);
964
965   /* Now, a lot more sources */
966   for (i = 0; i < 50; i++)
967     {
968       source = add_idle_source (ctx, &data);
969       g_assert_cmpint (source->source_id, !=, 0);
970     }
971
972   g_main_loop_run (loop);
973   g_assert_cmpint (data.outstanding_ops, ==, 0);
974
975   g_main_loop_unref (loop);
976   g_main_context_unref (ctx);
977 }
978
979 static gint ready_time_dispatched;  /* (atomic) */
980
981 static gboolean
982 ready_time_dispatch (GSource     *source,
983                      GSourceFunc  callback,
984                      gpointer     user_data)
985 {
986   g_atomic_int_set (&ready_time_dispatched, TRUE);
987
988   g_source_set_ready_time (source, -1);
989
990   return TRUE;
991 }
992
993 static gpointer
994 run_context (gpointer user_data)
995 {
996   g_main_loop_run (user_data);
997
998   return NULL;
999 }
1000
1001 static void
1002 test_ready_time (void)
1003 {
1004   GThread *thread;
1005   GSource *source;
1006   GSourceFuncs source_funcs = {
1007     NULL, NULL, ready_time_dispatch, NULL, NULL, NULL
1008   };
1009   GMainLoop *loop;
1010
1011   source = g_source_new (&source_funcs, sizeof (GSource));
1012   g_source_attach (source, NULL);
1013   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   g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
1024   while (g_main_context_iteration (NULL, FALSE));
1025   g_assert_false (g_atomic_int_get (&ready_time_dispatched));
1026
1027   /* The ready time should not have been changed */
1028   g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
1029
1030   /* Of course this shouldn't change anything either */
1031   g_source_set_ready_time (source, -1);
1032   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   g_source_set_ready_time (source, g_get_monotonic_time () + G_TIME_SPAN_DAY);
1038   while (g_main_context_iteration (NULL, FALSE));
1039   g_assert_false (g_atomic_int_get (&ready_time_dispatched));
1040   /* Make sure it didn't get reset */
1041   g_assert_cmpint (g_source_get_ready_time (source), !=, -1);
1042
1043   /* Ready time of -1 -> don't fire */
1044   g_source_set_ready_time (source, -1);
1045   while (g_main_context_iteration (NULL, FALSE));
1046   g_assert_false (g_atomic_int_get (&ready_time_dispatched));
1047   /* Not reset, but should still be -1 from above */
1048   g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
1049
1050   /* A ready time of the current time should fire immediately */
1051   g_source_set_ready_time (source, g_get_monotonic_time ());
1052   while (g_main_context_iteration (NULL, FALSE));
1053   g_assert_true (g_atomic_int_get (&ready_time_dispatched));
1054   g_atomic_int_set (&ready_time_dispatched, FALSE);
1055   /* Should have gotten reset by the handler function */
1056   g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
1057
1058   /* As well as one in the recent past... */
1059   g_source_set_ready_time (source, g_get_monotonic_time () - G_TIME_SPAN_SECOND);
1060   while (g_main_context_iteration (NULL, FALSE));
1061   g_assert_true (g_atomic_int_get (&ready_time_dispatched));
1062   g_atomic_int_set (&ready_time_dispatched, FALSE);
1063   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   g_source_set_ready_time (source, 0);
1067   while (g_main_context_iteration (NULL, FALSE));
1068   g_assert_true (g_atomic_int_get (&ready_time_dispatched));
1069   g_atomic_int_set (&ready_time_dispatched, FALSE);
1070   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   g_source_set_ready_time (source, 0);
1077   loop = g_main_loop_new (NULL, FALSE);
1078   thread = g_thread_new ("context thread", run_context, loop);
1079   while (!g_atomic_int_get (&ready_time_dispatched));
1080
1081   /* Now let's see if it can wake up from sleeping. */
1082   g_usleep (G_TIME_SPAN_SECOND / 2);
1083   g_atomic_int_set (&ready_time_dispatched, FALSE);
1084   g_source_set_ready_time (source, 0);
1085   while (!g_atomic_int_get (&ready_time_dispatched));
1086
1087   /* kill the thread */
1088   g_main_loop_quit (loop);
1089   g_thread_join (thread);
1090   g_main_loop_unref (loop);
1091
1092   g_source_destroy (source);
1093 }
1094
1095 static void
1096 test_wakeup(void)
1097 {
1098   GMainContext *ctx;
1099   int i;
1100
1101   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   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       g_main_context_wakeup (ctx);
1117       g_main_context_iteration (ctx, TRUE);
1118     }
1119
1120   g_main_context_unref (ctx);
1121 }
1122
1123 static void
1124 test_remove_invalid (void)
1125 {
1126   g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "Source ID 3000000000 was not found*");
1127   g_source_remove (3000000000u);
1128   g_test_assert_expected_messages ();
1129 }
1130
1131 static gboolean
1132 trivial_prepare (GSource *source,
1133                  gint    *timeout)
1134 {
1135   *timeout = 0;
1136   return TRUE;
1137 }
1138
1139 static gint n_finalized;
1140
1141 static void
1142 trivial_finalize (GSource *source)
1143 {
1144   n_finalized++;
1145 }
1146
1147 static void
1148 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   context = g_main_context_new ();
1157
1158   source = g_source_new (&funcs, sizeof (GSource));
1159   g_source_attach (source, context);
1160   g_source_unref (source);
1161
1162   /* Do incomplete main iteration -- get a pending source but don't dispatch it. */
1163   g_main_context_prepare (context, NULL);
1164   g_main_context_query (context, 0, NULL, NULL, 0);
1165   g_main_context_check (context, 1000, NULL, 0);
1166
1167   /* Destroy the context */
1168   g_main_context_unref (context);
1169
1170   /* Make sure we didn't leak the source */
1171   g_assert_cmpint (n_finalized, ==, 1);
1172 }
1173
1174 typedef struct {
1175   GSource parent;
1176   GMainLoop *loop;
1177 } LoopedSource;
1178
1179 static gboolean
1180 prepare_loop_run (GSource *source, gint *time)
1181 {
1182   LoopedSource *looped_source = (LoopedSource*) source;
1183   *time = 0;
1184
1185   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   g_main_loop_run (looped_source->loop);
1189   g_test_assert_expected_messages ();
1190
1191   return FALSE;
1192 }
1193
1194 static gboolean
1195 check_loop_run (GSource *source)
1196 {
1197   LoopedSource *looped_source = (LoopedSource*) source;
1198
1199   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   g_main_loop_run (looped_source->loop);
1203   g_test_assert_expected_messages ();
1204
1205   return TRUE;
1206 }
1207
1208 static gboolean
1209 dispatch_loop_run (GSource    *source,
1210                    GSourceFunc callback,
1211                    gpointer    user_data)
1212 {
1213   LoopedSource *looped_source = (LoopedSource*) source;
1214
1215   g_main_loop_quit (looped_source->loop);
1216
1217   return FALSE;
1218 }
1219
1220 static void
1221 test_recursive_loop_child_sources (void)
1222 {
1223   GMainLoop *loop;
1224   GSource *source;
1225   GSourceFuncs loop_run_funcs = {
1226     prepare_loop_run, check_loop_run, dispatch_loop_run, NULL, NULL, NULL,
1227   };
1228
1229   loop = g_main_loop_new (NULL, FALSE);
1230
1231   source = g_source_new (&loop_run_funcs, sizeof (LoopedSource));
1232   ((LoopedSource*)source)->loop = loop;
1233
1234   g_source_attach (source, NULL);
1235
1236   g_main_loop_run (loop);
1237   g_source_unref (source);
1238
1239   g_main_loop_unref (loop);
1240 }
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 fill_a_pipe (gint fd)
1252 {
1253   gsize written = 0;
1254   GPollFD pfd;
1255
1256   pfd.fd = fd;
1257   pfd.events = G_IO_OUT;
1258   while (g_poll (&pfd, 1, 0) == 1)
1259     /* we should never see -1 here */
1260     written += write (fd, zeros, sizeof zeros);
1261
1262   return written;
1263 }
1264
1265 static gboolean
1266 write_bytes (gint         fd,
1267              GIOCondition condition,
1268              gpointer     user_data)
1269 {
1270   gssize *to_write = user_data;
1271   gint limit;
1272
1273   if (*to_write == 0)
1274     return FALSE;
1275
1276   /* Detect if we run before we should */
1277   g_assert_cmpint (*to_write, >=, 0);
1278
1279   limit = MIN ((gsize) *to_write, sizeof zeros);
1280   *to_write -= write (fd, zeros, limit);
1281
1282   return TRUE;
1283 }
1284
1285 static gboolean
1286 read_bytes (gint         fd,
1287             GIOCondition condition,
1288             gpointer     user_data)
1289 {
1290   static gchar buffer[1024];
1291   gssize *to_read = user_data;
1292
1293   *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   return TRUE;
1299 }
1300
1301 #ifdef G_OS_UNIX
1302 static void
1303 test_unix_fd (void)
1304 {
1305   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   s = pipe (fds);
1314   g_assert_cmpint (s, ==, 0);
1315
1316   to_read = fill_a_pipe (fds[1]);
1317   /* write at higher priority to keep the pipe full... */
1318   a = g_unix_fd_add_full (G_PRIORITY_HIGH, fds[1], G_IO_OUT, write_bytes, &to_write, NULL);
1319   source_a = g_source_ref (g_main_context_find_source_by_id (NULL, a));
1320   /* make sure no 'writes' get dispatched yet */
1321   while (g_main_context_iteration (NULL, FALSE));
1322
1323   to_read += 128 * 1024 * 1024;
1324   to_write = 128 * 1024 * 1024;
1325   b = g_unix_fd_add (fds[0], G_IO_IN, read_bytes, &to_read);
1326   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     {
1334       gssize to_write_was = to_write;
1335       gssize to_read_was = to_read;
1336
1337       if (!g_main_context_iteration (NULL, FALSE))
1338         break;
1339
1340       /* Since the sources are at different priority, only one of them
1341        * should possibly have run.
1342        */
1343       g_assert_true (to_write == to_write_was || to_read == to_read_was);
1344     }
1345
1346   g_assert_cmpint (to_write, ==, 0);
1347   g_assert_cmpint (to_read, ==, 0);
1348
1349   /* 'a' is already removed by itself */
1350   g_assert_true (g_source_is_destroyed (source_a));
1351   g_source_unref (source_a);
1352   g_source_remove (b);
1353   g_assert_true (g_source_is_destroyed (source_b));
1354   g_source_unref (source_b);
1355   close (fds[1]);
1356   close (fds[0]);
1357 }
1358 #endif
1359
1360 static void
1361 assert_main_context_state (gint n_to_poll,
1362                            ...)
1363 {
1364   GMainContext *context;
1365   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   context = g_main_context_default ();
1376
1377   acquired = g_main_context_acquire (context);
1378   g_assert_true (acquired);
1379
1380   immediate = g_main_context_prepare (context, &max_priority);
1381   g_assert_false (immediate);
1382   n = g_main_context_query (context, max_priority, &timeout, poll_fds, 10);
1383   g_assert_cmpint (n, ==, n_to_poll + 1); /* one will be the gwakeup */
1384
1385   va_start (ap, n_to_poll);
1386   for (i = 0; i < n_to_poll; i++)
1387     {
1388       gint expected_fd = va_arg (ap, gint);
1389       GIOCondition expected_events = va_arg (ap, GIOCondition);
1390       GIOCondition report_events = va_arg (ap, GIOCondition);
1391
1392       for (j = 0; j < n; j++)
1393         if (!consumed[j] && poll_fds[j].fd == expected_fd && poll_fds[j].events == expected_events)
1394           {
1395             poll_fds[j].revents = report_events;
1396             consumed[j] = TRUE;
1397             break;
1398           }
1399
1400       if (j == n)
1401         g_error ("Unable to find fd %d (index %d) with events 0x%x", expected_fd, i, (guint) expected_events);
1402     }
1403   va_end (ap);
1404
1405   /* find the gwakeup, flag as non-ready */
1406   for (i = 0; i < n; i++)
1407     if (!consumed[i])
1408       poll_fds[i].revents = 0;
1409
1410   if (g_main_context_check (context, max_priority, poll_fds, n))
1411     g_main_context_dispatch (context);
1412
1413   g_main_context_release (context);
1414 }
1415
1416 static gboolean
1417 flag_bool (gint         fd,
1418            GIOCondition condition,
1419            gpointer     user_data)
1420 {
1421   gboolean *flag = user_data;
1422
1423   *flag = TRUE;
1424
1425   return TRUE;
1426 }
1427
1428 static void
1429 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   assert_main_context_state (0);
1439
1440   s = pipe (fds);
1441   g_assert_cmpint (s, ==, 0);
1442
1443   source = g_unix_fd_source_new (fds[1], G_IO_OUT);
1444   g_source_attach (source, NULL);
1445
1446   /* Check that a source with no callback gets successfully detached
1447    * with a warning printed.
1448    */
1449   g_test_expect_message ("GLib", G_LOG_LEVEL_WARNING, "*GUnixFDSource dispatched without callback*");
1450   while (g_main_context_iteration (NULL, FALSE));
1451   g_test_assert_expected_messages ();
1452   g_assert_true (g_source_is_destroyed (source));
1453   g_source_unref (source);
1454
1455   out = in = FALSE;
1456   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   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   g_source_attach (out_source, NULL);
1473   assert_main_context_state (1,
1474                              fds[1], G_IO_OUT, 0);
1475   g_assert_true (!in && !out);
1476
1477   in_source = g_unix_fd_source_new (fds[0], G_IO_IN);
1478   g_source_set_callback (in_source, (GSourceFunc) flag_bool, &in, NULL);
1479   g_source_set_priority (in_source, G_PRIORITY_DEFAULT_IDLE);
1480   g_source_attach (in_source, NULL);
1481   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   g_assert_true (!in && out);
1486
1487   /* raise the priority of the in source to higher than out*/
1488   in = out = FALSE;
1489   g_source_set_priority (in_source, G_PRIORITY_HIGH);
1490   assert_main_context_state (2,
1491                              fds[0], G_IO_IN, G_IO_IN,
1492                              fds[1], G_IO_OUT, G_IO_OUT);
1493   g_assert_true (in && !out);
1494
1495   /* now, let them be equal */
1496   in = out = FALSE;
1497   g_source_set_priority (in_source, G_PRIORITY_DEFAULT);
1498   assert_main_context_state (2,
1499                              fds[0], G_IO_IN, G_IO_IN,
1500                              fds[1], G_IO_OUT, G_IO_OUT);
1501   g_assert_true (in && out);
1502
1503   g_source_destroy (out_source);
1504   g_source_unref (out_source);
1505   g_source_destroy (in_source);
1506   g_source_unref (in_source);
1507   close (fds[1]);
1508   close (fds[0]);
1509 }
1510
1511 typedef struct
1512 {
1513   GSource parent;
1514   gboolean flagged;
1515 } FlagSource;
1516
1517 static gboolean
1518 return_true (GSource *source, GSourceFunc callback, gpointer user_data)
1519 {
1520   FlagSource *flag_source = (FlagSource *) source;
1521
1522   flag_source->flagged = TRUE;
1523
1524   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 test_source_unix_fd_api (void)
1533 {
1534   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   g_assert_cmpint (pipe (fds_a), ==, 0);
1544   g_assert_cmpint (pipe (fds_b), ==, 0);
1545
1546   source_a = g_source_new (&no_funcs, sizeof (FlagSource));
1547   source_b = g_source_new (&no_funcs, sizeof (FlagSource));
1548
1549   /* attach a source with more than one fd */
1550   g_source_add_unix_fd (source_a, fds_a[0], G_IO_IN);
1551   g_source_add_unix_fd (source_a, fds_a[1], G_IO_OUT);
1552   g_source_attach (source_a, NULL);
1553   assert_main_context_state (2,
1554                              fds_a[0], G_IO_IN, 0,
1555                              fds_a[1], G_IO_OUT, 0);
1556   assert_not_flagged (source_a);
1557
1558   /* attach a higher priority source with no fds */
1559   g_source_set_priority (source_b, G_PRIORITY_HIGH);
1560   g_source_attach (source_b, NULL);
1561   assert_main_context_state (2,
1562                              fds_a[0], G_IO_IN, G_IO_IN,
1563                              fds_a[1], G_IO_OUT, 0);
1564   assert_flagged (source_a);
1565   assert_not_flagged (source_b);
1566   clear_flag (source_a);
1567
1568   /* add some fds to the second source, while attached */
1569   tag1 = g_source_add_unix_fd (source_b, fds_b[0], G_IO_IN);
1570   tag2 = g_source_add_unix_fd (source_b, fds_b[1], G_IO_OUT);
1571   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   assert_not_flagged (source_a);
1578   assert_flagged (source_b);
1579   clear_flag (source_b);
1580
1581   /* change our events on b to the same as they were before */
1582   g_source_modify_unix_fd (source_b, tag1, G_IO_IN);
1583   g_source_modify_unix_fd (source_b, tag2, G_IO_OUT);
1584   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   assert_not_flagged (source_a);
1590   assert_flagged (source_b);
1591   clear_flag (source_b);
1592
1593   /* now reverse them */
1594   g_source_modify_unix_fd (source_b, tag1, G_IO_OUT);
1595   g_source_modify_unix_fd (source_b, tag2, G_IO_IN);
1596   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   assert_flagged (source_a);
1603   assert_not_flagged (source_b);
1604   clear_flag (source_a);
1605
1606   /* remove one of the fds from 'b' */
1607   g_source_remove_unix_fd (source_b, tag1);
1608   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   assert_not_flagged (source_a);
1613   assert_not_flagged (source_b);
1614
1615   /* remove the other */
1616   g_source_remove_unix_fd (source_b, tag2);
1617   assert_main_context_state (2,
1618                              fds_a[0], G_IO_IN, 0,
1619                              fds_a[1], G_IO_OUT, 0);
1620   assert_not_flagged (source_a);
1621   assert_not_flagged (source_b);
1622
1623   /* destroy the sources */
1624   g_source_destroy (source_a);
1625   g_source_destroy (source_b);
1626   assert_main_context_state (0);
1627
1628   g_source_unref (source_a);
1629   g_source_unref (source_b);
1630   close (fds_a[0]);
1631   close (fds_a[1]);
1632   close (fds_b[0]);
1633   close (fds_b[1]);
1634 }
1635
1636 static gboolean
1637 unixfd_quit_loop (gint         fd,
1638                   GIOCondition condition,
1639                   gpointer     user_data)
1640 {
1641   GMainLoop *loop = user_data;
1642
1643   g_main_loop_quit (loop);
1644
1645   return FALSE;
1646 }
1647
1648 static void
1649 test_unix_file_poll (void)
1650 {
1651   gint fd;
1652   GSource *source;
1653   GMainLoop *loop;
1654
1655   fd = open ("/dev/null", O_RDONLY);
1656   g_assert_cmpint (fd, >=, 0);
1657
1658   loop = g_main_loop_new (NULL, FALSE);
1659
1660   source = g_unix_fd_source_new (fd, G_IO_IN);
1661   g_source_set_callback (source, (GSourceFunc) unixfd_quit_loop, loop, NULL);
1662   g_source_attach (source, NULL);
1663
1664   /* Should not block */
1665   g_main_loop_run (loop);
1666
1667   g_source_destroy (source);
1668
1669   assert_main_context_state (0);
1670
1671   g_source_unref (source);
1672
1673   g_main_loop_unref (loop);
1674
1675   close (fd);
1676 }
1677
1678 static void
1679 test_unix_fd_priority (void)
1680 {
1681   gint fd1, fd2;
1682   GMainLoop *loop;
1683   GSource *source;
1684
1685   gint s1 = 0;
1686   gboolean s2 = FALSE, s3 = FALSE;
1687
1688   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/1592");
1689
1690   loop = g_main_loop_new (NULL, FALSE);
1691
1692   source = g_idle_source_new ();
1693   g_source_set_callback (source, count_calls, &s1, NULL);
1694   g_source_set_priority (source, 0);
1695   g_source_attach (source, NULL);
1696   g_source_unref (source);
1697
1698   fd1 = open ("/dev/random", O_RDONLY);
1699   g_assert_cmpint (fd1, >=, 0);
1700   source = g_unix_fd_source_new (fd1, G_IO_IN);
1701   g_source_set_callback (source, G_SOURCE_FUNC (flag_bool), &s2, NULL);
1702   g_source_set_priority (source, 10);
1703   g_source_attach (source, NULL);
1704   g_source_unref (source);
1705
1706   fd2 = open ("/dev/random", O_RDONLY);
1707   g_assert_cmpint (fd2, >=, 0);
1708   source = g_unix_fd_source_new (fd2, G_IO_IN);
1709   g_source_set_callback (source, G_SOURCE_FUNC (flag_bool), &s3, NULL);
1710   g_source_set_priority (source, 0);
1711   g_source_attach (source, NULL);
1712   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   g_assert_cmpint (fd1, <, fd2);
1718
1719   g_assert_true (g_main_context_iteration (NULL, FALSE));
1720
1721   /* Idle source should have been dispatched. */
1722   g_assert_cmpint (s1, ==, 1);
1723   /* Low priority FD source shouldn't have been dispatched. */
1724   g_assert_false (s2);
1725   /* Default priority FD source should have been dispatched. */
1726   g_assert_true (s3);
1727
1728   g_main_loop_unref (loop);
1729
1730   close (fd1);
1731   close (fd2);
1732 }
1733
1734 #endif
1735
1736 #ifdef G_OS_UNIX
1737 static gboolean
1738 timeout_cb (gpointer data)
1739 {
1740   GMainLoop *loop = data;
1741   GMainContext *context;
1742
1743   context = g_main_loop_get_context (loop);
1744   g_assert_true (g_main_loop_is_running (loop));
1745   g_assert_true (g_main_context_is_owner (context));
1746
1747   g_main_loop_quit (loop);
1748
1749   return G_SOURCE_REMOVE;
1750 }
1751
1752 static gpointer
1753 threadf (gpointer data)
1754 {
1755   GMainContext *context = data;
1756   GMainLoop *loop;
1757   GSource *source;
1758
1759   loop = g_main_loop_new (context, FALSE);
1760   source = g_timeout_source_new (250);
1761   g_source_set_callback (source, timeout_cb, loop, NULL);
1762   g_source_attach (source, context);
1763  
1764   g_main_loop_run (loop);
1765
1766   g_source_destroy (source);
1767   g_source_unref (source);
1768   g_main_loop_unref (loop);
1769
1770   return NULL;
1771 }
1772
1773 static void
1774 test_mainloop_wait (void)
1775 {
1776   GMainContext *context;
1777   GThread *t1, *t2;
1778
1779   context = g_main_context_new ();
1780
1781   t1 = g_thread_new ("t1", threadf, context);
1782   t2 = g_thread_new ("t2", threadf, context);
1783
1784   g_thread_join (t1);
1785   g_thread_join (t2);
1786
1787   g_main_context_unref (context);
1788 }
1789 #endif
1790
1791 static gboolean
1792 nfds_in_cb (GIOChannel   *io,
1793             GIOCondition  condition,
1794             gpointer      user_data)
1795 {
1796   gboolean *in_cb_ran = user_data;
1797
1798   *in_cb_ran = TRUE;
1799   g_assert_cmpint (condition, ==, G_IO_IN);
1800   return FALSE;
1801 }
1802
1803 static gboolean
1804 nfds_out_cb (GIOChannel   *io,
1805              GIOCondition  condition,
1806              gpointer      user_data)
1807 {
1808   gboolean *out_cb_ran = user_data;
1809
1810   *out_cb_ran = TRUE;
1811   g_assert_cmpint (condition, ==, G_IO_OUT);
1812   return FALSE;
1813 }
1814
1815 static gboolean
1816 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 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   gboolean source1_ran = FALSE, source3_ran = FALSE;
1833   gchar *tmpfile;
1834   GError *error = NULL;
1835
1836   ctx = g_main_context_new ();
1837   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   g_assert_cmpint (nfds, ==, 1);
1843
1844   fd = g_file_open_tmp (NULL, &tmpfile, &error);
1845   g_assert_no_error (error);
1846
1847   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   source1 = g_io_create_watch (io, G_IO_IN);
1856   g_source_set_priority (source1, G_PRIORITY_DEFAULT);
1857   g_source_set_callback (source1, (GSourceFunc) nfds_in_cb,
1858                          &source1_ran, NULL);
1859   g_source_attach (source1, ctx);
1860
1861   nfds = g_main_context_query (ctx, G_MAXINT, NULL,
1862                                out_fds, G_N_ELEMENTS (out_fds));
1863   g_assert_cmpint (nfds, ==, 2);
1864   if (out_fds[0].fd == fd)
1865     g_assert_cmpint (out_fds[0].events, ==, G_IO_IN);
1866   else if (out_fds[1].fd == fd)
1867     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   source2 = g_io_create_watch (io, G_IO_OUT);
1875   g_source_set_priority (source2, G_PRIORITY_LOW);
1876   g_source_set_callback (source2, (GSourceFunc) nfds_out_low_cb,
1877                          NULL, NULL);
1878   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   nfds = g_main_context_query (ctx, G_MAXINT, NULL,
1884                                out_fds, G_N_ELEMENTS (out_fds));
1885   g_assert_cmpint (nfds, ==, 2);
1886   if (out_fds[0].fd == fd)
1887     g_assert_cmpint (out_fds[0].events, ==, G_IO_IN | G_IO_OUT);
1888   else if (out_fds[1].fd == fd)
1889     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   nfds = g_main_context_query (ctx, G_PRIORITY_DEFAULT, NULL,
1897                                out_fds, G_N_ELEMENTS (out_fds));
1898   g_assert_cmpint (nfds, ==, 2);
1899   if (out_fds[0].fd == fd)
1900     g_assert_cmpint (out_fds[0].events, ==, G_IO_IN);
1901   else if (out_fds[1].fd == fd)
1902     g_assert_cmpint (out_fds[1].events, ==, G_IO_IN);
1903   else
1904     g_assert_not_reached ();
1905
1906   /* Third pollfd */
1907   source3 = g_io_create_watch (io, G_IO_OUT);
1908   g_source_set_priority (source3, G_PRIORITY_DEFAULT);
1909   g_source_set_callback (source3, (GSourceFunc) nfds_out_cb,
1910                          &source3_ran, NULL);
1911   g_source_attach (source3, ctx);
1912
1913   nfds = g_main_context_query (ctx, G_MAXINT, NULL,
1914                                out_fds, G_N_ELEMENTS (out_fds));
1915   g_assert_cmpint (nfds, ==, 2);
1916   if (out_fds[0].fd == fd)
1917     g_assert_cmpint (out_fds[0].events, ==, G_IO_IN | G_IO_OUT);
1918   else if (out_fds[1].fd == fd)
1919     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   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   g_assert_true (source1_ran);
1936   g_assert_true (source3_ran);
1937 #endif
1938
1939   g_source_destroy (source1);
1940   g_source_unref (source1);
1941   g_source_destroy (source2);
1942   g_source_unref (source2);
1943   g_source_destroy (source3);
1944   g_source_unref (source3);
1945
1946   g_io_channel_unref (io);
1947   remove (tmpfile);
1948   g_free (tmpfile);
1949
1950   g_main_context_unref (ctx);
1951 }
1952
1953 static gboolean
1954 nsources_cb (gpointer user_data)
1955 {
1956   g_assert_not_reached ();
1957   return FALSE;
1958 }
1959
1960 static void
1961 shuffle_nsources (GSource **sources, int num)
1962 {
1963   int i, a, b;
1964   GSource *tmp;
1965
1966   for (i = 0; i < num * 10; i++)
1967     {
1968       a = g_random_int_range (0, num);
1969       b = g_random_int_range (0, num);
1970       tmp = sources[a];
1971       sources[a] = sources[b];
1972       sources[b] = tmp;
1973     }
1974 }
1975
1976 static void
1977 test_nsources_same_priority (void)
1978 {
1979   GMainContext *context;
1980   GSource **sources;
1981   gint64 start, end;
1982   gsize n_sources = 50000, i;
1983
1984   context = g_main_context_default ();
1985   sources = g_new0 (GSource *, n_sources);
1986
1987   start = g_get_monotonic_time ();
1988   for (i = 0; i < n_sources; i++)
1989     {
1990       sources[i] = g_idle_source_new ();
1991       g_source_set_callback (sources[i], nsources_cb, NULL, NULL);
1992       g_source_attach (sources[i], context);
1993     }
1994   end = g_get_monotonic_time ();
1995   g_test_message ("Add same-priority sources: %" G_GINT64_FORMAT,
1996                   (end - start) / 1000);
1997
1998   start = g_get_monotonic_time ();
1999   for (i = 0; i < n_sources; i++)
2000     g_assert_true (sources[i] == g_main_context_find_source_by_id (context, g_source_get_id (sources[i])));
2001   end = g_get_monotonic_time ();
2002   g_test_message ("Find each source: %" G_GINT64_FORMAT,
2003                   (end - start) / 1000);
2004
2005   shuffle_nsources (sources, n_sources);
2006
2007   start = g_get_monotonic_time ();
2008   for (i = 0; i < n_sources; i++)
2009     {
2010       g_source_destroy (sources[i]);
2011       g_source_unref (sources[i]);
2012     }
2013   end = g_get_monotonic_time ();
2014   g_test_message ("Remove in random order: %" G_GINT64_FORMAT,
2015                   (end - start) / 1000);
2016
2017   /* Make sure they really did get removed */
2018   g_main_context_iteration (context, FALSE);
2019
2020   g_free (sources);
2021 }
2022
2023 static void
2024 test_nsources_different_priority (void)
2025 {
2026   GMainContext *context;
2027   GSource **sources;
2028   gint64 start, end;
2029   gsize n_sources = 50000, i;
2030
2031   context = g_main_context_default ();
2032   sources = g_new0 (GSource *, n_sources);
2033
2034   start = g_get_monotonic_time ();
2035   for (i = 0; i < n_sources; i++)
2036     {
2037       sources[i] = g_idle_source_new ();
2038       g_source_set_callback (sources[i], nsources_cb, NULL, NULL);
2039       g_source_set_priority (sources[i], i % 100);
2040       g_source_attach (sources[i], context);
2041     }
2042   end = g_get_monotonic_time ();
2043   g_test_message ("Add different-priority sources: %" G_GINT64_FORMAT,
2044                   (end - start) / 1000);
2045
2046   start = g_get_monotonic_time ();
2047   for (i = 0; i < n_sources; i++)
2048     g_assert_true (sources[i] == g_main_context_find_source_by_id (context, g_source_get_id (sources[i])));
2049   end = g_get_monotonic_time ();
2050   g_test_message ("Find each source: %" G_GINT64_FORMAT,
2051                   (end - start) / 1000);
2052
2053   shuffle_nsources (sources, n_sources);
2054
2055   start = g_get_monotonic_time ();
2056   for (i = 0; i < n_sources; i++)
2057     {
2058       g_source_destroy (sources[i]);
2059       g_source_unref (sources[i]);
2060     }
2061   end = g_get_monotonic_time ();
2062   g_test_message ("Remove in random order: %" G_GINT64_FORMAT,
2063                   (end - start) / 1000);
2064
2065   /* Make sure they really did get removed */
2066   g_main_context_iteration (context, FALSE);
2067
2068   g_free (sources);
2069 }
2070
2071 static void
2072 thread_pool_attach_func (gpointer data,
2073                          gpointer user_data)
2074 {
2075   GMainContext *context = user_data;
2076   GSource *source = data;
2077
2078   g_source_attach (source, context);
2079   g_source_unref (source);
2080 }
2081
2082 static void
2083 thread_pool_destroy_func (gpointer data,
2084                           gpointer user_data)
2085 {
2086   GSource *source = data;
2087
2088   g_source_destroy (source);
2089 }
2090
2091 static void
2092 test_nsources_threadpool (void)
2093 {
2094   GMainContext *context;
2095   GSource **sources;
2096   GThreadPool *pool;
2097   GError *error = NULL;
2098   gint64 start, end;
2099   gsize n_sources = 50000, i;
2100
2101   context = g_main_context_default ();
2102   sources = g_new0 (GSource *, n_sources);
2103
2104   pool = g_thread_pool_new (thread_pool_attach_func, context,
2105                             20, TRUE, NULL);
2106   start = g_get_monotonic_time ();
2107   for (i = 0; i < n_sources; i++)
2108     {
2109       sources[i] = g_idle_source_new ();
2110       g_source_set_callback (sources[i], nsources_cb, NULL, NULL);
2111       g_thread_pool_push (pool, sources[i], &error);
2112       g_assert_no_error (error);
2113     }
2114   g_thread_pool_free (pool, FALSE, TRUE);
2115   end = g_get_monotonic_time ();
2116   g_test_message ("Add sources from threads: %" G_GINT64_FORMAT,
2117                   (end - start) / 1000);
2118
2119   pool = g_thread_pool_new (thread_pool_destroy_func, context,
2120                             20, TRUE, NULL);
2121   start = g_get_monotonic_time ();
2122   for (i = 0; i < n_sources; i++)
2123     {
2124       g_thread_pool_push (pool, sources[i], &error);
2125       g_assert_no_error (error);
2126     }
2127   g_thread_pool_free (pool, FALSE, TRUE);
2128   end = g_get_monotonic_time ();
2129   g_test_message ("Remove sources from threads: %" G_GINT64_FORMAT,
2130                   (end - start) / 1000);
2131
2132   /* Make sure they really did get removed */
2133   g_main_context_iteration (context, FALSE);
2134
2135   g_free (sources);
2136 }
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 finalize (GSource *source)
2144 {
2145   g_assert_false (source_finalize_called);
2146   source_finalize_called = TRUE;
2147 }
2148
2149 static void
2150 dispose (GSource *source)
2151 {
2152   /* Dispose must always be called before finalize */
2153   g_assert_false (source_finalize_called);
2154
2155   if (source_dispose_recycle)
2156     g_source_ref (source);
2157   source_dispose_called++;
2158 }
2159
2160 static GSourceFuncs source_funcs = {
2161   prepare,
2162   check,
2163   dispatch,
2164   finalize,
2165   NULL,
2166   NULL
2167 };
2168
2169 static void
2170 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   source_finalize_called = FALSE;
2177   source_dispose_called = 0;
2178   source_dispose_recycle = FALSE;
2179   source = g_source_new (&source_funcs, sizeof (GSource));
2180   g_source_unref (source);
2181   g_assert_cmpint (source_dispose_called, ==, 0);
2182   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   source_finalize_called = FALSE;
2187   source_dispose_called = 0;
2188   source_dispose_recycle = FALSE;
2189   source = g_source_new (&source_funcs, sizeof (GSource));
2190   g_source_set_dispose_function (source, dispose);
2191   g_source_unref (source);
2192   g_assert_cmpint (source_dispose_called, ==, 1);
2193   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   source_finalize_called = FALSE;
2198   source_dispose_called = 0;
2199   source_dispose_recycle = TRUE;
2200   source = g_source_new (&source_funcs, sizeof (GSource));
2201   g_source_set_dispose_function (source, dispose);
2202   g_source_unref (source);
2203   g_assert_cmpint (source_dispose_called, ==, 1);
2204   g_assert_false (source_finalize_called);
2205
2206   /* Check if the source is properly recycled */
2207   g_assert_cmpint (source->ref_count, ==, 1);
2208
2209   /* And then get rid of it properly */
2210   source_dispose_recycle = FALSE;
2211   g_source_unref (source);
2212   g_assert_cmpint (source_dispose_called, ==, 2);
2213   g_assert_true (source_finalize_called);
2214 }
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 finalize_source_with_source (GSource *source)
2227 {
2228   SourceWithSource *s = (SourceWithSource *) source;
2229
2230   if (s->other_source)
2231     {
2232       g_source_destroy (s->other_source);
2233       g_source_unref (s->other_source);
2234       s->other_source = NULL;
2235     }
2236 }
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 test_maincontext_source_finalization_from_source (gconstpointer user_data)
2249 {
2250   GMainContext *c = g_main_context_new ();
2251   GSource *s1, *s2;
2252
2253   g_test_summary ("Tests if freeing a GSource as part of another GSource "
2254                   "during main context destruction works.");
2255   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/merge_requests/1353");
2256
2257   s1 = g_source_new (&source_with_source_funcs, sizeof (SourceWithSource));
2258   s2 = g_source_new (&source_with_source_funcs, sizeof (SourceWithSource));
2259   ((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   if (GPOINTER_TO_INT (user_data) < 5)
2264     {
2265       g_source_attach (s1, c);
2266       g_source_attach (s2, c);
2267     }
2268   else
2269     {
2270       g_source_attach (s2, c);
2271       g_source_attach (s1, c);
2272     }
2273
2274   /* Test a few different permutations here */
2275   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       g_source_unref (s1);
2280       g_source_unref (s2);
2281       g_main_context_unref (c);
2282     }
2283   else if (GPOINTER_TO_INT (user_data) % 5 == 1)
2284     {
2285       /* Destroy and free the sources before the context */
2286       g_source_destroy (s1);
2287       g_source_unref (s1);
2288       g_source_destroy (s2);
2289       g_source_unref (s2);
2290       g_main_context_unref (c);
2291     }
2292   else if (GPOINTER_TO_INT (user_data) % 5 == 2)
2293     {
2294       /* Destroy and free the sources before the context */
2295       g_source_destroy (s2);
2296       g_source_unref (s2);
2297       g_source_destroy (s1);
2298       g_source_unref (s1);
2299       g_main_context_unref (c);
2300     }
2301   else if (GPOINTER_TO_INT (user_data) % 5 == 3)
2302     {
2303       /* Destroy and free the context before the sources */
2304       g_main_context_unref (c);
2305       g_source_unref (s2);
2306       g_source_unref (s1);
2307     }
2308   else if (GPOINTER_TO_INT (user_data) % 5 == 4)
2309     {
2310       /* Destroy and free the context before the sources */
2311       g_main_context_unref (c);
2312       g_source_unref (s1);
2313       g_source_unref (s2);
2314     }
2315 }
2316
2317 static gboolean
2318 dispatch_source_with_source (GSource *source, GSourceFunc callback, gpointer user_data)
2319 {
2320   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 test_maincontext_source_finalization_from_dispatch (gconstpointer user_data)
2334 {
2335   GMainContext *c = g_main_context_new ();
2336   GSource *s1, *s2;
2337
2338   g_test_summary ("Tests if freeing a GSource as part of another GSource "
2339                   "during main context iteration works.");
2340
2341   s1 = g_source_new (&source_with_source_funcs_dispatch, sizeof (SourceWithSource));
2342   s2 = g_source_new (&source_with_source_funcs_dispatch, sizeof (SourceWithSource));
2343   ((SourceWithSource *)s1)->other_source = g_source_ref (s2);
2344
2345   g_source_attach (s1, c);
2346   g_source_attach (s2, c);
2347
2348   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       g_source_set_ready_time (s1, 0);
2353     }
2354   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       g_source_set_ready_time (s2, 0);
2359     }
2360   else if (GPOINTER_TO_INT (user_data) == 2)
2361     {
2362       /* This destroys both s1 and s2 as part of the iteration */
2363       g_source_set_ready_time (s1, 0);
2364       g_source_set_ready_time (s2, 0);
2365     }
2366
2367   /* Get rid of our references so only the main context has one now */
2368   g_source_unref (s1);
2369   g_source_unref (s2);
2370
2371   /* Iterate as long as there are sources to dispatch */
2372   while (g_main_context_iteration (c, FALSE))
2373     {
2374       /* Do nothing here */
2375     }
2376
2377   g_main_context_unref (c);
2378 }
2379
2380 static void
2381 once_cb (gpointer user_data)
2382 {
2383   guint *counter = user_data;
2384
2385   *counter = *counter + 1;
2386 }
2387
2388 static void
2389 test_maincontext_idle_once (void)
2390 {
2391   guint counter = 0;
2392   guint source_id;
2393   GSource *source;
2394
2395   g_test_summary ("Test g_idle_add_once() works");
2396
2397   source_id = g_idle_add_once (once_cb, &counter);
2398   source = g_main_context_find_source_by_id (NULL, source_id);
2399   g_assert_nonnull (source);
2400   g_source_ref (source);
2401
2402   /* Iterating the main context should dispatch the source. */
2403   g_assert_cmpuint (counter, ==, 0);
2404   g_main_context_iteration (NULL, FALSE);
2405   g_assert_cmpuint (counter, ==, 1);
2406
2407   /* Iterating it again should not dispatch the source again. */
2408   g_main_context_iteration (NULL, FALSE);
2409   g_assert_cmpuint (counter, ==, 1);
2410   g_assert_true (g_source_is_destroyed (source));
2411
2412   g_clear_pointer (&source, g_source_unref);
2413 }
2414
2415 static void
2416 test_maincontext_timeout_once (void)
2417 {
2418   guint counter = 0, check_counter = 0;
2419   guint source_id;
2420   gint64 t;
2421   GSource *source;
2422
2423   g_test_summary ("Test g_timeout_add_once() works");
2424
2425   source_id = g_timeout_add_once (10 /* ms */, once_cb, &counter);
2426   source = g_main_context_find_source_by_id (NULL, source_id);
2427   g_assert_nonnull (source);
2428   g_source_ref (source);
2429
2430   /* Iterating the main context should dispatch the source, though we have to block. */
2431   g_assert_cmpuint (counter, ==, 0);
2432   t = g_get_monotonic_time ();
2433   while (g_get_monotonic_time () - t < 50 * 1000 && counter == 0)
2434     g_main_context_iteration (NULL, TRUE);
2435   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   g_timeout_add_once (30 /* ms */, once_cb, &check_counter);
2441   t = g_get_monotonic_time ();
2442   while (g_get_monotonic_time () - t < 50 * 1000 && check_counter == 0)
2443     g_main_context_iteration (NULL, TRUE);
2444   g_assert_cmpuint (check_counter, ==, 1);
2445   g_assert_cmpuint (counter, ==, 1);
2446   g_assert_true (g_source_is_destroyed (source));
2447
2448   g_clear_pointer (&source, g_source_unref);
2449 }
2450
2451 static void
2452 test_steal_fd (void)
2453 {
2454   GError *error = NULL;
2455   gchar *tmpfile = NULL;
2456   int fd = -42;
2457   int borrowed;
2458   int stolen;
2459
2460   g_assert_cmpint (g_steal_fd (&fd), ==, -42);
2461   g_assert_cmpint (fd, ==, -1);
2462   g_assert_cmpint (g_steal_fd (&fd), ==, -1);
2463   g_assert_cmpint (fd, ==, -1);
2464
2465   fd = g_file_open_tmp (NULL, &tmpfile, &error);
2466   g_assert_cmpint (fd, >=, 0);
2467   g_assert_no_error (error);
2468   borrowed = fd;
2469   stolen = g_steal_fd (&fd);
2470   g_assert_cmpint (fd, ==, -1);
2471   g_assert_cmpint (borrowed, ==, stolen);
2472
2473   g_close (g_steal_fd (&stolen), &error);
2474   g_assert_no_error (error);
2475   g_assert_cmpint (stolen, ==, -1);
2476
2477   g_assert_no_errno (remove (tmpfile));
2478   g_free (tmpfile);
2479 }
2480
2481 int
2482 main (int argc, char *argv[])
2483 {
2484   gint i;
2485
2486   g_test_init (&argc, &argv, NULL);
2487
2488   g_test_add_func ("/maincontext/basic", test_maincontext_basic);
2489   g_test_add_func ("/maincontext/nsources_same_priority", test_nsources_same_priority);
2490   g_test_add_func ("/maincontext/nsources_different_priority", test_nsources_different_priority);
2491   g_test_add_func ("/maincontext/nsources_threadpool", test_nsources_threadpool);
2492   g_test_add_func ("/maincontext/source_finalization", test_maincontext_source_finalization);
2493   for (i = 0; i < 10; i++)
2494     {
2495       gchar *name = g_strdup_printf ("/maincontext/source_finalization_from_source/%d", i);
2496       g_test_add_data_func (name, GINT_TO_POINTER (i), test_maincontext_source_finalization_from_source);
2497       g_free (name);
2498     }
2499   for (i = 0; i < 3; i++)
2500     {
2501       gchar *name = g_strdup_printf ("/maincontext/source_finalization_from_dispatch/%d", i);
2502       g_test_add_data_func (name, GINT_TO_POINTER (i), test_maincontext_source_finalization_from_dispatch);
2503       g_free (name);
2504     }
2505   g_test_add_func ("/maincontext/idle-once", test_maincontext_idle_once);
2506   g_test_add_func ("/maincontext/timeout-once", test_maincontext_timeout_once);
2507
2508   g_test_add_func ("/mainloop/basic", test_mainloop_basic);
2509   g_test_add_func ("/mainloop/timeouts", test_timeouts);
2510   g_test_add_func ("/mainloop/priorities", test_priorities);
2511   g_test_add_func ("/mainloop/invoke", test_invoke);
2512   g_test_add_func ("/mainloop/child_sources", test_child_sources);
2513   g_test_add_func ("/mainloop/recursive_child_sources", test_recursive_child_sources);
2514   g_test_add_func ("/mainloop/recursive_loop_child_sources", test_recursive_loop_child_sources);
2515   g_test_add_func ("/mainloop/swapping_child_sources", test_swapping_child_sources);
2516   g_test_add_func ("/mainloop/blocked_child_sources", test_blocked_child_sources);
2517   g_test_add_func ("/mainloop/source_time", test_source_time);
2518   g_test_add_func ("/mainloop/overflow", test_mainloop_overflow);
2519   g_test_add_func ("/mainloop/ready-time", test_ready_time);
2520   g_test_add_func ("/mainloop/wakeup", test_wakeup);
2521   g_test_add_func ("/mainloop/remove-invalid", test_remove_invalid);
2522   g_test_add_func ("/mainloop/unref-while-pending", test_unref_while_pending);
2523 #ifdef G_OS_UNIX
2524   g_test_add_func ("/mainloop/unix-fd", test_unix_fd);
2525   g_test_add_func ("/mainloop/unix-fd-source", test_unix_fd_source);
2526   g_test_add_func ("/mainloop/source-unix-fd-api", test_source_unix_fd_api);
2527   g_test_add_func ("/mainloop/wait", test_mainloop_wait);
2528   g_test_add_func ("/mainloop/unix-file-poll", test_unix_file_poll);
2529   g_test_add_func ("/mainloop/unix-fd-priority", test_unix_fd_priority);
2530 #endif
2531   g_test_add_func ("/mainloop/nfds", test_nfds);
2532   g_test_add_func ("/mainloop/steal-fd", test_steal_fd);
2533   g_test_add_data_func ("/mainloop/ownerless-polling/attach-first", GINT_TO_POINTER (TRUE), test_ownerless_polling);
2534   g_test_add_data_func ("/mainloop/ownerless-polling/pop-first", GINT_TO_POINTER (FALSE), test_ownerless_polling);
2535
2536   return g_test_run ();
2537 }