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.
24
#include "glib-private.h"
27
static gboolean cb (gpointer data)
32
static gboolean prepare (GSource *source, gint *time)
36
static gboolean check (GSource *source)
40
static gboolean dispatch (GSource *source, GSourceFunc cb, gpointer date)
45
GSourceFuncs funcs = {
53
test_maincontext_basic (void)
58
gpointer data = &funcs;
60
ctx = g_main_context_new ();
62
g_assert (!g_main_context_pending (ctx));
63
g_assert (!g_main_context_iteration (ctx, FALSE));
65
source = g_source_new (&funcs, sizeof (GSource));
66
g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_DEFAULT);
67
g_assert (!g_source_is_destroyed (source));
69
g_assert (!g_source_get_can_recurse (source));
70
g_assert (g_source_get_name (source) == NULL);
72
g_source_set_can_recurse (source, TRUE);
73
g_source_set_name (source, "d");
75
g_assert (g_source_get_can_recurse (source));
76
g_assert_cmpstr (g_source_get_name (source), ==, "d");
78
g_assert (g_main_context_find_source_by_user_data (ctx, NULL) == NULL);
79
g_assert (g_main_context_find_source_by_funcs_user_data (ctx, &funcs, NULL) == NULL);
81
id = g_source_attach (source, ctx);
82
g_assert_cmpint (g_source_get_id (source), ==, id);
83
g_assert (g_main_context_find_source_by_id (ctx, id) == source);
85
g_source_set_priority (source, G_PRIORITY_HIGH);
86
g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_HIGH);
88
g_source_destroy (source);
89
g_assert (g_source_get_context (source) == ctx);
90
g_assert (g_main_context_find_source_by_id (ctx, id) == NULL);
92
g_main_context_unref (ctx);
94
if (g_test_undefined ())
96
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
97
"*assertion*source->context != NULL*failed*");
98
g_assert (g_source_get_context (source) == NULL);
99
g_test_assert_expected_messages ();
102
g_source_unref (source);
104
ctx = g_main_context_default ();
105
source = g_source_new (&funcs, sizeof (GSource));
106
g_source_set_funcs (source, &funcs);
107
g_source_set_callback (source, cb, data, NULL);
108
id = g_source_attach (source, ctx);
109
g_source_unref (source);
110
g_source_set_name_by_id (id, "e");
111
g_assert_cmpstr (g_source_get_name (source), ==, "e");
112
g_assert (g_source_get_context (source) == ctx);
113
g_assert (g_source_remove_by_funcs_user_data (&funcs, data));
115
source = g_source_new (&funcs, sizeof (GSource));
116
g_source_set_funcs (source, &funcs);
117
g_source_set_callback (source, cb, data, NULL);
118
id = g_source_attach (source, ctx);
119
g_source_unref (source);
120
g_assert (g_source_remove_by_user_data (data));
122
g_idle_add (cb, data);
123
g_assert (g_idle_remove_by_data (data));
127
test_mainloop_basic (void)
132
loop = g_main_loop_new (NULL, FALSE);
134
g_assert (!g_main_loop_is_running (loop));
136
g_main_loop_ref (loop);
138
ctx = g_main_loop_get_context (loop);
139
g_assert (ctx == g_main_context_default ());
141
g_main_loop_unref (loop);
143
g_assert_cmpint (g_main_depth (), ==, 0);
145
g_main_loop_unref (loop);
153
count_calls (gpointer data)
171
ctx = g_main_context_new ();
172
loop = g_main_loop_new (ctx, FALSE);
174
source = g_timeout_source_new (100);
175
g_source_set_callback (source, count_calls, &a, NULL);
176
g_source_attach (source, ctx);
177
g_source_unref (source);
179
source = g_timeout_source_new (250);
180
g_source_set_callback (source, count_calls, &b, NULL);
181
g_source_attach (source, ctx);
182
g_source_unref (source);
184
source = g_timeout_source_new (330);
185
g_source_set_callback (source, count_calls, &c, NULL);
186
g_source_attach (source, ctx);
187
g_source_unref (source);
189
source = g_timeout_source_new (1050);
190
g_source_set_callback (source, (GSourceFunc)g_main_loop_quit, loop, NULL);
191
g_source_attach (source, ctx);
192
g_source_unref (source);
194
g_main_loop_run (loop);
196
/* this is a race condition; under some circumstances we might not get 10
197
* 100ms runs in 1050 ms, so consider 9 as "close enough" */
198
g_assert_cmpint (a, >=, 9);
199
g_assert_cmpint (a, <=, 10);
200
g_assert_cmpint (b, ==, 4);
201
g_assert_cmpint (c, ==, 3);
203
g_main_loop_unref (loop);
204
g_main_context_unref (ctx);
208
test_priorities (void)
216
ctx = g_main_context_new ();
218
sourcea = g_idle_source_new ();
219
g_source_set_callback (sourcea, count_calls, &a, NULL);
220
g_source_set_priority (sourcea, 1);
221
g_source_attach (sourcea, ctx);
222
g_source_unref (sourcea);
224
sourceb = g_idle_source_new ();
225
g_source_set_callback (sourceb, count_calls, &b, NULL);
226
g_source_set_priority (sourceb, 0);
227
g_source_attach (sourceb, ctx);
228
g_source_unref (sourceb);
230
g_assert (g_main_context_pending (ctx));
231
g_assert (g_main_context_iteration (ctx, FALSE));
232
g_assert_cmpint (a, ==, 0);
233
g_assert_cmpint (b, ==, 1);
235
g_assert (g_main_context_iteration (ctx, FALSE));
236
g_assert_cmpint (a, ==, 0);
237
g_assert_cmpint (b, ==, 2);
239
g_source_destroy (sourceb);
241
g_assert (g_main_context_iteration (ctx, FALSE));
242
g_assert_cmpint (a, ==, 1);
243
g_assert_cmpint (b, ==, 2);
245
g_assert (g_main_context_pending (ctx));
246
g_source_destroy (sourcea);
247
g_assert (!g_main_context_pending (ctx));
249
g_main_context_unref (ctx);
253
quit_loop (gpointer data)
255
GMainLoop *loop = data;
257
g_main_loop_quit (loop);
259
return G_SOURCE_REMOVE;
268
g_assert (data == g_thread_self ());
276
call_func (gpointer data)
278
func (g_thread_self ());
280
return G_SOURCE_REMOVE;
285
static gboolean thread_ready;
288
thread_func (gpointer data)
290
GMainContext *ctx = data;
294
g_main_context_push_thread_default (ctx);
295
loop = g_main_loop_new (ctx, FALSE);
297
g_mutex_lock (&mutex);
299
g_cond_signal (&cond);
300
g_mutex_unlock (&mutex);
302
source = g_timeout_source_new (500);
303
g_source_set_callback (source, quit_loop, loop, NULL);
304
g_source_attach (source, ctx);
305
g_source_unref (source);
307
g_main_loop_run (loop);
309
g_main_context_pop_thread_default (ctx);
310
g_main_loop_unref (loop);
323
/* this one gets invoked directly */
324
g_main_context_invoke (NULL, func, g_thread_self ());
325
g_assert_cmpint (count, ==, 1);
327
/* invoking out of an idle works too */
328
g_idle_add (call_func, NULL);
329
g_main_context_iteration (g_main_context_default (), FALSE);
330
g_assert_cmpint (count, ==, 2);
332
/* test thread-default forcing the invocation to go
335
ctx = g_main_context_new ();
336
thread = g_thread_new ("worker", thread_func, ctx);
338
g_mutex_lock (&mutex);
339
while (!thread_ready)
340
g_cond_wait (&cond, &mutex);
341
g_mutex_unlock (&mutex);
343
g_main_context_invoke (ctx, func, thread);
345
g_thread_join (thread);
346
g_assert_cmpint (count, ==, 3);
348
g_main_context_unref (ctx);
352
run_inner_loop (gpointer user_data)
354
GMainContext *ctx = user_data;
360
inner = g_main_loop_new (ctx, FALSE);
361
timeout = g_timeout_source_new (100);
362
g_source_set_callback (timeout, quit_loop, inner, NULL);
363
g_source_attach (timeout, ctx);
364
g_source_unref (timeout);
366
g_main_loop_run (inner);
367
g_main_loop_unref (inner);
369
return G_SOURCE_CONTINUE;
373
test_child_sources (void)
377
GSource *parent, *child_b, *child_c, *end;
379
ctx = g_main_context_new ();
380
loop = g_main_loop_new (ctx, FALSE);
384
parent = g_timeout_source_new (2000);
385
g_source_set_callback (parent, run_inner_loop, ctx, NULL);
386
g_source_set_priority (parent, G_PRIORITY_LOW);
387
g_source_attach (parent, ctx);
389
child_b = g_timeout_source_new (250);
390
g_source_set_callback (child_b, count_calls, &b, NULL);
391
g_source_add_child_source (parent, child_b);
393
child_c = g_timeout_source_new (330);
394
g_source_set_callback (child_c, count_calls, &c, NULL);
395
g_source_set_priority (child_c, G_PRIORITY_HIGH);
396
g_source_add_child_source (parent, child_c);
398
/* Child sources always have the priority of the parent */
399
g_assert_cmpint (g_source_get_priority (parent), ==, G_PRIORITY_LOW);
400
g_assert_cmpint (g_source_get_priority (child_b), ==, G_PRIORITY_LOW);
401
g_assert_cmpint (g_source_get_priority (child_c), ==, G_PRIORITY_LOW);
402
g_source_set_priority (parent, G_PRIORITY_DEFAULT);
403
g_assert_cmpint (g_source_get_priority (parent), ==, G_PRIORITY_DEFAULT);
404
g_assert_cmpint (g_source_get_priority (child_b), ==, G_PRIORITY_DEFAULT);
405
g_assert_cmpint (g_source_get_priority (child_c), ==, G_PRIORITY_DEFAULT);
407
end = g_timeout_source_new (1050);
408
g_source_set_callback (end, quit_loop, loop, NULL);
409
g_source_attach (end, ctx);
410
g_source_unref (end);
412
g_main_loop_run (loop);
414
/* The parent source's own timeout will never trigger, so "a" will
415
* only get incremented when "b" or "c" does. And when timeouts get
416
* blocked, they still wait the full interval next time rather than
417
* "catching up". So the timing is:
419
* 250 - b++ -> a++, run_inner_loop
420
* 330 - (c is blocked)
421
* 350 - inner_loop ends
422
* 350 - c++ belatedly -> a++, run_inner_loop
423
* 450 - inner loop ends
424
* 500 - b++ -> a++, run_inner_loop
425
* 600 - inner_loop ends
426
* 680 - c++ -> a++, run_inner_loop
427
* 750 - (b is blocked)
428
* 780 - inner loop ends
429
* 780 - b++ belatedly -> a++, run_inner_loop
430
* 880 - inner loop ends
431
* 1010 - c++ -> a++, run_inner_loop
432
* 1030 - (b is blocked)
433
* 1050 - end runs, quits outer loop, which has no effect yet
434
* 1110 - inner loop ends, a returns, outer loop exits
437
g_assert_cmpint (a, ==, 6);
438
g_assert_cmpint (b, ==, 3);
439
g_assert_cmpint (c, ==, 3);
441
g_source_destroy (parent);
442
g_source_unref (parent);
443
g_source_unref (child_b);
444
g_source_unref (child_c);
446
g_main_loop_unref (loop);
447
g_main_context_unref (ctx);
451
test_recursive_child_sources (void)
455
GSource *parent, *child_b, *child_c, *end;
457
ctx = g_main_context_new ();
458
loop = g_main_loop_new (ctx, FALSE);
462
parent = g_timeout_source_new (500);
463
g_source_set_callback (parent, count_calls, &a, NULL);
465
child_b = g_timeout_source_new (220);
466
g_source_set_callback (child_b, count_calls, &b, NULL);
467
g_source_add_child_source (parent, child_b);
469
child_c = g_timeout_source_new (430);
470
g_source_set_callback (child_c, count_calls, &c, NULL);
471
g_source_add_child_source (child_b, child_c);
473
g_source_attach (parent, ctx);
475
end = g_timeout_source_new (2010);
476
g_source_set_callback (end, (GSourceFunc)g_main_loop_quit, loop, NULL);
477
g_source_attach (end, ctx);
478
g_source_unref (end);
480
g_main_loop_run (loop);
482
/* Sequence of events:
483
* 220 b (b = 440, a = 720)
484
* 430 c (c = 860, b = 650, a = 930)
485
* 650 b (b = 870, a = 1150)
486
* 860 c (c = 1290, b = 1080, a = 1360)
487
* 1080 b (b = 1300, a = 1580)
488
* 1290 c (c = 1720, b = 1510, a = 1790)
489
* 1510 b (b = 1730, a = 2010)
490
* 1720 c (c = 2150, b = 1940, a = 2220)
491
* 1940 b (b = 2160, a = 2440)
494
g_assert_cmpint (a, ==, 9);
495
g_assert_cmpint (b, ==, 9);
496
g_assert_cmpint (c, ==, 4);
498
g_source_destroy (parent);
499
g_source_unref (parent);
500
g_source_unref (child_b);
501
g_source_unref (child_c);
503
g_main_loop_unref (loop);
504
g_main_context_unref (ctx);
508
GSource *parent, *old_child, *new_child;
513
swap_sources (gpointer user_data)
515
SwappingTestData *data = user_data;
519
g_source_remove_child_source (data->parent, data->old_child);
520
g_clear_pointer (&data->old_child, g_source_unref);
523
if (!data->new_child)
525
data->new_child = g_timeout_source_new (0);
526
g_source_set_callback (data->new_child, quit_loop, data->loop, NULL);
527
g_source_add_child_source (data->parent, data->new_child);
530
return G_SOURCE_CONTINUE;
534
assert_not_reached_callback (gpointer user_data)
536
g_assert_not_reached ();
538
return G_SOURCE_REMOVE;
542
test_swapping_child_sources (void)
546
SwappingTestData data;
548
ctx = g_main_context_new ();
549
loop = g_main_loop_new (ctx, FALSE);
551
data.parent = g_timeout_source_new (50);
553
g_source_set_callback (data.parent, swap_sources, &data, NULL);
554
g_source_attach (data.parent, ctx);
556
data.old_child = g_timeout_source_new (100);
557
g_source_add_child_source (data.parent, data.old_child);
558
g_source_set_callback (data.old_child, assert_not_reached_callback, NULL, NULL);
560
data.new_child = NULL;
561
g_main_loop_run (loop);
563
g_source_destroy (data.parent);
564
g_source_unref (data.parent);
565
g_source_unref (data.new_child);
567
g_main_loop_unref (loop);
568
g_main_context_unref (ctx);
575
GSource *timeout1, *timeout2;
580
timeout1_callback (gpointer user_data)
582
TimeTestData *data = user_data;
584
gint64 mtime1, mtime2, time2;
586
source = g_main_current_source ();
587
g_assert (source == data->timeout1);
589
if (data->time1 == -1)
591
/* First iteration */
592
g_assert (!g_source_is_destroyed (data->timeout2));
594
mtime1 = g_get_monotonic_time ();
595
data->time1 = g_source_get_time (source);
597
/* g_source_get_time() does not change during a single callback */
599
mtime2 = g_get_monotonic_time ();
600
time2 = g_source_get_time (source);
602
g_assert_cmpint (mtime1, <, mtime2);
603
g_assert_cmpint (data->time1, ==, time2);
607
/* Second iteration */
608
g_assert (g_source_is_destroyed (data->timeout2));
610
/* g_source_get_time() MAY change between iterations; in this
611
* case we know for sure that it did because of the g_usleep()
614
time2 = g_source_get_time (source);
615
g_assert_cmpint (data->time1, <, time2);
617
g_main_loop_quit (data->loop);
624
timeout2_callback (gpointer user_data)
626
TimeTestData *data = user_data;
630
source = g_main_current_source ();
631
g_assert (source == data->timeout2);
633
g_assert (!g_source_is_destroyed (data->timeout1));
635
/* g_source_get_time() does not change between different sources in
636
* a single iteration of the mainloop.
638
time2 = g_source_get_time (source);
639
g_assert_cmpint (data->time1, ==, time2);
641
/* The source should still have a valid time even after being
642
* destroyed, since it's currently running.
644
g_source_destroy (source);
645
time3 = g_source_get_time (source);
646
g_assert_cmpint (time2, ==, time3);
652
test_source_time (void)
656
data.ctx = g_main_context_new ();
657
data.loop = g_main_loop_new (data.ctx, FALSE);
659
data.timeout1 = g_timeout_source_new (0);
660
g_source_set_callback (data.timeout1, timeout1_callback, &data, NULL);
661
g_source_attach (data.timeout1, data.ctx);
663
data.timeout2 = g_timeout_source_new (0);
664
g_source_set_callback (data.timeout2, timeout2_callback, &data, NULL);
665
g_source_attach (data.timeout2, data.ctx);
669
g_main_loop_run (data.loop);
671
g_assert (!g_source_is_destroyed (data.timeout1));
672
g_assert (g_source_is_destroyed (data.timeout2));
674
g_source_destroy (data.timeout1);
675
g_source_unref (data.timeout1);
676
g_source_unref (data.timeout2);
678
g_main_loop_unref (data.loop);
679
g_main_context_unref (data.ctx);
683
guint outstanding_ops;
688
on_source_fired_cb (gpointer user_data)
690
TestOverflowData *data = user_data;
691
GSource *current_source;
692
GMainContext *current_context;
695
data->outstanding_ops--;
697
current_source = g_main_current_source ();
698
current_context = g_source_get_context (current_source);
699
source_id = g_source_get_id (current_source);
700
g_assert (g_main_context_find_source_by_id (current_context, source_id) != NULL);
701
g_source_destroy (current_source);
702
g_assert (g_main_context_find_source_by_id (current_context, source_id) == NULL);
704
if (data->outstanding_ops == 0)
705
g_main_loop_quit (data->loop);
710
add_idle_source (GMainContext *ctx,
711
TestOverflowData *data)
715
source = g_idle_source_new ();
716
g_source_set_callback (source, on_source_fired_cb, data, NULL);
717
g_source_attach (source, ctx);
718
g_source_unref (source);
719
data->outstanding_ops++;
724
/* https://bugzilla.gnome.org/show_bug.cgi?id=687098 */
726
test_mainloop_overflow (void)
731
TestOverflowData data;
734
memset (&data, 0, sizeof (data));
736
ctx = GLIB_PRIVATE_CALL (g_main_context_new_with_next_id) (G_MAXUINT-1);
738
loop = g_main_loop_new (ctx, TRUE);
739
data.outstanding_ops = 0;
742
source = add_idle_source (ctx, &data);
743
g_assert_cmpint (source->source_id, ==, G_MAXUINT-1);
745
source = add_idle_source (ctx, &data);
746
g_assert_cmpint (source->source_id, ==, G_MAXUINT);
748
source = add_idle_source (ctx, &data);
749
g_assert_cmpint (source->source_id, !=, 0);
751
/* Now, a lot more sources */
752
for (i = 0; i < 50; i++)
754
source = add_idle_source (ctx, &data);
755
g_assert_cmpint (source->source_id, !=, 0);
758
g_main_loop_run (loop);
759
g_assert_cmpint (data.outstanding_ops, ==, 0);
761
g_main_loop_unref (loop);
762
g_main_context_unref (ctx);
765
static volatile gint ready_time_dispatched;
768
ready_time_dispatch (GSource *source,
769
GSourceFunc callback,
772
g_atomic_int_set (&ready_time_dispatched, TRUE);
774
g_source_set_ready_time (source, -1);
780
run_context (gpointer user_data)
782
g_main_loop_run (user_data);
788
test_ready_time (void)
792
GSourceFuncs source_funcs = {
793
NULL, NULL, ready_time_dispatch
797
source = g_source_new (&source_funcs, sizeof (GSource));
798
g_source_attach (source, NULL);
799
g_source_unref (source);
801
/* Unfortunately we can't do too many things with respect to timing
802
* without getting into trouble on slow systems or heavily loaded
805
* We can test that the basics are working, though.
808
/* A source with no ready time set should not fire */
809
g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
810
while (g_main_context_iteration (NULL, FALSE));
811
g_assert (!ready_time_dispatched);
813
/* The ready time should not have been changed */
814
g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
816
/* Of course this shouldn't change anything either */
817
g_source_set_ready_time (source, -1);
818
g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
820
/* A source with a ready time set to tomorrow should not fire on any
821
* builder, no matter how badly loaded...
823
g_source_set_ready_time (source, g_get_monotonic_time () + G_TIME_SPAN_DAY);
824
while (g_main_context_iteration (NULL, FALSE));
825
g_assert (!ready_time_dispatched);
826
/* Make sure it didn't get reset */
827
g_assert_cmpint (g_source_get_ready_time (source), !=, -1);
829
/* Ready time of -1 -> don't fire */
830
g_source_set_ready_time (source, -1);
831
while (g_main_context_iteration (NULL, FALSE));
832
g_assert (!ready_time_dispatched);
833
/* Not reset, but should still be -1 from above */
834
g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
836
/* A ready time of the current time should fire immediately */
837
g_source_set_ready_time (source, g_get_monotonic_time ());
838
while (g_main_context_iteration (NULL, FALSE));
839
g_assert (ready_time_dispatched);
840
ready_time_dispatched = FALSE;
841
/* Should have gotten reset by the handler function */
842
g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
844
/* As well as one in the recent past... */
845
g_source_set_ready_time (source, g_get_monotonic_time () - G_TIME_SPAN_SECOND);
846
while (g_main_context_iteration (NULL, FALSE));
847
g_assert (ready_time_dispatched);
848
ready_time_dispatched = FALSE;
849
g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
851
/* Zero is the 'official' way to get a source to fire immediately */
852
g_source_set_ready_time (source, 0);
853
while (g_main_context_iteration (NULL, FALSE));
854
g_assert (ready_time_dispatched);
855
ready_time_dispatched = FALSE;
856
g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
858
/* Now do some tests of cross-thread wakeups.
860
* Make sure it wakes up right away from the start.
862
g_source_set_ready_time (source, 0);
863
loop = g_main_loop_new (NULL, FALSE);
864
thread = g_thread_new ("context thread", run_context, loop);
865
while (!g_atomic_int_get (&ready_time_dispatched));
867
/* Now let's see if it can wake up from sleeping. */
868
g_usleep (G_TIME_SPAN_SECOND / 2);
869
g_atomic_int_set (&ready_time_dispatched, FALSE);
870
g_source_set_ready_time (source, 0);
871
while (!g_atomic_int_get (&ready_time_dispatched));
873
/* kill the thread */
874
g_main_loop_quit (loop);
875
g_thread_join (thread);
876
g_main_loop_unref (loop);
878
g_source_destroy (source);
883
#include <glib-unix.h>
886
static gchar zeros[1024];
889
fill_a_pipe (gint fd)
895
pfd.events = G_IO_OUT;
896
while (g_poll (&pfd, 1, 0) == 1)
897
/* we should never see -1 here */
898
written += write (fd, zeros, sizeof zeros);
904
write_bytes (gint fd,
905
GIOCondition condition,
908
gssize *to_write = user_data;
914
/* Detect if we run before we should */
915
g_assert (*to_write >= 0);
917
limit = MIN (*to_write, sizeof zeros);
918
*to_write -= write (fd, zeros, limit);
925
GIOCondition condition,
928
static gchar buffer[1024];
929
gssize *to_read = user_data;
931
*to_read -= read (fd, buffer, sizeof buffer);
933
/* The loop will exit when there is nothing else to read, then we will
934
* use g_source_remove() to destroy this source.
942
gssize to_write = -1;
953
to_read = fill_a_pipe (fds[1]);
954
/* write at higher priority to keep the pipe full... */
955
a = g_unix_fd_add_full (G_PRIORITY_HIGH, fds[1], G_IO_OUT, write_bytes, &to_write, NULL);
956
source_a = g_source_ref (g_main_context_find_source_by_id (NULL, a));
957
/* make sure no 'writes' get dispatched yet */
958
while (g_main_context_iteration (NULL, FALSE));
960
to_read += 128 * 1024 * 1024;
961
to_write = 128 * 1024 * 1024;
962
b = g_unix_fd_add (fds[0], G_IO_IN, read_bytes, &to_read);
963
source_b = g_source_ref (g_main_context_find_source_by_id (NULL, b));
965
/* Assuming the kernel isn't internally 'laggy' then there will always
966
* be either data to read or room in which to write. That will keep
967
* the loop running until all data has been read and written.
971
gssize to_write_was = to_write;
972
gssize to_read_was = to_read;
974
if (!g_main_context_iteration (NULL, FALSE))
977
/* Since the sources are at different priority, only one of them
978
* should possibly have run.
980
g_assert (to_write == to_write_was || to_read == to_read_was);
983
g_assert (to_write == 0);
984
g_assert (to_read == 0);
986
/* 'a' is already removed by itself */
987
g_assert (g_source_is_destroyed (source_a));
988
g_source_unref (source_a);
990
g_assert (g_source_is_destroyed (source_b));
991
g_source_unref (source_b);
997
assert_main_context_state (gint n_to_poll,
1000
GMainContext *context;
1001
gboolean consumed[10] = { };
1002
GPollFD poll_fds[10];
1010
context = g_main_context_default ();
1012
immediate = g_main_context_prepare (context, &max_priority);
1013
g_assert (!immediate);
1014
n = g_main_context_query (context, max_priority, &timeout, poll_fds, 10);
1015
g_assert_cmpint (n, ==, n_to_poll + 1); /* one will be the gwakeup */
1017
va_start (ap, n_to_poll);
1018
for (i = 0; i < n_to_poll; i++)
1020
gint expected_fd = va_arg (ap, gint);
1021
GIOCondition expected_events = va_arg (ap, GIOCondition);
1022
GIOCondition report_events = va_arg (ap, GIOCondition);
1024
for (j = 0; j < n; j++)
1025
if (!consumed[j] && poll_fds[j].fd == expected_fd && poll_fds[j].events == expected_events)
1027
poll_fds[j].revents = report_events;
1033
g_error ("Unable to find fd %d (index %d) with events 0x%x\n", expected_fd, i, (guint) expected_events);
1037
/* find the gwakeup, flag as non-ready */
1038
for (i = 0; i < n; i++)
1040
poll_fds[i].revents = 0;
1042
if (g_main_context_check (context, max_priority, poll_fds, n))
1043
g_main_context_dispatch (context);
1048
GIOCondition condition,
1051
gboolean *flag = user_data;
1059
test_unix_fd_source (void)
1061
GSource *out_source;
1068
assert_main_context_state (0);
1073
source = g_unix_fd_source_new (fds[1], G_IO_OUT);
1074
g_source_attach (source, NULL);
1076
/* Check that a source with no callback gets successfully detached
1077
* with a warning printed.
1079
g_test_expect_message ("GLib", G_LOG_LEVEL_WARNING, "*GUnixFDSource dispatched without callback*");
1080
while (g_main_context_iteration (NULL, FALSE));
1081
g_test_assert_expected_messages ();
1082
g_assert (g_source_is_destroyed (source));
1083
g_source_unref (source);
1086
out_source = g_unix_fd_source_new (fds[1], G_IO_OUT);
1087
g_source_set_callback (out_source, (GSourceFunc) flag_bool, &out, NULL);
1088
g_source_attach (out_source, NULL);
1089
assert_main_context_state (1,
1090
fds[1], G_IO_OUT, 0);
1091
g_assert (!in && !out);
1093
in_source = g_unix_fd_source_new (fds[0], G_IO_IN);
1094
g_source_set_callback (in_source, (GSourceFunc) flag_bool, &in, NULL);
1095
g_source_set_priority (in_source, G_PRIORITY_DEFAULT_IDLE);
1096
g_source_attach (in_source, NULL);
1097
assert_main_context_state (2,
1098
fds[0], G_IO_IN, G_IO_IN,
1099
fds[1], G_IO_OUT, G_IO_OUT);
1100
/* out is higher priority so only it should fire */
1101
g_assert (!in && out);
1103
/* raise the priority of the in source to higher than out*/
1105
g_source_set_priority (in_source, G_PRIORITY_HIGH);
1106
assert_main_context_state (2,
1107
fds[0], G_IO_IN, G_IO_IN,
1108
fds[1], G_IO_OUT, G_IO_OUT);
1109
g_assert (in && !out);
1111
/* now, let them be equal */
1113
g_source_set_priority (in_source, G_PRIORITY_DEFAULT);
1114
assert_main_context_state (2,
1115
fds[0], G_IO_IN, G_IO_IN,
1116
fds[1], G_IO_OUT, G_IO_OUT);
1117
g_assert (in && out);
1119
g_source_destroy (out_source);
1120
g_source_destroy (in_source);
1132
return_true (GSource *source, GSourceFunc callback, gpointer user_data)
1134
FlagSource *flag_source = (FlagSource *) source;
1136
flag_source->flagged = TRUE;
1141
#define assert_flagged(s) g_assert (((FlagSource *) (s))->flagged);
1142
#define assert_not_flagged(s) g_assert (!((FlagSource *) (s))->flagged);
1143
#define clear_flag(s) ((FlagSource *) (s))->flagged = 0
1146
test_source_unix_fd_api (void)
1148
GSourceFuncs no_funcs = {
1149
NULL, NULL, return_true
1153
gpointer tag1, tag2;
1160
source_a = g_source_new (&no_funcs, sizeof (FlagSource));
1161
source_b = g_source_new (&no_funcs, sizeof (FlagSource));
1163
/* attach a source with more than one fd */
1164
g_source_add_unix_fd (source_a, fds_a[0], G_IO_IN);
1165
g_source_add_unix_fd (source_a, fds_a[1], G_IO_OUT);
1166
g_source_attach (source_a, NULL);
1167
assert_main_context_state (2,
1168
fds_a[0], G_IO_IN, 0,
1169
fds_a[1], G_IO_OUT, 0);
1170
assert_not_flagged (source_a);
1172
/* attach a higher priority source with no fds */
1173
g_source_set_priority (source_b, G_PRIORITY_HIGH);
1174
g_source_attach (source_b, NULL);
1175
assert_main_context_state (2,
1176
fds_a[0], G_IO_IN, G_IO_IN,
1177
fds_a[1], G_IO_OUT, 0);
1178
assert_flagged (source_a);
1179
assert_not_flagged (source_b);
1180
clear_flag (source_a);
1182
/* add some fds to the second source, while attached */
1183
tag1 = g_source_add_unix_fd (source_b, fds_b[0], G_IO_IN);
1184
tag2 = g_source_add_unix_fd (source_b, fds_b[1], G_IO_OUT);
1185
assert_main_context_state (4,
1186
fds_a[0], G_IO_IN, 0,
1187
fds_a[1], G_IO_OUT, G_IO_OUT,
1188
fds_b[0], G_IO_IN, 0,
1189
fds_b[1], G_IO_OUT, G_IO_OUT);
1190
/* only 'b' (higher priority) should have dispatched */
1191
assert_not_flagged (source_a);
1192
assert_flagged (source_b);
1193
clear_flag (source_b);
1195
/* change our events on b to the same as they were before */
1196
g_source_modify_unix_fd (source_b, tag1, G_IO_IN);
1197
g_source_modify_unix_fd (source_b, tag2, G_IO_OUT);
1198
assert_main_context_state (4,
1199
fds_a[0], G_IO_IN, 0,
1200
fds_a[1], G_IO_OUT, G_IO_OUT,
1201
fds_b[0], G_IO_IN, 0,
1202
fds_b[1], G_IO_OUT, G_IO_OUT);
1203
assert_not_flagged (source_a);
1204
assert_flagged (source_b);
1205
clear_flag (source_b);
1207
/* now reverse them */
1208
g_source_modify_unix_fd (source_b, tag1, G_IO_OUT);
1209
g_source_modify_unix_fd (source_b, tag2, G_IO_IN);
1210
assert_main_context_state (4,
1211
fds_a[0], G_IO_IN, 0,
1212
fds_a[1], G_IO_OUT, G_IO_OUT,
1213
fds_b[0], G_IO_OUT, 0,
1214
fds_b[1], G_IO_IN, 0);
1215
/* 'b' had no events, so 'a' can go this time */
1216
assert_flagged (source_a);
1217
assert_not_flagged (source_b);
1218
clear_flag (source_a);
1220
/* remove one of the fds from 'b' */
1221
g_source_remove_unix_fd (source_b, tag1);
1222
assert_main_context_state (3,
1223
fds_a[0], G_IO_IN, 0,
1224
fds_a[1], G_IO_OUT, 0,
1225
fds_b[1], G_IO_IN, 0);
1226
assert_not_flagged (source_a);
1227
assert_not_flagged (source_b);
1229
/* remove the other */
1230
g_source_remove_unix_fd (source_b, tag2);
1231
assert_main_context_state (2,
1232
fds_a[0], G_IO_IN, 0,
1233
fds_a[1], G_IO_OUT, 0);
1234
assert_not_flagged (source_a);
1235
assert_not_flagged (source_b);
1237
/* destroy the sources */
1238
g_source_destroy (source_a);
1239
g_source_destroy (source_b);
1240
assert_main_context_state (0);
1242
g_source_unref (source_a);
1243
g_source_unref (source_b);
1253
main (int argc, char *argv[])
1255
g_test_init (&argc, &argv, NULL);
1257
g_test_add_func ("/maincontext/basic", test_maincontext_basic);
1258
g_test_add_func ("/mainloop/basic", test_mainloop_basic);
1259
g_test_add_func ("/mainloop/timeouts", test_timeouts);
1260
g_test_add_func ("/mainloop/priorities", test_priorities);
1261
g_test_add_func ("/mainloop/invoke", test_invoke);
1262
g_test_add_func ("/mainloop/child_sources", test_child_sources);
1263
g_test_add_func ("/mainloop/recursive_child_sources", test_recursive_child_sources);
1264
g_test_add_func ("/mainloop/swapping_child_sources", test_swapping_child_sources);
1265
g_test_add_func ("/mainloop/source_time", test_source_time);
1266
g_test_add_func ("/mainloop/overflow", test_mainloop_overflow);
1267
g_test_add_func ("/mainloop/ready-time", test_ready_time);
1269
g_test_add_func ("/mainloop/unix-fd", test_unix_fd);
1270
g_test_add_func ("/mainloop/unix-fd-source", test_unix_fd_source);
1271
g_test_add_func ("/mainloop/source-unix-fd-api", test_source_unix_fd_api);
1274
return g_test_run ();