1 /* Unit tests for GMainLoop
2 * Copyright (C) 2011 Red Hat, Inc
3 * Author: Matthias Clasen
5 * SPDX-License-Identifier: LicenseRef-old-glib-tests
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.
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.
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.
26 #include <glib/gstdio.h>
27 #include "glib-private.h"
38 prepare (GSource *source, gint *time)
40 g_assert_nonnull (time);
41 g_assert_cmpint (*time, ==, -1);
45 check (GSource *source)
50 dispatch (GSource *source, GSourceFunc cb, gpointer date)
55 static GSourceFuncs global_funcs = {
65 test_maincontext_basic (void)
70 gpointer data = &global_funcs;
72 ctx = g_main_context_new ();
74 g_assert_false (g_main_context_pending (ctx));
75 g_assert_false (g_main_context_iteration (ctx, FALSE));
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));
81 g_assert_false (g_source_get_can_recurse (source));
82 g_assert_null (g_source_get_name (source));
84 g_source_set_can_recurse (source, TRUE);
85 g_source_set_static_name (source, "d");
87 g_assert_true (g_source_get_can_recurse (source));
88 g_assert_cmpstr (g_source_get_name (source), ==, "d");
90 g_source_set_static_name (source, "still d");
91 g_assert_cmpstr (g_source_get_name (source), ==, "still d");
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));
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);
100 g_source_set_priority (source, G_PRIORITY_HIGH);
101 g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_HIGH);
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));
107 g_main_context_unref (ctx);
109 if (g_test_undefined ())
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 ();
117 g_source_unref (source);
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));
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));
139 g_idle_add (cb, data);
140 g_assert_true (g_idle_remove_by_data (data));
144 test_mainloop_basic (void)
149 loop = g_main_loop_new (NULL, FALSE);
151 g_assert_false (g_main_loop_is_running (loop));
153 g_main_loop_ref (loop);
155 ctx = g_main_loop_get_context (loop);
156 g_assert_true (ctx == g_main_context_default ());
158 g_main_loop_unref (loop);
160 g_assert_cmpint (g_main_depth (), ==, 0);
162 g_main_loop_unref (loop);
166 test_ownerless_polling (gconstpointer test_data)
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);
175 GSource *source = NULL;
177 g_assert_true (ctx != g_main_context_default ());
179 g_main_context_push_thread_default (ctx);
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)
193 g_usleep (timeout * 1000);
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);
201 g_main_context_pop_thread_default (ctx);
203 source = g_idle_source_new ();
204 g_source_attach (source, ctx);
205 g_source_unref (source);
208 g_main_context_pop_thread_default (ctx);
210 g_assert_cmpint (g_poll (fds, fds_size, 0), >, 0);
212 g_main_context_unref (ctx);
215 static gint global_a;
216 static gint global_b;
217 static gint global_c;
220 count_calls (gpointer data)
236 if (!g_test_thorough ())
238 g_test_skip ("Not running timing heavy test");
242 global_a = global_b = global_c = 0;
244 ctx = g_main_context_new ();
245 loop = g_main_loop_new (ctx, FALSE);
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);
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);
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);
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);
267 g_main_loop_run (loop);
269 /* We may be delayed for an arbitrary amount of time - for example,
270 * it's possible for all timeouts to fire exactly once.
272 g_assert_cmpint (global_a, >, 0);
273 g_assert_cmpint (global_a, >=, global_b);
274 g_assert_cmpint (global_b, >=, global_c);
276 g_assert_cmpint (global_a, <=, 10);
277 g_assert_cmpint (global_b, <=, 4);
278 g_assert_cmpint (global_c, <=, 3);
280 g_main_loop_unref (loop);
281 g_main_context_unref (ctx);
285 test_priorities (void)
291 global_a = global_b = global_c = 0;
293 ctx = g_main_context_new ();
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);
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);
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);
312 g_assert_true (g_main_context_iteration (ctx, FALSE));
313 g_assert_cmpint (global_a, ==, 0);
314 g_assert_cmpint (global_b, ==, 2);
316 g_source_destroy (sourceb);
318 g_assert_true (g_main_context_iteration (ctx, FALSE));
319 g_assert_cmpint (global_a, ==, 1);
320 g_assert_cmpint (global_b, ==, 2);
322 g_assert_true (g_main_context_pending (ctx));
323 g_source_destroy (sourcea);
324 g_assert_false (g_main_context_pending (ctx));
326 g_main_context_unref (ctx);
330 quit_loop (gpointer data)
332 GMainLoop *loop = data;
334 g_main_loop_quit (loop);
336 return G_SOURCE_REMOVE;
345 g_assert_true (data == g_thread_self ());
353 call_func (gpointer data)
355 func (g_thread_self ());
357 return G_SOURCE_REMOVE;
362 static gboolean thread_ready;
365 thread_func (gpointer data)
367 GMainContext *ctx = data;
371 g_main_context_push_thread_default (ctx);
372 loop = g_main_loop_new (ctx, FALSE);
374 g_mutex_lock (&mutex);
376 g_cond_signal (&cond);
377 g_mutex_unlock (&mutex);
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);
384 g_main_loop_run (loop);
386 g_main_context_pop_thread_default (ctx);
387 g_main_loop_unref (loop);
400 /* this one gets invoked directly */
401 g_main_context_invoke (NULL, func, g_thread_self ());
402 g_assert_cmpint (count, ==, 1);
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);
409 /* test thread-default forcing the invocation to go
412 ctx = g_main_context_new ();
413 thread = g_thread_new ("worker", thread_func, ctx);
415 g_mutex_lock (&mutex);
416 while (!thread_ready)
417 g_cond_wait (&cond, &mutex);
418 g_mutex_unlock (&mutex);
420 g_main_context_invoke (ctx, func, thread);
422 g_thread_join (thread);
423 g_assert_cmpint (count, ==, 3);
425 g_main_context_unref (ctx);
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.
435 static gint64 last_counter_update;
444 counter_source_prepare (GSource *source,
447 CounterSource *csource = (CounterSource *)source;
450 now = g_source_get_time (source);
451 if (now != last_counter_update)
453 last_counter_update = now;
458 return counter >= csource->timeout;
462 counter_source_dispatch (GSource *source,
463 GSourceFunc callback,
466 CounterSource *csource = (CounterSource *) source;
469 again = callback (user_data);
472 csource->timeout = counter + csource->interval;
477 static GSourceFuncs counter_source_funcs = {
478 counter_source_prepare,
480 counter_source_dispatch,
487 counter_source_new (gint interval)
489 GSource *source = g_source_new (&counter_source_funcs, sizeof (CounterSource));
490 CounterSource *csource = (CounterSource *) source;
492 csource->interval = interval;
493 csource->timeout = counter + interval;
500 run_inner_loop (gpointer user_data)
502 GMainContext *ctx = user_data;
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);
514 g_main_loop_run (inner);
515 g_main_loop_unref (inner);
517 return G_SOURCE_CONTINUE;
521 test_child_sources (void)
525 GSource *parent, *child_b, *child_c, *end;
527 ctx = g_main_context_new ();
528 loop = g_main_loop_new (ctx, FALSE);
530 global_a = global_b = global_c = 0;
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);
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);
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);
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);
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);
560 g_main_loop_run (loop);
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:
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
585 g_assert_cmpint (global_a, ==, 6);
586 g_assert_cmpint (global_b, ==, 3);
587 g_assert_cmpint (global_c, ==, 3);
589 g_source_destroy (parent);
590 g_source_unref (parent);
591 g_source_unref (child_b);
592 g_source_unref (child_c);
594 g_main_loop_unref (loop);
595 g_main_context_unref (ctx);
599 test_recursive_child_sources (void)
603 GSource *parent, *child_b, *child_c, *end;
605 ctx = g_main_context_new ();
606 loop = g_main_loop_new (ctx, FALSE);
608 global_a = global_b = global_c = 0;
610 parent = counter_source_new (500);
611 g_source_set_callback (parent, count_calls, &global_a, NULL);
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);
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);
621 g_source_attach (parent, ctx);
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);
628 g_main_loop_run (loop);
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)
642 g_assert_cmpint (global_a, ==, 9);
643 g_assert_cmpint (global_b, ==, 9);
644 g_assert_cmpint (global_c, ==, 4);
646 g_source_destroy (parent);
647 g_source_unref (parent);
648 g_source_unref (child_b);
649 g_source_unref (child_c);
651 g_main_loop_unref (loop);
652 g_main_context_unref (ctx);
656 GSource *parent, *old_child, *new_child;
661 swap_sources (gpointer user_data)
663 SwappingTestData *data = user_data;
667 g_source_remove_child_source (data->parent, data->old_child);
668 g_clear_pointer (&data->old_child, g_source_unref);
671 if (!data->new_child)
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);
678 return G_SOURCE_CONTINUE;
682 assert_not_reached_callback (gpointer user_data)
684 g_assert_not_reached ();
686 return G_SOURCE_REMOVE;
690 test_swapping_child_sources (void)
694 SwappingTestData data;
696 ctx = g_main_context_new ();
697 loop = g_main_loop_new (ctx, FALSE);
699 data.parent = counter_source_new (50);
701 g_source_set_callback (data.parent, swap_sources, &data, NULL);
702 g_source_attach (data.parent, ctx);
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);
708 data.new_child = NULL;
709 g_main_loop_run (loop);
711 g_source_destroy (data.parent);
712 g_source_unref (data.parent);
713 g_source_unref (data.new_child);
715 g_main_loop_unref (loop);
716 g_main_context_unref (ctx);
720 add_source_callback (gpointer user_data)
722 GMainLoop *loop = user_data;
723 GSource *self = g_main_current_source (), *child;
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.
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);
736 g_main_loop_quit (loop);
741 test_blocked_child_sources (void)
747 g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=701283");
749 ctx = g_main_context_new ();
750 loop = g_main_loop_new (ctx, FALSE);
752 source = g_idle_source_new ();
753 g_source_set_callback (source, add_source_callback, loop, NULL);
754 g_source_attach (source, ctx);
756 g_main_loop_run (loop);
758 g_source_destroy (source);
759 g_source_unref (source);
761 g_main_loop_unref (loop);
762 g_main_context_unref (ctx);
769 GSource *timeout1, *timeout2;
771 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
772 GTimeVal tv; /* needed for g_source_get_current_time() */
773 G_GNUC_END_IGNORE_DEPRECATIONS
777 timeout1_callback (gpointer user_data)
779 TimeTestData *data = user_data;
781 gint64 mtime1, mtime2, time2;
783 source = g_main_current_source ();
784 g_assert_true (source == data->timeout1);
786 if (data->time1 == -1)
788 /* First iteration */
789 g_assert_false (g_source_is_destroyed (data->timeout2));
791 mtime1 = g_get_monotonic_time ();
792 data->time1 = g_source_get_time (source);
794 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
795 g_source_get_current_time (source, &data->tv);
796 G_GNUC_END_IGNORE_DEPRECATIONS
798 /* g_source_get_time() does not change during a single callback */
800 mtime2 = g_get_monotonic_time ();
801 time2 = g_source_get_time (source);
803 g_assert_cmpint (mtime1, <, mtime2);
804 g_assert_cmpint (data->time1, ==, time2);
808 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
810 G_GNUC_END_IGNORE_DEPRECATIONS
812 /* Second iteration */
813 g_assert_true (g_source_is_destroyed (data->timeout2));
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()
819 time2 = g_source_get_time (source);
820 g_assert_cmpint (data->time1, <, time2);
822 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
823 g_source_get_current_time (source, &tv);
824 G_GNUC_END_IGNORE_DEPRECATIONS
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));
830 g_main_loop_quit (data->loop);
837 timeout2_callback (gpointer user_data)
839 TimeTestData *data = user_data;
843 source = g_main_current_source ();
844 g_assert_true (source == data->timeout2);
846 g_assert_false (g_source_is_destroyed (data->timeout1));
848 /* g_source_get_time() does not change between different sources in
849 * a single iteration of the mainloop.
851 time2 = g_source_get_time (source);
852 g_assert_cmpint (data->time1, ==, time2);
854 /* The source should still have a valid time even after being
855 * destroyed, since it's currently running.
857 g_source_destroy (source);
858 time3 = g_source_get_time (source);
859 g_assert_cmpint (time2, ==, time3);
865 test_source_time (void)
869 data.ctx = g_main_context_new ();
870 data.loop = g_main_loop_new (data.ctx, FALSE);
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);
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);
882 g_main_loop_run (data.loop);
884 g_assert_false (g_source_is_destroyed (data.timeout1));
885 g_assert_true (g_source_is_destroyed (data.timeout2));
887 g_source_destroy (data.timeout1);
888 g_source_unref (data.timeout1);
889 g_source_unref (data.timeout2);
891 g_main_loop_unref (data.loop);
892 g_main_context_unref (data.ctx);
896 guint outstanding_ops;
901 on_source_fired_cb (gpointer user_data)
903 TestOverflowData *data = user_data;
904 GSource *current_source;
905 GMainContext *current_context;
908 data->outstanding_ops--;
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));
917 if (data->outstanding_ops == 0)
918 g_main_loop_quit (data->loop);
923 add_idle_source (GMainContext *ctx,
924 TestOverflowData *data)
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++;
938 test_mainloop_overflow (void)
943 TestOverflowData data;
946 g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=687098");
948 memset (&data, 0, sizeof (data));
950 ctx = GLIB_PRIVATE_CALL (g_main_context_new_with_next_id) (G_MAXUINT-1);
952 loop = g_main_loop_new (ctx, TRUE);
953 data.outstanding_ops = 0;
956 source = add_idle_source (ctx, &data);
957 g_assert_cmpint (source->source_id, ==, G_MAXUINT-1);
959 source = add_idle_source (ctx, &data);
960 g_assert_cmpint (source->source_id, ==, G_MAXUINT);
962 source = add_idle_source (ctx, &data);
963 g_assert_cmpint (source->source_id, !=, 0);
965 /* Now, a lot more sources */
966 for (i = 0; i < 50; i++)
968 source = add_idle_source (ctx, &data);
969 g_assert_cmpint (source->source_id, !=, 0);
972 g_main_loop_run (loop);
973 g_assert_cmpint (data.outstanding_ops, ==, 0);
975 g_main_loop_unref (loop);
976 g_main_context_unref (ctx);
979 static gint ready_time_dispatched; /* (atomic) */
982 ready_time_dispatch (GSource *source,
983 GSourceFunc callback,
986 g_atomic_int_set (&ready_time_dispatched, TRUE);
988 g_source_set_ready_time (source, -1);
994 run_context (gpointer user_data)
996 g_main_loop_run (user_data);
1002 test_ready_time (void)
1006 GSourceFuncs source_funcs = {
1007 NULL, NULL, ready_time_dispatch, NULL, NULL, NULL
1011 source = g_source_new (&source_funcs, sizeof (GSource));
1012 g_source_attach (source, NULL);
1013 g_source_unref (source);
1015 /* Unfortunately we can't do too many things with respect to timing
1016 * without getting into trouble on slow systems or heavily loaded
1019 * We can test that the basics are working, though.
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));
1027 /* The ready time should not have been changed */
1028 g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
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);
1034 /* A source with a ready time set to tomorrow should not fire on any
1035 * builder, no matter how badly loaded...
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);
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);
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);
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);
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);
1072 /* Now do some tests of cross-thread wakeups.
1074 * Make sure it wakes up right away from the start.
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));
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));
1087 /* kill the thread */
1088 g_main_loop_quit (loop);
1089 g_thread_join (thread);
1090 g_main_loop_unref (loop);
1092 g_source_destroy (source);
1101 ctx = g_main_context_new ();
1103 /* run a random large enough number of times because
1104 * main contexts tend to wake up a few times after creation.
1106 for (i = 0; i < 100; i++)
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
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().
1116 g_main_context_wakeup (ctx);
1117 g_main_context_iteration (ctx, TRUE);
1120 g_main_context_unref (ctx);
1124 test_remove_invalid (void)
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 ();
1132 trivial_prepare (GSource *source,
1139 static gint n_finalized;
1142 trivial_finalize (GSource *source)
1148 test_unref_while_pending (void)
1150 static GSourceFuncs funcs = {
1151 trivial_prepare, NULL, NULL, trivial_finalize, NULL, NULL
1153 GMainContext *context;
1156 context = g_main_context_new ();
1158 source = g_source_new (&funcs, sizeof (GSource));
1159 g_source_attach (source, context);
1160 g_source_unref (source);
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);
1167 /* Destroy the context */
1168 g_main_context_unref (context);
1170 /* Make sure we didn't leak the source */
1171 g_assert_cmpint (n_finalized, ==, 1);
1180 prepare_loop_run (GSource *source, gint *time)
1182 LoopedSource *looped_source = (LoopedSource*) source;
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 ();
1195 check_loop_run (GSource *source)
1197 LoopedSource *looped_source = (LoopedSource*) source;
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 ();
1209 dispatch_loop_run (GSource *source,
1210 GSourceFunc callback,
1213 LoopedSource *looped_source = (LoopedSource*) source;
1215 g_main_loop_quit (looped_source->loop);
1221 test_recursive_loop_child_sources (void)
1225 GSourceFuncs loop_run_funcs = {
1226 prepare_loop_run, check_loop_run, dispatch_loop_run, NULL, NULL, NULL,
1229 loop = g_main_loop_new (NULL, FALSE);
1231 source = g_source_new (&loop_run_funcs, sizeof (LoopedSource));
1232 ((LoopedSource*)source)->loop = loop;
1234 g_source_attach (source, NULL);
1236 g_main_loop_run (loop);
1237 g_source_unref (source);
1239 g_main_loop_unref (loop);
1245 #include <glib-unix.h>
1248 static gchar zeros[1024];
1251 fill_a_pipe (gint 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);
1266 write_bytes (gint fd,
1267 GIOCondition condition,
1270 gssize *to_write = user_data;
1276 /* Detect if we run before we should */
1277 g_assert_cmpint (*to_write, >=, 0);
1279 limit = MIN ((gsize) *to_write, sizeof zeros);
1280 *to_write -= write (fd, zeros, limit);
1286 read_bytes (gint fd,
1287 GIOCondition condition,
1290 static gchar buffer[1024];
1291 gssize *to_read = user_data;
1293 *to_read -= read (fd, buffer, sizeof buffer);
1295 /* The loop will exit when there is nothing else to read, then we will
1296 * use g_source_remove() to destroy this source.
1305 gssize to_write = -1;
1314 g_assert_cmpint (s, ==, 0);
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));
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));
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.
1334 gssize to_write_was = to_write;
1335 gssize to_read_was = to_read;
1337 if (!g_main_context_iteration (NULL, FALSE))
1340 /* Since the sources are at different priority, only one of them
1341 * should possibly have run.
1343 g_assert_true (to_write == to_write_was || to_read == to_read_was);
1346 g_assert_cmpint (to_write, ==, 0);
1347 g_assert_cmpint (to_read, ==, 0);
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);
1361 assert_main_context_state (gint n_to_poll,
1364 GMainContext *context;
1365 gboolean consumed[10] = { };
1366 GPollFD poll_fds[10];
1375 context = g_main_context_default ();
1377 acquired = g_main_context_acquire (context);
1378 g_assert_true (acquired);
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 */
1385 va_start (ap, n_to_poll);
1386 for (i = 0; i < n_to_poll; i++)
1388 gint expected_fd = va_arg (ap, gint);
1389 GIOCondition expected_events = va_arg (ap, GIOCondition);
1390 GIOCondition report_events = va_arg (ap, GIOCondition);
1392 for (j = 0; j < n; j++)
1393 if (!consumed[j] && poll_fds[j].fd == expected_fd && poll_fds[j].events == expected_events)
1395 poll_fds[j].revents = report_events;
1401 g_error ("Unable to find fd %d (index %d) with events 0x%x", expected_fd, i, (guint) expected_events);
1405 /* find the gwakeup, flag as non-ready */
1406 for (i = 0; i < n; i++)
1408 poll_fds[i].revents = 0;
1410 if (g_main_context_check (context, max_priority, poll_fds, n))
1411 g_main_context_dispatch (context);
1413 g_main_context_release (context);
1418 GIOCondition condition,
1421 gboolean *flag = user_data;
1429 test_unix_fd_source (void)
1431 GSource *out_source;
1438 assert_main_context_state (0);
1441 g_assert_cmpint (s, ==, 0);
1443 source = g_unix_fd_source_new (fds[1], G_IO_OUT);
1444 g_source_attach (source, NULL);
1446 /* Check that a source with no callback gets successfully detached
1447 * with a warning printed.
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);
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.
1464 #if G_GNUC_CHECK_VERSION(8, 0)
1465 #pragma GCC diagnostic push
1466 #pragma GCC diagnostic error "-Wcast-function-type"
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
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);
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);
1487 /* raise the priority of the in source to higher than out*/
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);
1495 /* now, let them be equal */
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);
1503 g_source_destroy (out_source);
1504 g_source_unref (out_source);
1505 g_source_destroy (in_source);
1506 g_source_unref (in_source);
1518 return_true (GSource *source, GSourceFunc callback, gpointer user_data)
1520 FlagSource *flag_source = (FlagSource *) source;
1522 flag_source->flagged = TRUE;
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
1532 test_source_unix_fd_api (void)
1534 GSourceFuncs no_funcs = {
1535 NULL, NULL, return_true, NULL, NULL, NULL
1539 gpointer tag1, tag2;
1543 g_assert_cmpint (pipe (fds_a), ==, 0);
1544 g_assert_cmpint (pipe (fds_b), ==, 0);
1546 source_a = g_source_new (&no_funcs, sizeof (FlagSource));
1547 source_b = g_source_new (&no_funcs, sizeof (FlagSource));
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);
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);
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);
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);
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);
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);
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);
1623 /* destroy the sources */
1624 g_source_destroy (source_a);
1625 g_source_destroy (source_b);
1626 assert_main_context_state (0);
1628 g_source_unref (source_a);
1629 g_source_unref (source_b);
1637 unixfd_quit_loop (gint fd,
1638 GIOCondition condition,
1641 GMainLoop *loop = user_data;
1643 g_main_loop_quit (loop);
1649 test_unix_file_poll (void)
1655 fd = open ("/dev/null", O_RDONLY);
1656 g_assert_cmpint (fd, >=, 0);
1658 loop = g_main_loop_new (NULL, FALSE);
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);
1664 /* Should not block */
1665 g_main_loop_run (loop);
1667 g_source_destroy (source);
1669 assert_main_context_state (0);
1671 g_source_unref (source);
1673 g_main_loop_unref (loop);
1679 test_unix_fd_priority (void)
1686 gboolean s2 = FALSE, s3 = FALSE;
1688 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/1592");
1690 loop = g_main_loop_new (NULL, FALSE);
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);
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);
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);
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
1717 g_assert_cmpint (fd1, <, fd2);
1719 g_assert_true (g_main_context_iteration (NULL, FALSE));
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. */
1728 g_main_loop_unref (loop);
1738 timeout_cb (gpointer data)
1740 GMainLoop *loop = data;
1741 GMainContext *context;
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));
1747 g_main_loop_quit (loop);
1749 return G_SOURCE_REMOVE;
1753 threadf (gpointer data)
1755 GMainContext *context = data;
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);
1764 g_main_loop_run (loop);
1766 g_source_destroy (source);
1767 g_source_unref (source);
1768 g_main_loop_unref (loop);
1774 test_mainloop_wait (void)
1776 GMainContext *context;
1779 context = g_main_context_new ();
1781 t1 = g_thread_new ("t1", threadf, context);
1782 t2 = g_thread_new ("t2", threadf, context);
1787 g_main_context_unref (context);
1792 nfds_in_cb (GIOChannel *io,
1793 GIOCondition condition,
1796 gboolean *in_cb_ran = user_data;
1799 g_assert_cmpint (condition, ==, G_IO_IN);
1804 nfds_out_cb (GIOChannel *io,
1805 GIOCondition condition,
1808 gboolean *out_cb_ran = user_data;
1811 g_assert_cmpint (condition, ==, G_IO_OUT);
1816 nfds_out_low_cb (GIOChannel *io,
1817 GIOCondition condition,
1820 g_assert_not_reached ();
1831 GSource *source1, *source2, *source3;
1832 gboolean source1_ran = FALSE, source3_ran = FALSE;
1834 GError *error = NULL;
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
1842 g_assert_cmpint (nfds, ==, 1);
1844 fd = g_file_open_tmp (NULL, &tmpfile, &error);
1845 g_assert_no_error (error);
1847 io = g_io_channel_unix_new (fd);
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);
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);
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);
1869 g_assert_not_reached ();
1871 /* Add a second pollfd with the same fd but different event, and
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,
1878 g_source_attach (source2, ctx);
1880 /* g_main_context_query() should still return only 2 pollfds,
1881 * one of which has our fd, and a combined events field.
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);
1891 g_assert_not_reached ();
1893 /* But if we query with a max priority, we won't see the
1894 * lower-priority one.
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);
1904 g_assert_not_reached ();
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);
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);
1921 g_assert_not_reached ();
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.
1927 g_main_context_iteration (ctx, FALSE);
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.
1935 g_assert_true (source1_ran);
1936 g_assert_true (source3_ran);
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);
1946 g_io_channel_unref (io);
1950 g_main_context_unref (ctx);
1954 nsources_cb (gpointer user_data)
1956 g_assert_not_reached ();
1961 shuffle_nsources (GSource **sources, int num)
1966 for (i = 0; i < num * 10; i++)
1968 a = g_random_int_range (0, num);
1969 b = g_random_int_range (0, num);
1971 sources[a] = sources[b];
1977 test_nsources_same_priority (void)
1979 GMainContext *context;
1982 gsize n_sources = 50000, i;
1984 context = g_main_context_default ();
1985 sources = g_new0 (GSource *, n_sources);
1987 start = g_get_monotonic_time ();
1988 for (i = 0; i < n_sources; i++)
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);
1994 end = g_get_monotonic_time ();
1995 g_test_message ("Add same-priority sources: %" G_GINT64_FORMAT,
1996 (end - start) / 1000);
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);
2005 shuffle_nsources (sources, n_sources);
2007 start = g_get_monotonic_time ();
2008 for (i = 0; i < n_sources; i++)
2010 g_source_destroy (sources[i]);
2011 g_source_unref (sources[i]);
2013 end = g_get_monotonic_time ();
2014 g_test_message ("Remove in random order: %" G_GINT64_FORMAT,
2015 (end - start) / 1000);
2017 /* Make sure they really did get removed */
2018 g_main_context_iteration (context, FALSE);
2024 test_nsources_different_priority (void)
2026 GMainContext *context;
2029 gsize n_sources = 50000, i;
2031 context = g_main_context_default ();
2032 sources = g_new0 (GSource *, n_sources);
2034 start = g_get_monotonic_time ();
2035 for (i = 0; i < n_sources; i++)
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);
2042 end = g_get_monotonic_time ();
2043 g_test_message ("Add different-priority sources: %" G_GINT64_FORMAT,
2044 (end - start) / 1000);
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);
2053 shuffle_nsources (sources, n_sources);
2055 start = g_get_monotonic_time ();
2056 for (i = 0; i < n_sources; i++)
2058 g_source_destroy (sources[i]);
2059 g_source_unref (sources[i]);
2061 end = g_get_monotonic_time ();
2062 g_test_message ("Remove in random order: %" G_GINT64_FORMAT,
2063 (end - start) / 1000);
2065 /* Make sure they really did get removed */
2066 g_main_context_iteration (context, FALSE);
2072 thread_pool_attach_func (gpointer data,
2075 GMainContext *context = user_data;
2076 GSource *source = data;
2078 g_source_attach (source, context);
2079 g_source_unref (source);
2083 thread_pool_destroy_func (gpointer data,
2086 GSource *source = data;
2088 g_source_destroy (source);
2092 test_nsources_threadpool (void)
2094 GMainContext *context;
2097 GError *error = NULL;
2099 gsize n_sources = 50000, i;
2101 context = g_main_context_default ();
2102 sources = g_new0 (GSource *, n_sources);
2104 pool = g_thread_pool_new (thread_pool_attach_func, context,
2106 start = g_get_monotonic_time ();
2107 for (i = 0; i < n_sources; i++)
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);
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);
2119 pool = g_thread_pool_new (thread_pool_destroy_func, context,
2121 start = g_get_monotonic_time ();
2122 for (i = 0; i < n_sources; i++)
2124 g_thread_pool_push (pool, sources[i], &error);
2125 g_assert_no_error (error);
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);
2132 /* Make sure they really did get removed */
2133 g_main_context_iteration (context, FALSE);
2138 static gboolean source_finalize_called = FALSE;
2139 static guint source_dispose_called = 0;
2140 static gboolean source_dispose_recycle = FALSE;
2143 finalize (GSource *source)
2145 g_assert_false (source_finalize_called);
2146 source_finalize_called = TRUE;
2150 dispose (GSource *source)
2152 /* Dispose must always be called before finalize */
2153 g_assert_false (source_finalize_called);
2155 if (source_dispose_recycle)
2156 g_source_ref (source);
2157 source_dispose_called++;
2160 static GSourceFuncs source_funcs = {
2170 test_maincontext_source_finalization (void)
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);
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);
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);
2206 /* Check if the source is properly recycled */
2207 g_assert_cmpint (source->ref_count, ==, 1);
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);
2216 /* GSource implementation which optionally keeps a strong reference to another
2217 * GSource until finalization, when it destroys and unrefs the other source.
2222 GSource *other_source;
2226 finalize_source_with_source (GSource *source)
2228 SourceWithSource *s = (SourceWithSource *) source;
2230 if (s->other_source)
2232 g_source_destroy (s->other_source);
2233 g_source_unref (s->other_source);
2234 s->other_source = NULL;
2238 static GSourceFuncs source_with_source_funcs = {
2242 finalize_source_with_source,
2248 test_maincontext_source_finalization_from_source (gconstpointer user_data)
2250 GMainContext *c = g_main_context_new ();
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");
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);
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)
2265 g_source_attach (s1, c);
2266 g_source_attach (s2, c);
2270 g_source_attach (s2, c);
2271 g_source_attach (s1, c);
2274 /* Test a few different permutations here */
2275 if (GPOINTER_TO_INT (user_data) % 5 == 0)
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);
2283 else if (GPOINTER_TO_INT (user_data) % 5 == 1)
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);
2292 else if (GPOINTER_TO_INT (user_data) % 5 == 2)
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);
2301 else if (GPOINTER_TO_INT (user_data) % 5 == 3)
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);
2308 else if (GPOINTER_TO_INT (user_data) % 5 == 4)
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);
2318 dispatch_source_with_source (GSource *source, GSourceFunc callback, gpointer user_data)
2320 return G_SOURCE_REMOVE;
2323 static GSourceFuncs source_with_source_funcs_dispatch = {
2326 dispatch_source_with_source,
2327 finalize_source_with_source,
2333 test_maincontext_source_finalization_from_dispatch (gconstpointer user_data)
2335 GMainContext *c = g_main_context_new ();
2338 g_test_summary ("Tests if freeing a GSource as part of another GSource "
2339 "during main context iteration works.");
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);
2345 g_source_attach (s1, c);
2346 g_source_attach (s2, c);
2348 if (GPOINTER_TO_INT (user_data) == 0)
2350 /* This finalizes s1 as part of the iteration, which then destroys and
2352 g_source_set_ready_time (s1, 0);
2354 else if (GPOINTER_TO_INT (user_data) == 1)
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);
2360 else if (GPOINTER_TO_INT (user_data) == 2)
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);
2367 /* Get rid of our references so only the main context has one now */
2368 g_source_unref (s1);
2369 g_source_unref (s2);
2371 /* Iterate as long as there are sources to dispatch */
2372 while (g_main_context_iteration (c, FALSE))
2374 /* Do nothing here */
2377 g_main_context_unref (c);
2381 once_cb (gpointer user_data)
2383 guint *counter = user_data;
2385 *counter = *counter + 1;
2389 test_maincontext_idle_once (void)
2395 g_test_summary ("Test g_idle_add_once() works");
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);
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);
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));
2412 g_clear_pointer (&source, g_source_unref);
2416 test_maincontext_timeout_once (void)
2418 guint counter = 0, check_counter = 0;
2423 g_test_summary ("Test g_timeout_add_once() works");
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);
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);
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));
2448 g_clear_pointer (&source, g_source_unref);
2452 test_steal_fd (void)
2454 GError *error = NULL;
2455 gchar *tmpfile = NULL;
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);
2465 fd = g_file_open_tmp (NULL, &tmpfile, &error);
2466 g_assert_cmpint (fd, >=, 0);
2467 g_assert_no_error (error);
2469 stolen = g_steal_fd (&fd);
2470 g_assert_cmpint (fd, ==, -1);
2471 g_assert_cmpint (borrowed, ==, stolen);
2473 g_close (g_steal_fd (&stolen), &error);
2474 g_assert_no_error (error);
2475 g_assert_cmpint (stolen, ==, -1);
2477 g_assert_no_errno (remove (tmpfile));
2482 main (int argc, char *argv[])
2486 g_test_init (&argc, &argv, NULL);
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++)
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);
2499 for (i = 0; i < 3; i++)
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);
2505 g_test_add_func ("/maincontext/idle-once", test_maincontext_idle_once);
2506 g_test_add_func ("/maincontext/timeout-once", test_maincontext_timeout_once);
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);
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);
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);
2536 return g_test_run ();