Merge branch '976-disable-assert-checks' into 'master'
[glib.git] / glib / tests / mainloop.c
blobcf114fd40a595485f9339041923c9d4b4c872c61
1 /* Unit tests for GMainLoop
2 * Copyright (C) 2011 Red Hat, Inc
3 * Author: Matthias Clasen
5 * This work is provided "as is"; redistribution and modification
6 * in whole or in part, in any medium, physical or electronic is
7 * permitted without restriction.
9 * This work is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * In no event shall the authors or contributors be liable for any
14 * direct, indirect, incidental, special, exemplary, or consequential
15 * damages (including, but not limited to, procurement of substitute
16 * goods or services; loss of use, data, or profits; or business
17 * interruption) however caused and on any theory of liability, whether
18 * in contract, strict liability, or tort (including negligence or
19 * otherwise) arising in any way out of the use of this software, even
20 * if advised of the possibility of such damage.
23 #include <glib.h>
24 #include "glib-private.h"
25 #include <stdio.h>
26 #include <string.h>
28 static gboolean cb (gpointer data)
30 return FALSE;
33 static gboolean prepare (GSource *source, gint *time)
35 return FALSE;
37 static gboolean check (GSource *source)
39 return FALSE;
41 static gboolean dispatch (GSource *source, GSourceFunc cb, gpointer date)
43 return FALSE;
46 GSourceFuncs funcs = {
47 prepare,
48 check,
49 dispatch,
50 NULL
53 static void
54 test_maincontext_basic (void)
56 GMainContext *ctx;
57 GSource *source;
58 guint id;
59 gpointer data = &funcs;
61 ctx = g_main_context_new ();
63 g_assert (!g_main_context_pending (ctx));
64 g_assert (!g_main_context_iteration (ctx, FALSE));
66 source = g_source_new (&funcs, sizeof (GSource));
67 g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_DEFAULT);
68 g_assert (!g_source_is_destroyed (source));
70 g_assert (!g_source_get_can_recurse (source));
71 g_assert (g_source_get_name (source) == NULL);
73 g_source_set_can_recurse (source, TRUE);
74 g_source_set_name (source, "d");
76 g_assert (g_source_get_can_recurse (source));
77 g_assert_cmpstr (g_source_get_name (source), ==, "d");
79 g_assert (g_main_context_find_source_by_user_data (ctx, NULL) == NULL);
80 g_assert (g_main_context_find_source_by_funcs_user_data (ctx, &funcs, NULL) == NULL);
82 id = g_source_attach (source, ctx);
83 g_assert_cmpint (g_source_get_id (source), ==, id);
84 g_assert (g_main_context_find_source_by_id (ctx, id) == source);
86 g_source_set_priority (source, G_PRIORITY_HIGH);
87 g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_HIGH);
89 g_source_destroy (source);
90 g_assert (g_source_get_context (source) == ctx);
91 g_assert (g_main_context_find_source_by_id (ctx, id) == NULL);
93 g_main_context_unref (ctx);
95 if (g_test_undefined ())
97 g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
98 "*assertion*source->context != NULL*failed*");
99 g_assert (g_source_get_context (source) == NULL);
100 g_test_assert_expected_messages ();
103 g_source_unref (source);
105 ctx = g_main_context_default ();
106 source = g_source_new (&funcs, sizeof (GSource));
107 g_source_set_funcs (source, &funcs);
108 g_source_set_callback (source, cb, data, NULL);
109 id = g_source_attach (source, ctx);
110 g_source_unref (source);
111 g_source_set_name_by_id (id, "e");
112 g_assert_cmpstr (g_source_get_name (source), ==, "e");
113 g_assert (g_source_get_context (source) == ctx);
114 g_assert (g_source_remove_by_funcs_user_data (&funcs, data));
116 source = g_source_new (&funcs, sizeof (GSource));
117 g_source_set_funcs (source, &funcs);
118 g_source_set_callback (source, cb, data, NULL);
119 id = g_source_attach (source, ctx);
120 g_source_unref (source);
121 g_assert (g_source_remove_by_user_data (data));
122 g_assert (!g_source_remove_by_user_data ((gpointer)0x1234));
124 g_idle_add (cb, data);
125 g_assert (g_idle_remove_by_data (data));
128 static void
129 test_mainloop_basic (void)
131 GMainLoop *loop;
132 GMainContext *ctx;
134 loop = g_main_loop_new (NULL, FALSE);
136 g_assert (!g_main_loop_is_running (loop));
138 g_main_loop_ref (loop);
140 ctx = g_main_loop_get_context (loop);
141 g_assert (ctx == g_main_context_default ());
143 g_main_loop_unref (loop);
145 g_assert_cmpint (g_main_depth (), ==, 0);
147 g_main_loop_unref (loop);
150 static gint a;
151 static gint b;
152 static gint c;
154 static gboolean
155 count_calls (gpointer data)
157 gint *i = data;
159 (*i)++;
161 return TRUE;
164 static void
165 test_timeouts (void)
167 GMainContext *ctx;
168 GMainLoop *loop;
169 GSource *source;
171 a = b = c = 0;
173 ctx = g_main_context_new ();
174 loop = g_main_loop_new (ctx, FALSE);
176 source = g_timeout_source_new (100);
177 g_source_set_callback (source, count_calls, &a, NULL);
178 g_source_attach (source, ctx);
179 g_source_unref (source);
181 source = g_timeout_source_new (250);
182 g_source_set_callback (source, count_calls, &b, NULL);
183 g_source_attach (source, ctx);
184 g_source_unref (source);
186 source = g_timeout_source_new (330);
187 g_source_set_callback (source, count_calls, &c, NULL);
188 g_source_attach (source, ctx);
189 g_source_unref (source);
191 source = g_timeout_source_new (1050);
192 g_source_set_callback (source, (GSourceFunc)g_main_loop_quit, loop, NULL);
193 g_source_attach (source, ctx);
194 g_source_unref (source);
196 g_main_loop_run (loop);
198 /* We may be delayed for an arbitrary amount of time - for example,
199 * it's possible for all timeouts to fire exactly once.
201 g_assert_cmpint (a, >, 0);
202 g_assert_cmpint (a, >=, b);
203 g_assert_cmpint (b, >=, c);
205 g_assert_cmpint (a, <=, 10);
206 g_assert_cmpint (b, <=, 4);
207 g_assert_cmpint (c, <=, 3);
209 g_main_loop_unref (loop);
210 g_main_context_unref (ctx);
213 static void
214 test_priorities (void)
216 GMainContext *ctx;
217 GSource *sourcea;
218 GSource *sourceb;
220 a = b = c = 0;
222 ctx = g_main_context_new ();
224 sourcea = g_idle_source_new ();
225 g_source_set_callback (sourcea, count_calls, &a, NULL);
226 g_source_set_priority (sourcea, 1);
227 g_source_attach (sourcea, ctx);
228 g_source_unref (sourcea);
230 sourceb = g_idle_source_new ();
231 g_source_set_callback (sourceb, count_calls, &b, NULL);
232 g_source_set_priority (sourceb, 0);
233 g_source_attach (sourceb, ctx);
234 g_source_unref (sourceb);
236 g_assert (g_main_context_pending (ctx));
237 g_assert (g_main_context_iteration (ctx, FALSE));
238 g_assert_cmpint (a, ==, 0);
239 g_assert_cmpint (b, ==, 1);
241 g_assert (g_main_context_iteration (ctx, FALSE));
242 g_assert_cmpint (a, ==, 0);
243 g_assert_cmpint (b, ==, 2);
245 g_source_destroy (sourceb);
247 g_assert (g_main_context_iteration (ctx, FALSE));
248 g_assert_cmpint (a, ==, 1);
249 g_assert_cmpint (b, ==, 2);
251 g_assert (g_main_context_pending (ctx));
252 g_source_destroy (sourcea);
253 g_assert (!g_main_context_pending (ctx));
255 g_main_context_unref (ctx);
258 static gboolean
259 quit_loop (gpointer data)
261 GMainLoop *loop = data;
263 g_main_loop_quit (loop);
265 return G_SOURCE_REMOVE;
268 static gint count;
270 static gboolean
271 func (gpointer data)
273 if (data != NULL)
274 g_assert (data == g_thread_self ());
276 count++;
278 return FALSE;
281 static gboolean
282 call_func (gpointer data)
284 func (g_thread_self ());
286 return G_SOURCE_REMOVE;
289 static GMutex mutex;
290 static GCond cond;
291 static gboolean thread_ready;
293 static gpointer
294 thread_func (gpointer data)
296 GMainContext *ctx = data;
297 GMainLoop *loop;
298 GSource *source;
300 g_main_context_push_thread_default (ctx);
301 loop = g_main_loop_new (ctx, FALSE);
303 g_mutex_lock (&mutex);
304 thread_ready = TRUE;
305 g_cond_signal (&cond);
306 g_mutex_unlock (&mutex);
308 source = g_timeout_source_new (500);
309 g_source_set_callback (source, quit_loop, loop, NULL);
310 g_source_attach (source, ctx);
311 g_source_unref (source);
313 g_main_loop_run (loop);
315 g_main_context_pop_thread_default (ctx);
316 g_main_loop_unref (loop);
318 return NULL;
321 static void
322 test_invoke (void)
324 GMainContext *ctx;
325 GThread *thread;
327 count = 0;
329 /* this one gets invoked directly */
330 g_main_context_invoke (NULL, func, g_thread_self ());
331 g_assert_cmpint (count, ==, 1);
333 /* invoking out of an idle works too */
334 g_idle_add (call_func, NULL);
335 g_main_context_iteration (g_main_context_default (), FALSE);
336 g_assert_cmpint (count, ==, 2);
338 /* test thread-default forcing the invocation to go
339 * to another thread
341 ctx = g_main_context_new ();
342 thread = g_thread_new ("worker", thread_func, ctx);
344 g_mutex_lock (&mutex);
345 while (!thread_ready)
346 g_cond_wait (&cond, &mutex);
347 g_mutex_unlock (&mutex);
349 g_main_context_invoke (ctx, func, thread);
351 g_thread_join (thread);
352 g_assert_cmpint (count, ==, 3);
354 g_main_context_unref (ctx);
357 /* We can't use timeout sources here because on slow or heavily-loaded
358 * machines, the test program might not get enough cycles to hit the
359 * timeouts at the expected times. So instead we define a source that
360 * is based on the number of GMainContext iterations.
363 static gint counter;
364 static gint64 last_counter_update;
366 typedef struct {
367 GSource source;
368 gint interval;
369 gint timeout;
370 } CounterSource;
372 static gboolean
373 counter_source_prepare (GSource *source,
374 gint *timeout)
376 CounterSource *csource = (CounterSource *)source;
377 gint64 now;
379 now = g_source_get_time (source);
380 if (now != last_counter_update)
382 last_counter_update = now;
383 counter++;
386 *timeout = 1;
387 return counter >= csource->timeout;
390 static gboolean
391 counter_source_dispatch (GSource *source,
392 GSourceFunc callback,
393 gpointer user_data)
395 CounterSource *csource = (CounterSource *) source;
396 gboolean again;
398 again = callback (user_data);
400 if (again)
401 csource->timeout = counter + csource->interval;
403 return again;
406 static GSourceFuncs counter_source_funcs = {
407 counter_source_prepare,
408 NULL,
409 counter_source_dispatch,
410 NULL,
413 static GSource *
414 counter_source_new (gint interval)
416 GSource *source = g_source_new (&counter_source_funcs, sizeof (CounterSource));
417 CounterSource *csource = (CounterSource *) source;
419 csource->interval = interval;
420 csource->timeout = counter + interval;
422 return source;
426 static gboolean
427 run_inner_loop (gpointer user_data)
429 GMainContext *ctx = user_data;
430 GMainLoop *inner;
431 GSource *timeout;
433 a++;
435 inner = g_main_loop_new (ctx, FALSE);
436 timeout = counter_source_new (100);
437 g_source_set_callback (timeout, quit_loop, inner, NULL);
438 g_source_attach (timeout, ctx);
439 g_source_unref (timeout);
441 g_main_loop_run (inner);
442 g_main_loop_unref (inner);
444 return G_SOURCE_CONTINUE;
447 static void
448 test_child_sources (void)
450 GMainContext *ctx;
451 GMainLoop *loop;
452 GSource *parent, *child_b, *child_c, *end;
454 ctx = g_main_context_new ();
455 loop = g_main_loop_new (ctx, FALSE);
457 a = b = c = 0;
459 parent = counter_source_new (2000);
460 g_source_set_callback (parent, run_inner_loop, ctx, NULL);
461 g_source_set_priority (parent, G_PRIORITY_LOW);
462 g_source_attach (parent, ctx);
464 child_b = counter_source_new (250);
465 g_source_set_callback (child_b, count_calls, &b, NULL);
466 g_source_add_child_source (parent, child_b);
468 child_c = counter_source_new (330);
469 g_source_set_callback (child_c, count_calls, &c, NULL);
470 g_source_set_priority (child_c, G_PRIORITY_HIGH);
471 g_source_add_child_source (parent, child_c);
473 /* Child sources always have the priority of the parent */
474 g_assert_cmpint (g_source_get_priority (parent), ==, G_PRIORITY_LOW);
475 g_assert_cmpint (g_source_get_priority (child_b), ==, G_PRIORITY_LOW);
476 g_assert_cmpint (g_source_get_priority (child_c), ==, G_PRIORITY_LOW);
477 g_source_set_priority (parent, G_PRIORITY_DEFAULT);
478 g_assert_cmpint (g_source_get_priority (parent), ==, G_PRIORITY_DEFAULT);
479 g_assert_cmpint (g_source_get_priority (child_b), ==, G_PRIORITY_DEFAULT);
480 g_assert_cmpint (g_source_get_priority (child_c), ==, G_PRIORITY_DEFAULT);
482 end = counter_source_new (1050);
483 g_source_set_callback (end, quit_loop, loop, NULL);
484 g_source_attach (end, ctx);
485 g_source_unref (end);
487 g_main_loop_run (loop);
489 /* The parent source's own timeout will never trigger, so "a" will
490 * only get incremented when "b" or "c" does. And when timeouts get
491 * blocked, they still wait the full interval next time rather than
492 * "catching up". So the timing is:
494 * 250 - b++ -> a++, run_inner_loop
495 * 330 - (c is blocked)
496 * 350 - inner_loop ends
497 * 350 - c++ belatedly -> a++, run_inner_loop
498 * 450 - inner loop ends
499 * 500 - b++ -> a++, run_inner_loop
500 * 600 - inner_loop ends
501 * 680 - c++ -> a++, run_inner_loop
502 * 750 - (b is blocked)
503 * 780 - inner loop ends
504 * 780 - b++ belatedly -> a++, run_inner_loop
505 * 880 - inner loop ends
506 * 1010 - c++ -> a++, run_inner_loop
507 * 1030 - (b is blocked)
508 * 1050 - end runs, quits outer loop, which has no effect yet
509 * 1110 - inner loop ends, a returns, outer loop exits
512 g_assert_cmpint (a, ==, 6);
513 g_assert_cmpint (b, ==, 3);
514 g_assert_cmpint (c, ==, 3);
516 g_source_destroy (parent);
517 g_source_unref (parent);
518 g_source_unref (child_b);
519 g_source_unref (child_c);
521 g_main_loop_unref (loop);
522 g_main_context_unref (ctx);
525 static void
526 test_recursive_child_sources (void)
528 GMainContext *ctx;
529 GMainLoop *loop;
530 GSource *parent, *child_b, *child_c, *end;
532 ctx = g_main_context_new ();
533 loop = g_main_loop_new (ctx, FALSE);
535 a = b = c = 0;
537 parent = counter_source_new (500);
538 g_source_set_callback (parent, count_calls, &a, NULL);
540 child_b = counter_source_new (220);
541 g_source_set_callback (child_b, count_calls, &b, NULL);
542 g_source_add_child_source (parent, child_b);
544 child_c = counter_source_new (430);
545 g_source_set_callback (child_c, count_calls, &c, NULL);
546 g_source_add_child_source (child_b, child_c);
548 g_source_attach (parent, ctx);
550 end = counter_source_new (2010);
551 g_source_set_callback (end, (GSourceFunc)g_main_loop_quit, loop, NULL);
552 g_source_attach (end, ctx);
553 g_source_unref (end);
555 g_main_loop_run (loop);
557 /* Sequence of events:
558 * 220 b (b -> 440, a -> 720)
559 * 430 c (c -> 860, b -> 650, a -> 930)
560 * 650 b (b -> 870, a -> 1150)
561 * 860 c (c -> 1290, b -> 1080, a -> 1360)
562 * 1080 b (b -> 1300, a -> 1580)
563 * 1290 c (c -> 1720, b -> 1510, a -> 1790)
564 * 1510 b (b -> 1730, a -> 2010)
565 * 1720 c (c -> 2150, b -> 1940, a -> 2220)
566 * 1940 b (b -> 2160, a -> 2440)
569 g_assert_cmpint (a, ==, 9);
570 g_assert_cmpint (b, ==, 9);
571 g_assert_cmpint (c, ==, 4);
573 g_source_destroy (parent);
574 g_source_unref (parent);
575 g_source_unref (child_b);
576 g_source_unref (child_c);
578 g_main_loop_unref (loop);
579 g_main_context_unref (ctx);
582 typedef struct {
583 GSource *parent, *old_child, *new_child;
584 GMainLoop *loop;
585 } SwappingTestData;
587 static gboolean
588 swap_sources (gpointer user_data)
590 SwappingTestData *data = user_data;
592 if (data->old_child)
594 g_source_remove_child_source (data->parent, data->old_child);
595 g_clear_pointer (&data->old_child, g_source_unref);
598 if (!data->new_child)
600 data->new_child = g_timeout_source_new (0);
601 g_source_set_callback (data->new_child, quit_loop, data->loop, NULL);
602 g_source_add_child_source (data->parent, data->new_child);
605 return G_SOURCE_CONTINUE;
608 static gboolean
609 assert_not_reached_callback (gpointer user_data)
611 g_assert_not_reached ();
613 return G_SOURCE_REMOVE;
616 static void
617 test_swapping_child_sources (void)
619 GMainContext *ctx;
620 GMainLoop *loop;
621 SwappingTestData data;
623 ctx = g_main_context_new ();
624 loop = g_main_loop_new (ctx, FALSE);
626 data.parent = counter_source_new (50);
627 data.loop = loop;
628 g_source_set_callback (data.parent, swap_sources, &data, NULL);
629 g_source_attach (data.parent, ctx);
631 data.old_child = counter_source_new (100);
632 g_source_add_child_source (data.parent, data.old_child);
633 g_source_set_callback (data.old_child, assert_not_reached_callback, NULL, NULL);
635 data.new_child = NULL;
636 g_main_loop_run (loop);
638 g_source_destroy (data.parent);
639 g_source_unref (data.parent);
640 g_source_unref (data.new_child);
642 g_main_loop_unref (loop);
643 g_main_context_unref (ctx);
646 static gboolean
647 add_source_callback (gpointer user_data)
649 GMainLoop *loop = user_data;
650 GSource *self = g_main_current_source (), *child;
651 GIOChannel *io;
653 /* It doesn't matter whether this is a valid fd or not; it never
654 * actually gets polled; the test is just checking that
655 * g_source_add_child_source() doesn't crash.
657 io = g_io_channel_unix_new (0);
658 child = g_io_create_watch (io, G_IO_IN);
659 g_source_add_child_source (self, child);
660 g_source_unref (child);
661 g_io_channel_unref (io);
663 g_main_loop_quit (loop);
664 return FALSE;
667 static void
668 test_blocked_child_sources (void)
670 GMainContext *ctx;
671 GMainLoop *loop;
672 GSource *source;
674 g_test_bug ("701283");
676 ctx = g_main_context_new ();
677 loop = g_main_loop_new (ctx, FALSE);
679 source = g_idle_source_new ();
680 g_source_set_callback (source, add_source_callback, loop, NULL);
681 g_source_attach (source, ctx);
683 g_main_loop_run (loop);
685 g_source_destroy (source);
686 g_source_unref (source);
688 g_main_loop_unref (loop);
689 g_main_context_unref (ctx);
692 typedef struct {
693 GMainContext *ctx;
694 GMainLoop *loop;
696 GSource *timeout1, *timeout2;
697 gint64 time1;
698 GTimeVal tv;
699 } TimeTestData;
701 static gboolean
702 timeout1_callback (gpointer user_data)
704 TimeTestData *data = user_data;
705 GSource *source;
706 gint64 mtime1, mtime2, time2;
708 source = g_main_current_source ();
709 g_assert (source == data->timeout1);
711 if (data->time1 == -1)
713 /* First iteration */
714 g_assert (!g_source_is_destroyed (data->timeout2));
716 mtime1 = g_get_monotonic_time ();
717 data->time1 = g_source_get_time (source);
719 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
720 g_source_get_current_time (source, &data->tv);
721 G_GNUC_END_IGNORE_DEPRECATIONS
723 /* g_source_get_time() does not change during a single callback */
724 g_usleep (1000000);
725 mtime2 = g_get_monotonic_time ();
726 time2 = g_source_get_time (source);
728 g_assert_cmpint (mtime1, <, mtime2);
729 g_assert_cmpint (data->time1, ==, time2);
731 else
733 GTimeVal tv;
735 /* Second iteration */
736 g_assert (g_source_is_destroyed (data->timeout2));
738 /* g_source_get_time() MAY change between iterations; in this
739 * case we know for sure that it did because of the g_usleep()
740 * last time.
742 time2 = g_source_get_time (source);
743 g_assert_cmpint (data->time1, <, time2);
745 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
746 g_source_get_current_time (source, &tv);
747 G_GNUC_END_IGNORE_DEPRECATIONS
749 g_assert (tv.tv_sec > data->tv.tv_sec ||
750 (tv.tv_sec == data->tv.tv_sec &&
751 tv.tv_usec > data->tv.tv_usec));
753 g_main_loop_quit (data->loop);
756 return TRUE;
759 static gboolean
760 timeout2_callback (gpointer user_data)
762 TimeTestData *data = user_data;
763 GSource *source;
764 gint64 time2, time3;
766 source = g_main_current_source ();
767 g_assert (source == data->timeout2);
769 g_assert (!g_source_is_destroyed (data->timeout1));
771 /* g_source_get_time() does not change between different sources in
772 * a single iteration of the mainloop.
774 time2 = g_source_get_time (source);
775 g_assert_cmpint (data->time1, ==, time2);
777 /* The source should still have a valid time even after being
778 * destroyed, since it's currently running.
780 g_source_destroy (source);
781 time3 = g_source_get_time (source);
782 g_assert_cmpint (time2, ==, time3);
784 return FALSE;
787 static void
788 test_source_time (void)
790 TimeTestData data;
792 data.ctx = g_main_context_new ();
793 data.loop = g_main_loop_new (data.ctx, FALSE);
795 data.timeout1 = g_timeout_source_new (0);
796 g_source_set_callback (data.timeout1, timeout1_callback, &data, NULL);
797 g_source_attach (data.timeout1, data.ctx);
799 data.timeout2 = g_timeout_source_new (0);
800 g_source_set_callback (data.timeout2, timeout2_callback, &data, NULL);
801 g_source_attach (data.timeout2, data.ctx);
803 data.time1 = -1;
805 g_main_loop_run (data.loop);
807 g_assert (!g_source_is_destroyed (data.timeout1));
808 g_assert (g_source_is_destroyed (data.timeout2));
810 g_source_destroy (data.timeout1);
811 g_source_unref (data.timeout1);
812 g_source_unref (data.timeout2);
814 g_main_loop_unref (data.loop);
815 g_main_context_unref (data.ctx);
818 typedef struct {
819 guint outstanding_ops;
820 GMainLoop *loop;
821 } TestOverflowData;
823 static gboolean
824 on_source_fired_cb (gpointer user_data)
826 TestOverflowData *data = user_data;
827 GSource *current_source;
828 GMainContext *current_context;
829 guint source_id;
831 data->outstanding_ops--;
833 current_source = g_main_current_source ();
834 current_context = g_source_get_context (current_source);
835 source_id = g_source_get_id (current_source);
836 g_assert (g_main_context_find_source_by_id (current_context, source_id) != NULL);
837 g_source_destroy (current_source);
838 g_assert (g_main_context_find_source_by_id (current_context, source_id) == NULL);
840 if (data->outstanding_ops == 0)
841 g_main_loop_quit (data->loop);
842 return FALSE;
845 static GSource *
846 add_idle_source (GMainContext *ctx,
847 TestOverflowData *data)
849 GSource *source;
851 source = g_idle_source_new ();
852 g_source_set_callback (source, on_source_fired_cb, data, NULL);
853 g_source_attach (source, ctx);
854 g_source_unref (source);
855 data->outstanding_ops++;
857 return source;
860 static void
861 test_mainloop_overflow (void)
863 GMainContext *ctx;
864 GMainLoop *loop;
865 GSource *source;
866 TestOverflowData data;
867 guint i;
869 g_test_bug ("687098");
871 memset (&data, 0, sizeof (data));
873 ctx = GLIB_PRIVATE_CALL (g_main_context_new_with_next_id) (G_MAXUINT-1);
875 loop = g_main_loop_new (ctx, TRUE);
876 data.outstanding_ops = 0;
877 data.loop = loop;
879 source = add_idle_source (ctx, &data);
880 g_assert_cmpint (source->source_id, ==, G_MAXUINT-1);
882 source = add_idle_source (ctx, &data);
883 g_assert_cmpint (source->source_id, ==, G_MAXUINT);
885 source = add_idle_source (ctx, &data);
886 g_assert_cmpint (source->source_id, !=, 0);
888 /* Now, a lot more sources */
889 for (i = 0; i < 50; i++)
891 source = add_idle_source (ctx, &data);
892 g_assert_cmpint (source->source_id, !=, 0);
895 g_main_loop_run (loop);
896 g_assert_cmpint (data.outstanding_ops, ==, 0);
898 g_main_loop_unref (loop);
899 g_main_context_unref (ctx);
902 static volatile gint ready_time_dispatched;
904 static gboolean
905 ready_time_dispatch (GSource *source,
906 GSourceFunc callback,
907 gpointer user_data)
909 g_atomic_int_set (&ready_time_dispatched, TRUE);
911 g_source_set_ready_time (source, -1);
913 return TRUE;
916 static gpointer
917 run_context (gpointer user_data)
919 g_main_loop_run (user_data);
921 return NULL;
924 static void
925 test_ready_time (void)
927 GThread *thread;
928 GSource *source;
929 GSourceFuncs source_funcs = {
930 NULL, NULL, ready_time_dispatch
932 GMainLoop *loop;
934 source = g_source_new (&source_funcs, sizeof (GSource));
935 g_source_attach (source, NULL);
936 g_source_unref (source);
938 /* Unfortunately we can't do too many things with respect to timing
939 * without getting into trouble on slow systems or heavily loaded
940 * builders.
942 * We can test that the basics are working, though.
945 /* A source with no ready time set should not fire */
946 g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
947 while (g_main_context_iteration (NULL, FALSE));
948 g_assert (!ready_time_dispatched);
950 /* The ready time should not have been changed */
951 g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
953 /* Of course this shouldn't change anything either */
954 g_source_set_ready_time (source, -1);
955 g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
957 /* A source with a ready time set to tomorrow should not fire on any
958 * builder, no matter how badly loaded...
960 g_source_set_ready_time (source, g_get_monotonic_time () + G_TIME_SPAN_DAY);
961 while (g_main_context_iteration (NULL, FALSE));
962 g_assert (!ready_time_dispatched);
963 /* Make sure it didn't get reset */
964 g_assert_cmpint (g_source_get_ready_time (source), !=, -1);
966 /* Ready time of -1 -> don't fire */
967 g_source_set_ready_time (source, -1);
968 while (g_main_context_iteration (NULL, FALSE));
969 g_assert (!ready_time_dispatched);
970 /* Not reset, but should still be -1 from above */
971 g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
973 /* A ready time of the current time should fire immediately */
974 g_source_set_ready_time (source, g_get_monotonic_time ());
975 while (g_main_context_iteration (NULL, FALSE));
976 g_assert (ready_time_dispatched);
977 ready_time_dispatched = FALSE;
978 /* Should have gotten reset by the handler function */
979 g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
981 /* As well as one in the recent past... */
982 g_source_set_ready_time (source, g_get_monotonic_time () - G_TIME_SPAN_SECOND);
983 while (g_main_context_iteration (NULL, FALSE));
984 g_assert (ready_time_dispatched);
985 ready_time_dispatched = FALSE;
986 g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
988 /* Zero is the 'official' way to get a source to fire immediately */
989 g_source_set_ready_time (source, 0);
990 while (g_main_context_iteration (NULL, FALSE));
991 g_assert (ready_time_dispatched);
992 ready_time_dispatched = FALSE;
993 g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
995 /* Now do some tests of cross-thread wakeups.
997 * Make sure it wakes up right away from the start.
999 g_source_set_ready_time (source, 0);
1000 loop = g_main_loop_new (NULL, FALSE);
1001 thread = g_thread_new ("context thread", run_context, loop);
1002 while (!g_atomic_int_get (&ready_time_dispatched));
1004 /* Now let's see if it can wake up from sleeping. */
1005 g_usleep (G_TIME_SPAN_SECOND / 2);
1006 g_atomic_int_set (&ready_time_dispatched, FALSE);
1007 g_source_set_ready_time (source, 0);
1008 while (!g_atomic_int_get (&ready_time_dispatched));
1010 /* kill the thread */
1011 g_main_loop_quit (loop);
1012 g_thread_join (thread);
1013 g_main_loop_unref (loop);
1015 g_source_destroy (source);
1018 static void
1019 test_wakeup(void)
1021 GMainContext *ctx;
1022 int i;
1024 ctx = g_main_context_new ();
1026 /* run a random large enough number of times because
1027 * main contexts tend to wake up a few times after creation.
1029 for (i = 0; i < 100; i++)
1031 /* This is the invariant we care about:
1032 * g_main_context_wakeup(ctx,) ensures that the next call to
1033 * g_main_context_iteration (ctx, TRUE) returns and doesn't
1034 * block.
1035 * This is important in threaded apps where we might not know
1036 * if the thread calls g_main_context_wakeup() before or after
1037 * we enter g_main_context_iteration().
1039 g_main_context_wakeup (ctx);
1040 g_main_context_iteration (ctx, TRUE);
1043 g_main_context_unref (ctx);
1046 static void
1047 test_remove_invalid (void)
1049 g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "Source ID 3000000000 was not found*");
1050 g_source_remove (3000000000u);
1051 g_test_assert_expected_messages ();
1054 static gboolean
1055 trivial_prepare (GSource *source,
1056 gint *timeout)
1058 *timeout = 0;
1059 return TRUE;
1062 static gint n_finalized;
1064 static void
1065 trivial_finalize (GSource *source)
1067 n_finalized++;
1070 static void
1071 test_unref_while_pending (void)
1073 static GSourceFuncs funcs = { trivial_prepare, NULL, NULL, trivial_finalize };
1074 GMainContext *context;
1075 GSource *source;
1077 context = g_main_context_new ();
1079 source = g_source_new (&funcs, sizeof (GSource));
1080 g_source_attach (source, context);
1081 g_source_unref (source);
1083 /* Do incomplete main iteration -- get a pending source but don't dispatch it. */
1084 g_main_context_prepare (context, NULL);
1085 g_main_context_query (context, 0, NULL, NULL, 0);
1086 g_main_context_check (context, 1000, NULL, 0);
1088 /* Destroy the context */
1089 g_main_context_unref (context);
1091 /* Make sure we didn't leak the source */
1092 g_assert_cmpint (n_finalized, ==, 1);
1095 #ifdef G_OS_UNIX
1097 #include <glib-unix.h>
1098 #include <unistd.h>
1100 static gchar zeros[1024];
1102 static gsize
1103 fill_a_pipe (gint fd)
1105 gsize written = 0;
1106 GPollFD pfd;
1108 pfd.fd = fd;
1109 pfd.events = G_IO_OUT;
1110 while (g_poll (&pfd, 1, 0) == 1)
1111 /* we should never see -1 here */
1112 written += write (fd, zeros, sizeof zeros);
1114 return written;
1117 static gboolean
1118 write_bytes (gint fd,
1119 GIOCondition condition,
1120 gpointer user_data)
1122 gssize *to_write = user_data;
1123 gint limit;
1125 if (*to_write == 0)
1126 return FALSE;
1128 /* Detect if we run before we should */
1129 g_assert (*to_write >= 0);
1131 limit = MIN (*to_write, sizeof zeros);
1132 *to_write -= write (fd, zeros, limit);
1134 return TRUE;
1137 static gboolean
1138 read_bytes (gint fd,
1139 GIOCondition condition,
1140 gpointer user_data)
1142 static gchar buffer[1024];
1143 gssize *to_read = user_data;
1145 *to_read -= read (fd, buffer, sizeof buffer);
1147 /* The loop will exit when there is nothing else to read, then we will
1148 * use g_source_remove() to destroy this source.
1150 return TRUE;
1153 #ifdef G_OS_UNIX
1154 static void
1155 test_unix_fd (void)
1157 gssize to_write = -1;
1158 gssize to_read;
1159 gint fds[2];
1160 gint a, b;
1161 gint s;
1162 GSource *source_a;
1163 GSource *source_b;
1165 s = pipe (fds);
1166 g_assert (s == 0);
1168 to_read = fill_a_pipe (fds[1]);
1169 /* write at higher priority to keep the pipe full... */
1170 a = g_unix_fd_add_full (G_PRIORITY_HIGH, fds[1], G_IO_OUT, write_bytes, &to_write, NULL);
1171 source_a = g_source_ref (g_main_context_find_source_by_id (NULL, a));
1172 /* make sure no 'writes' get dispatched yet */
1173 while (g_main_context_iteration (NULL, FALSE));
1175 to_read += 128 * 1024 * 1024;
1176 to_write = 128 * 1024 * 1024;
1177 b = g_unix_fd_add (fds[0], G_IO_IN, read_bytes, &to_read);
1178 source_b = g_source_ref (g_main_context_find_source_by_id (NULL, b));
1180 /* Assuming the kernel isn't internally 'laggy' then there will always
1181 * be either data to read or room in which to write. That will keep
1182 * the loop running until all data has been read and written.
1184 while (TRUE)
1186 gssize to_write_was = to_write;
1187 gssize to_read_was = to_read;
1189 if (!g_main_context_iteration (NULL, FALSE))
1190 break;
1192 /* Since the sources are at different priority, only one of them
1193 * should possibly have run.
1195 g_assert (to_write == to_write_was || to_read == to_read_was);
1198 g_assert (to_write == 0);
1199 g_assert (to_read == 0);
1201 /* 'a' is already removed by itself */
1202 g_assert (g_source_is_destroyed (source_a));
1203 g_source_unref (source_a);
1204 g_source_remove (b);
1205 g_assert (g_source_is_destroyed (source_b));
1206 g_source_unref (source_b);
1207 close (fds[1]);
1208 close (fds[0]);
1210 #endif
1212 static void
1213 assert_main_context_state (gint n_to_poll,
1214 ...)
1216 GMainContext *context;
1217 gboolean consumed[10] = { };
1218 GPollFD poll_fds[10];
1219 gboolean acquired;
1220 gboolean immediate;
1221 gint max_priority;
1222 gint timeout;
1223 gint n;
1224 gint i, j;
1225 va_list ap;
1227 context = g_main_context_default ();
1229 acquired = g_main_context_acquire (context);
1230 g_assert (acquired);
1232 immediate = g_main_context_prepare (context, &max_priority);
1233 g_assert (!immediate);
1234 n = g_main_context_query (context, max_priority, &timeout, poll_fds, 10);
1235 g_assert_cmpint (n, ==, n_to_poll + 1); /* one will be the gwakeup */
1237 va_start (ap, n_to_poll);
1238 for (i = 0; i < n_to_poll; i++)
1240 gint expected_fd = va_arg (ap, gint);
1241 GIOCondition expected_events = va_arg (ap, GIOCondition);
1242 GIOCondition report_events = va_arg (ap, GIOCondition);
1244 for (j = 0; j < n; j++)
1245 if (!consumed[j] && poll_fds[j].fd == expected_fd && poll_fds[j].events == expected_events)
1247 poll_fds[j].revents = report_events;
1248 consumed[j] = TRUE;
1249 break;
1252 if (j == n)
1253 g_error ("Unable to find fd %d (index %d) with events 0x%x", expected_fd, i, (guint) expected_events);
1255 va_end (ap);
1257 /* find the gwakeup, flag as non-ready */
1258 for (i = 0; i < n; i++)
1259 if (!consumed[i])
1260 poll_fds[i].revents = 0;
1262 if (g_main_context_check (context, max_priority, poll_fds, n))
1263 g_main_context_dispatch (context);
1265 g_main_context_release (context);
1268 static gboolean
1269 flag_bool (gint fd,
1270 GIOCondition condition,
1271 gpointer user_data)
1273 gboolean *flag = user_data;
1275 *flag = TRUE;
1277 return TRUE;
1280 static void
1281 test_unix_fd_source (void)
1283 GSource *out_source;
1284 GSource *in_source;
1285 GSource *source;
1286 gboolean out, in;
1287 gint fds[2];
1288 gint s;
1290 assert_main_context_state (0);
1292 s = pipe (fds);
1293 g_assert (s == 0);
1295 source = g_unix_fd_source_new (fds[1], G_IO_OUT);
1296 g_source_attach (source, NULL);
1298 /* Check that a source with no callback gets successfully detached
1299 * with a warning printed.
1301 g_test_expect_message ("GLib", G_LOG_LEVEL_WARNING, "*GUnixFDSource dispatched without callback*");
1302 while (g_main_context_iteration (NULL, FALSE));
1303 g_test_assert_expected_messages ();
1304 g_assert (g_source_is_destroyed (source));
1305 g_source_unref (source);
1307 out = in = FALSE;
1308 out_source = g_unix_fd_source_new (fds[1], G_IO_OUT);
1309 /* -Wcast-function-type complains about casting 'flag_bool' to GSourceFunc.
1310 * GCC has no way of knowing that it will be cast back to GUnixFDSourceFunc
1311 * before being called. Although GLib itself is not compiled with
1312 * -Wcast-function-type, applications that use GLib may well be (since
1313 * -Wextra includes it), so we provide a G_SOURCE_FUNC() macro to suppress
1314 * the warning. We check that it works here.
1316 #if G_GNUC_CHECK_VERSION(8, 0)
1317 #pragma GCC diagnostic push
1318 #pragma GCC diagnostic error "-Wcast-function-type"
1319 #endif
1320 g_source_set_callback (out_source, G_SOURCE_FUNC (flag_bool), &out, NULL);
1321 #if G_GNUC_CHECK_VERSION(8, 0)
1322 #pragma GCC diagnostic pop
1323 #endif
1324 g_source_attach (out_source, NULL);
1325 assert_main_context_state (1,
1326 fds[1], G_IO_OUT, 0);
1327 g_assert (!in && !out);
1329 in_source = g_unix_fd_source_new (fds[0], G_IO_IN);
1330 g_source_set_callback (in_source, (GSourceFunc) flag_bool, &in, NULL);
1331 g_source_set_priority (in_source, G_PRIORITY_DEFAULT_IDLE);
1332 g_source_attach (in_source, NULL);
1333 assert_main_context_state (2,
1334 fds[0], G_IO_IN, G_IO_IN,
1335 fds[1], G_IO_OUT, G_IO_OUT);
1336 /* out is higher priority so only it should fire */
1337 g_assert (!in && out);
1339 /* raise the priority of the in source to higher than out*/
1340 in = out = FALSE;
1341 g_source_set_priority (in_source, G_PRIORITY_HIGH);
1342 assert_main_context_state (2,
1343 fds[0], G_IO_IN, G_IO_IN,
1344 fds[1], G_IO_OUT, G_IO_OUT);
1345 g_assert (in && !out);
1347 /* now, let them be equal */
1348 in = out = FALSE;
1349 g_source_set_priority (in_source, G_PRIORITY_DEFAULT);
1350 assert_main_context_state (2,
1351 fds[0], G_IO_IN, G_IO_IN,
1352 fds[1], G_IO_OUT, G_IO_OUT);
1353 g_assert (in && out);
1355 g_source_destroy (out_source);
1356 g_source_unref (out_source);
1357 g_source_destroy (in_source);
1358 g_source_unref (in_source);
1359 close (fds[1]);
1360 close (fds[0]);
1363 typedef struct
1365 GSource parent;
1366 gboolean flagged;
1367 } FlagSource;
1369 static gboolean
1370 return_true (GSource *source, GSourceFunc callback, gpointer user_data)
1372 FlagSource *flag_source = (FlagSource *) source;
1374 flag_source->flagged = TRUE;
1376 return TRUE;
1379 #define assert_flagged(s) g_assert (((FlagSource *) (s))->flagged);
1380 #define assert_not_flagged(s) g_assert (!((FlagSource *) (s))->flagged);
1381 #define clear_flag(s) ((FlagSource *) (s))->flagged = 0
1383 static void
1384 test_source_unix_fd_api (void)
1386 GSourceFuncs no_funcs = {
1387 NULL, NULL, return_true
1389 GSource *source_a;
1390 GSource *source_b;
1391 gpointer tag1, tag2;
1392 gint fds_a[2];
1393 gint fds_b[2];
1395 pipe (fds_a);
1396 pipe (fds_b);
1398 source_a = g_source_new (&no_funcs, sizeof (FlagSource));
1399 source_b = g_source_new (&no_funcs, sizeof (FlagSource));
1401 /* attach a source with more than one fd */
1402 g_source_add_unix_fd (source_a, fds_a[0], G_IO_IN);
1403 g_source_add_unix_fd (source_a, fds_a[1], G_IO_OUT);
1404 g_source_attach (source_a, NULL);
1405 assert_main_context_state (2,
1406 fds_a[0], G_IO_IN, 0,
1407 fds_a[1], G_IO_OUT, 0);
1408 assert_not_flagged (source_a);
1410 /* attach a higher priority source with no fds */
1411 g_source_set_priority (source_b, G_PRIORITY_HIGH);
1412 g_source_attach (source_b, NULL);
1413 assert_main_context_state (2,
1414 fds_a[0], G_IO_IN, G_IO_IN,
1415 fds_a[1], G_IO_OUT, 0);
1416 assert_flagged (source_a);
1417 assert_not_flagged (source_b);
1418 clear_flag (source_a);
1420 /* add some fds to the second source, while attached */
1421 tag1 = g_source_add_unix_fd (source_b, fds_b[0], G_IO_IN);
1422 tag2 = g_source_add_unix_fd (source_b, fds_b[1], G_IO_OUT);
1423 assert_main_context_state (4,
1424 fds_a[0], G_IO_IN, 0,
1425 fds_a[1], G_IO_OUT, G_IO_OUT,
1426 fds_b[0], G_IO_IN, 0,
1427 fds_b[1], G_IO_OUT, G_IO_OUT);
1428 /* only 'b' (higher priority) should have dispatched */
1429 assert_not_flagged (source_a);
1430 assert_flagged (source_b);
1431 clear_flag (source_b);
1433 /* change our events on b to the same as they were before */
1434 g_source_modify_unix_fd (source_b, tag1, G_IO_IN);
1435 g_source_modify_unix_fd (source_b, tag2, G_IO_OUT);
1436 assert_main_context_state (4,
1437 fds_a[0], G_IO_IN, 0,
1438 fds_a[1], G_IO_OUT, G_IO_OUT,
1439 fds_b[0], G_IO_IN, 0,
1440 fds_b[1], G_IO_OUT, G_IO_OUT);
1441 assert_not_flagged (source_a);
1442 assert_flagged (source_b);
1443 clear_flag (source_b);
1445 /* now reverse them */
1446 g_source_modify_unix_fd (source_b, tag1, G_IO_OUT);
1447 g_source_modify_unix_fd (source_b, tag2, G_IO_IN);
1448 assert_main_context_state (4,
1449 fds_a[0], G_IO_IN, 0,
1450 fds_a[1], G_IO_OUT, G_IO_OUT,
1451 fds_b[0], G_IO_OUT, 0,
1452 fds_b[1], G_IO_IN, 0);
1453 /* 'b' had no events, so 'a' can go this time */
1454 assert_flagged (source_a);
1455 assert_not_flagged (source_b);
1456 clear_flag (source_a);
1458 /* remove one of the fds from 'b' */
1459 g_source_remove_unix_fd (source_b, tag1);
1460 assert_main_context_state (3,
1461 fds_a[0], G_IO_IN, 0,
1462 fds_a[1], G_IO_OUT, 0,
1463 fds_b[1], G_IO_IN, 0);
1464 assert_not_flagged (source_a);
1465 assert_not_flagged (source_b);
1467 /* remove the other */
1468 g_source_remove_unix_fd (source_b, tag2);
1469 assert_main_context_state (2,
1470 fds_a[0], G_IO_IN, 0,
1471 fds_a[1], G_IO_OUT, 0);
1472 assert_not_flagged (source_a);
1473 assert_not_flagged (source_b);
1475 /* destroy the sources */
1476 g_source_destroy (source_a);
1477 g_source_destroy (source_b);
1478 assert_main_context_state (0);
1480 g_source_unref (source_a);
1481 g_source_unref (source_b);
1482 close (fds_a[0]);
1483 close (fds_a[1]);
1484 close (fds_b[0]);
1485 close (fds_b[1]);
1488 static gboolean
1489 unixfd_quit_loop (gint fd,
1490 GIOCondition condition,
1491 gpointer user_data)
1493 GMainLoop *loop = user_data;
1495 g_main_loop_quit (loop);
1497 return FALSE;
1500 static void
1501 test_unix_file_poll (void)
1503 gint fd;
1504 GSource *source;
1505 GMainLoop *loop;
1507 fd = open ("/dev/null", O_RDONLY);
1508 g_assert (fd >= 0);
1510 loop = g_main_loop_new (NULL, FALSE);
1512 source = g_unix_fd_source_new (fd, G_IO_IN);
1513 g_source_set_callback (source, (GSourceFunc) unixfd_quit_loop, loop, NULL);
1514 g_source_attach (source, NULL);
1516 /* Should not block */
1517 g_main_loop_run (loop);
1519 g_source_destroy (source);
1521 assert_main_context_state (0);
1523 g_source_unref (source);
1525 g_main_loop_unref (loop);
1527 close (fd);
1530 #endif
1532 #ifdef G_OS_UNIX
1533 static gboolean
1534 timeout_cb (gpointer data)
1536 GMainLoop *loop = data;
1537 GMainContext *context;
1539 context = g_main_loop_get_context (loop);
1540 g_assert (g_main_loop_is_running (loop));
1541 g_assert (g_main_context_is_owner (context));
1543 g_main_loop_quit (loop);
1545 return G_SOURCE_REMOVE;
1548 static gpointer
1549 threadf (gpointer data)
1551 GMainContext *context = data;
1552 GMainLoop *loop;
1553 GSource *source;
1555 loop = g_main_loop_new (context, FALSE);
1556 source = g_timeout_source_new (250);
1557 g_source_set_callback (source, timeout_cb, loop, NULL);
1558 g_source_attach (source, context);
1559 g_source_unref (source);
1561 g_main_loop_run (loop);
1563 g_main_loop_unref (loop);
1565 return NULL;
1568 static void
1569 test_mainloop_wait (void)
1571 GMainContext *context;
1572 GThread *t1, *t2;
1574 context = g_main_context_new ();
1576 t1 = g_thread_new ("t1", threadf, context);
1577 t2 = g_thread_new ("t2", threadf, context);
1579 g_thread_join (t1);
1580 g_thread_join (t2);
1582 g_main_context_unref (context);
1584 #endif
1586 static gboolean
1587 nfds_in_cb (GIOChannel *io,
1588 GIOCondition condition,
1589 gpointer user_data)
1591 gboolean *in_cb_ran = user_data;
1593 *in_cb_ran = TRUE;
1594 g_assert_cmpint (condition, ==, G_IO_IN);
1595 return FALSE;
1598 static gboolean
1599 nfds_out_cb (GIOChannel *io,
1600 GIOCondition condition,
1601 gpointer user_data)
1603 gboolean *out_cb_ran = user_data;
1605 *out_cb_ran = TRUE;
1606 g_assert_cmpint (condition, ==, G_IO_OUT);
1607 return FALSE;
1610 static gboolean
1611 nfds_out_low_cb (GIOChannel *io,
1612 GIOCondition condition,
1613 gpointer user_data)
1615 g_assert_not_reached ();
1616 return FALSE;
1619 static void
1620 test_nfds (void)
1622 GMainContext *ctx;
1623 GPollFD out_fds[3];
1624 gint fd, nfds;
1625 GIOChannel *io;
1626 GSource *source1, *source2, *source3;
1627 gboolean source1_ran = FALSE, source3_ran = FALSE;
1628 gchar *tmpfile;
1629 GError *error = NULL;
1631 ctx = g_main_context_new ();
1632 nfds = g_main_context_query (ctx, G_MAXINT, NULL,
1633 out_fds, G_N_ELEMENTS (out_fds));
1634 /* An "empty" GMainContext will have a single GPollFD, for its
1635 * internal GWakeup.
1637 g_assert_cmpint (nfds, ==, 1);
1639 fd = g_file_open_tmp (NULL, &tmpfile, &error);
1640 g_assert_no_error (error);
1642 io = g_io_channel_unix_new (fd);
1643 #ifdef G_OS_WIN32
1644 /* The fd in the pollfds won't be the same fd we passed in */
1645 g_io_channel_win32_make_pollfd (io, G_IO_IN, out_fds);
1646 fd = out_fds[0].fd;
1647 #endif
1649 /* Add our first pollfd */
1650 source1 = g_io_create_watch (io, G_IO_IN);
1651 g_source_set_priority (source1, G_PRIORITY_DEFAULT);
1652 g_source_set_callback (source1, (GSourceFunc) nfds_in_cb,
1653 &source1_ran, NULL);
1654 g_source_attach (source1, ctx);
1656 nfds = g_main_context_query (ctx, G_MAXINT, NULL,
1657 out_fds, G_N_ELEMENTS (out_fds));
1658 g_assert_cmpint (nfds, ==, 2);
1659 if (out_fds[0].fd == fd)
1660 g_assert_cmpint (out_fds[0].events, ==, G_IO_IN);
1661 else if (out_fds[1].fd == fd)
1662 g_assert_cmpint (out_fds[1].events, ==, G_IO_IN);
1663 else
1664 g_assert_not_reached ();
1666 /* Add a second pollfd with the same fd but different event, and
1667 * lower priority.
1669 source2 = g_io_create_watch (io, G_IO_OUT);
1670 g_source_set_priority (source2, G_PRIORITY_LOW);
1671 g_source_set_callback (source2, (GSourceFunc) nfds_out_low_cb,
1672 NULL, NULL);
1673 g_source_attach (source2, ctx);
1675 /* g_main_context_query() should still return only 2 pollfds,
1676 * one of which has our fd, and a combined events field.
1678 nfds = g_main_context_query (ctx, G_MAXINT, NULL,
1679 out_fds, G_N_ELEMENTS (out_fds));
1680 g_assert_cmpint (nfds, ==, 2);
1681 if (out_fds[0].fd == fd)
1682 g_assert_cmpint (out_fds[0].events, ==, G_IO_IN | G_IO_OUT);
1683 else if (out_fds[1].fd == fd)
1684 g_assert_cmpint (out_fds[1].events, ==, G_IO_IN | G_IO_OUT);
1685 else
1686 g_assert_not_reached ();
1688 /* But if we query with a max priority, we won't see the
1689 * lower-priority one.
1691 nfds = g_main_context_query (ctx, G_PRIORITY_DEFAULT, NULL,
1692 out_fds, G_N_ELEMENTS (out_fds));
1693 g_assert_cmpint (nfds, ==, 2);
1694 if (out_fds[0].fd == fd)
1695 g_assert_cmpint (out_fds[0].events, ==, G_IO_IN);
1696 else if (out_fds[1].fd == fd)
1697 g_assert_cmpint (out_fds[1].events, ==, G_IO_IN);
1698 else
1699 g_assert_not_reached ();
1701 /* Third pollfd */
1702 source3 = g_io_create_watch (io, G_IO_OUT);
1703 g_source_set_priority (source3, G_PRIORITY_DEFAULT);
1704 g_source_set_callback (source3, (GSourceFunc) nfds_out_cb,
1705 &source3_ran, NULL);
1706 g_source_attach (source3, ctx);
1708 nfds = g_main_context_query (ctx, G_MAXINT, NULL,
1709 out_fds, G_N_ELEMENTS (out_fds));
1710 g_assert_cmpint (nfds, ==, 2);
1711 if (out_fds[0].fd == fd)
1712 g_assert_cmpint (out_fds[0].events, ==, G_IO_IN | G_IO_OUT);
1713 else if (out_fds[1].fd == fd)
1714 g_assert_cmpint (out_fds[1].events, ==, G_IO_IN | G_IO_OUT);
1715 else
1716 g_assert_not_reached ();
1718 /* Now actually iterate the loop; the fd should be readable and
1719 * writable, so source1 and source3 should be triggered, but *not*
1720 * source2, since it's lower priority than them. (Though on
1721 * G_OS_WIN32, source3 doesn't get triggered, probably because of
1722 * giowin32 weirdness...)
1724 g_main_context_iteration (ctx, FALSE);
1726 g_assert (source1_ran);
1727 #ifndef G_OS_WIN32
1728 g_assert (source3_ran);
1729 #endif
1731 g_source_destroy (source1);
1732 g_source_unref (source1);
1733 g_source_destroy (source2);
1734 g_source_unref (source2);
1735 g_source_destroy (source3);
1736 g_source_unref (source3);
1738 g_io_channel_unref (io);
1739 remove (tmpfile);
1740 g_free (tmpfile);
1742 g_main_context_unref (ctx);
1746 main (int argc, char *argv[])
1748 g_test_init (&argc, &argv, NULL);
1749 g_test_bug_base ("http://bugzilla.gnome.org/");
1751 g_test_add_func ("/maincontext/basic", test_maincontext_basic);
1752 g_test_add_func ("/mainloop/basic", test_mainloop_basic);
1753 g_test_add_func ("/mainloop/timeouts", test_timeouts);
1754 g_test_add_func ("/mainloop/priorities", test_priorities);
1755 g_test_add_func ("/mainloop/invoke", test_invoke);
1756 g_test_add_func ("/mainloop/child_sources", test_child_sources);
1757 g_test_add_func ("/mainloop/recursive_child_sources", test_recursive_child_sources);
1758 g_test_add_func ("/mainloop/swapping_child_sources", test_swapping_child_sources);
1759 g_test_add_func ("/mainloop/blocked_child_sources", test_blocked_child_sources);
1760 g_test_add_func ("/mainloop/source_time", test_source_time);
1761 g_test_add_func ("/mainloop/overflow", test_mainloop_overflow);
1762 g_test_add_func ("/mainloop/ready-time", test_ready_time);
1763 g_test_add_func ("/mainloop/wakeup", test_wakeup);
1764 g_test_add_func ("/mainloop/remove-invalid", test_remove_invalid);
1765 g_test_add_func ("/mainloop/unref-while-pending", test_unref_while_pending);
1766 #ifdef G_OS_UNIX
1767 g_test_add_func ("/mainloop/unix-fd", test_unix_fd);
1768 g_test_add_func ("/mainloop/unix-fd-source", test_unix_fd_source);
1769 g_test_add_func ("/mainloop/source-unix-fd-api", test_source_unix_fd_api);
1770 g_test_add_func ("/mainloop/wait", test_mainloop_wait);
1771 g_test_add_func ("/mainloop/unix-file-poll", test_unix_file_poll);
1772 #endif
1773 g_test_add_func ("/mainloop/nfds", test_nfds);
1775 return g_test_run ();