~ubuntu-branches/debian/sid/glib2.0/sid

« back to all changes in this revision

Viewing changes to .pc/07_disable_tests_on_slow_archs.patch/glib/tests/mainloop.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2013-05-08 06:25:57 UTC
  • mfrom: (1.27.14) (3.1.181 experimental)
  • Revision ID: package-import@ubuntu.com-20130508062557-i7gbku66mls70gi2
Tags: 2.36.1-2
Merge experimental branch, upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Unit tests for GMainLoop
 
2
 * Copyright (C) 2011 Red Hat, Inc
 
3
 * Author: Matthias Clasen
 
4
 *
 
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.
 
8
 *
 
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.
 
12
 *
 
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.
 
21
 */
 
22
 
 
23
#include <glib.h>
 
24
#include "glib-private.h"
 
25
#include <string.h>
 
26
 
 
27
static gboolean cb (gpointer data)
 
28
{
 
29
  return FALSE;
 
30
}
 
31
 
 
32
static gboolean prepare (GSource *source, gint *time)
 
33
{
 
34
  return FALSE;
 
35
}
 
36
static gboolean check (GSource *source)
 
37
{
 
38
  return FALSE;
 
39
}
 
40
static gboolean dispatch (GSource *source, GSourceFunc cb, gpointer date)
 
41
{
 
42
  return FALSE;
 
43
}
 
44
 
 
45
GSourceFuncs funcs = {
 
46
  prepare,
 
47
  check,
 
48
  dispatch,
 
49
  NULL
 
50
};
 
51
 
 
52
static void
 
53
test_maincontext_basic (void)
 
54
{
 
55
  GMainContext *ctx;
 
56
  GSource *source;
 
57
  guint id;
 
58
  gpointer data = &funcs;
 
59
 
 
60
  ctx = g_main_context_new ();
 
61
 
 
62
  g_assert (!g_main_context_pending (ctx));
 
63
  g_assert (!g_main_context_iteration (ctx, FALSE));
 
64
 
 
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));
 
68
 
 
69
  g_assert (!g_source_get_can_recurse (source));
 
70
  g_assert (g_source_get_name (source) == NULL);
 
71
 
 
72
  g_source_set_can_recurse (source, TRUE);
 
73
  g_source_set_name (source, "d");
 
74
 
 
75
  g_assert (g_source_get_can_recurse (source));
 
76
  g_assert_cmpstr (g_source_get_name (source), ==, "d");
 
77
 
 
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);
 
80
 
 
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);
 
84
 
 
85
  g_source_set_priority (source, G_PRIORITY_HIGH);
 
86
  g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_HIGH);
 
87
 
 
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);
 
91
 
 
92
  g_main_context_unref (ctx);
 
93
 
 
94
  if (g_test_undefined ())
 
95
    {
 
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 ();
 
100
    }
 
101
 
 
102
  g_source_unref (source);
 
103
 
 
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));
 
114
 
 
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));
 
121
 
 
122
  g_idle_add (cb, data);
 
123
  g_assert (g_idle_remove_by_data (data));
 
124
}
 
125
 
 
126
static void
 
127
test_mainloop_basic (void)
 
128
{
 
129
  GMainLoop *loop;
 
130
  GMainContext *ctx;
 
131
 
 
132
  loop = g_main_loop_new (NULL, FALSE);
 
133
 
 
134
  g_assert (!g_main_loop_is_running (loop));
 
135
 
 
136
  g_main_loop_ref (loop);
 
137
 
 
138
  ctx = g_main_loop_get_context (loop);
 
139
  g_assert (ctx == g_main_context_default ());
 
140
 
 
141
  g_main_loop_unref (loop);
 
142
 
 
143
  g_assert_cmpint (g_main_depth (), ==, 0);
 
144
 
 
145
  g_main_loop_unref (loop);
 
146
}
 
147
 
 
148
static gint a;
 
149
static gint b;
 
150
static gint c;
 
151
 
 
152
static gboolean
 
153
count_calls (gpointer data)
 
154
{
 
155
  gint *i = data;
 
156
 
 
157
  (*i)++;
 
158
 
 
159
  return TRUE;
 
160
}
 
161
 
 
162
static void
 
163
test_timeouts (void)
 
164
{
 
165
  GMainContext *ctx;
 
166
  GMainLoop *loop;
 
167
  GSource *source;
 
168
 
 
169
  a = b = c = 0;
 
170
 
 
171
  ctx = g_main_context_new ();
 
172
  loop = g_main_loop_new (ctx, FALSE);
 
173
 
 
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);
 
178
 
 
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);
 
183
 
 
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);
 
188
 
 
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);
 
193
 
 
194
  g_main_loop_run (loop);
 
195
 
 
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);
 
202
 
 
203
  g_main_loop_unref (loop);
 
204
  g_main_context_unref (ctx);
 
205
}
 
206
 
 
207
static void
 
208
test_priorities (void)
 
209
{
 
210
  GMainContext *ctx;
 
211
  GSource *sourcea;
 
212
  GSource *sourceb;
 
213
 
 
214
  a = b = c = 0;
 
215
 
 
216
  ctx = g_main_context_new ();
 
217
 
 
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);
 
223
 
 
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);
 
229
 
 
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);
 
234
 
 
235
  g_assert (g_main_context_iteration (ctx, FALSE));
 
236
  g_assert_cmpint (a, ==, 0);
 
237
  g_assert_cmpint (b, ==, 2);
 
238
 
 
239
  g_source_destroy (sourceb);
 
240
 
 
241
  g_assert (g_main_context_iteration (ctx, FALSE));
 
242
  g_assert_cmpint (a, ==, 1);
 
243
  g_assert_cmpint (b, ==, 2);
 
244
 
 
245
  g_assert (g_main_context_pending (ctx));
 
246
  g_source_destroy (sourcea);
 
247
  g_assert (!g_main_context_pending (ctx));
 
248
 
 
249
  g_main_context_unref (ctx);
 
250
}
 
251
 
 
252
static gboolean
 
253
quit_loop (gpointer data)
 
254
{
 
255
  GMainLoop *loop = data;
 
256
 
 
257
  g_main_loop_quit (loop);
 
258
 
 
259
  return G_SOURCE_REMOVE;
 
260
}
 
261
 
 
262
static gint count;
 
263
 
 
264
static gboolean
 
265
func (gpointer data)
 
266
{
 
267
  if (data != NULL)
 
268
    g_assert (data == g_thread_self ());
 
269
 
 
270
  count++;
 
271
 
 
272
  return FALSE;
 
273
}
 
274
 
 
275
static gboolean
 
276
call_func (gpointer data)
 
277
{
 
278
  func (g_thread_self ());
 
279
 
 
280
  return G_SOURCE_REMOVE;
 
281
}
 
282
 
 
283
static GMutex mutex;
 
284
static GCond cond;
 
285
static gboolean thread_ready;
 
286
 
 
287
static gpointer
 
288
thread_func (gpointer data)
 
289
{
 
290
  GMainContext *ctx = data;
 
291
  GMainLoop *loop;
 
292
  GSource *source;
 
293
 
 
294
  g_main_context_push_thread_default (ctx);
 
295
  loop = g_main_loop_new (ctx, FALSE);
 
296
 
 
297
  g_mutex_lock (&mutex);
 
298
  thread_ready = TRUE;
 
299
  g_cond_signal (&cond);
 
300
  g_mutex_unlock (&mutex);
 
301
 
 
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);
 
306
 
 
307
  g_main_loop_run (loop);
 
308
 
 
309
  g_main_context_pop_thread_default (ctx);
 
310
  g_main_loop_unref (loop);
 
311
 
 
312
  return NULL;
 
313
}
 
314
 
 
315
static void
 
316
test_invoke (void)
 
317
{
 
318
  GMainContext *ctx;
 
319
  GThread *thread;
 
320
 
 
321
  count = 0;
 
322
 
 
323
  /* this one gets invoked directly */
 
324
  g_main_context_invoke (NULL, func, g_thread_self ());
 
325
  g_assert_cmpint (count, ==, 1);
 
326
 
 
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);
 
331
 
 
332
  /* test thread-default forcing the invocation to go
 
333
   * to another thread
 
334
   */
 
335
  ctx = g_main_context_new ();
 
336
  thread = g_thread_new ("worker", thread_func, ctx);
 
337
 
 
338
  g_mutex_lock (&mutex);
 
339
  while (!thread_ready)
 
340
    g_cond_wait (&cond, &mutex);
 
341
  g_mutex_unlock (&mutex);
 
342
 
 
343
  g_main_context_invoke (ctx, func, thread);
 
344
 
 
345
  g_thread_join (thread);
 
346
  g_assert_cmpint (count, ==, 3);
 
347
 
 
348
  g_main_context_unref (ctx);
 
349
}
 
350
 
 
351
static gboolean
 
352
run_inner_loop (gpointer user_data)
 
353
{
 
354
  GMainContext *ctx = user_data;
 
355
  GMainLoop *inner;
 
356
  GSource *timeout;
 
357
 
 
358
  a++;
 
359
 
 
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);
 
365
 
 
366
  g_main_loop_run (inner);
 
367
  g_main_loop_unref (inner);
 
368
 
 
369
  return G_SOURCE_CONTINUE;
 
370
}
 
371
 
 
372
static void
 
373
test_child_sources (void)
 
374
{
 
375
  GMainContext *ctx;
 
376
  GMainLoop *loop;
 
377
  GSource *parent, *child_b, *child_c, *end;
 
378
 
 
379
  ctx = g_main_context_new ();
 
380
  loop = g_main_loop_new (ctx, FALSE);
 
381
 
 
382
  a = b = c = 0;
 
383
 
 
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);
 
388
 
 
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);
 
392
 
 
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);
 
397
 
 
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);
 
406
 
 
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);
 
411
 
 
412
  g_main_loop_run (loop);
 
413
 
 
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:
 
418
   *
 
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
 
435
   */
 
436
 
 
437
  g_assert_cmpint (a, ==, 6);
 
438
  g_assert_cmpint (b, ==, 3);
 
439
  g_assert_cmpint (c, ==, 3);
 
440
 
 
441
  g_source_destroy (parent);
 
442
  g_source_unref (parent);
 
443
  g_source_unref (child_b);
 
444
  g_source_unref (child_c);
 
445
 
 
446
  g_main_loop_unref (loop);
 
447
  g_main_context_unref (ctx);
 
448
}
 
449
 
 
450
static void
 
451
test_recursive_child_sources (void)
 
452
{
 
453
  GMainContext *ctx;
 
454
  GMainLoop *loop;
 
455
  GSource *parent, *child_b, *child_c, *end;
 
456
 
 
457
  ctx = g_main_context_new ();
 
458
  loop = g_main_loop_new (ctx, FALSE);
 
459
 
 
460
  a = b = c = 0;
 
461
 
 
462
  parent = g_timeout_source_new (500);
 
463
  g_source_set_callback (parent, count_calls, &a, NULL);
 
464
 
 
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);
 
468
 
 
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);
 
472
 
 
473
  g_source_attach (parent, ctx);
 
474
 
 
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);
 
479
 
 
480
  g_main_loop_run (loop);
 
481
 
 
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)
 
492
   */
 
493
 
 
494
  g_assert_cmpint (a, ==, 9);
 
495
  g_assert_cmpint (b, ==, 9);
 
496
  g_assert_cmpint (c, ==, 4);
 
497
 
 
498
  g_source_destroy (parent);
 
499
  g_source_unref (parent);
 
500
  g_source_unref (child_b);
 
501
  g_source_unref (child_c);
 
502
 
 
503
  g_main_loop_unref (loop);
 
504
  g_main_context_unref (ctx);
 
505
}
 
506
 
 
507
typedef struct {
 
508
  GSource *parent, *old_child, *new_child;
 
509
  GMainLoop *loop;
 
510
} SwappingTestData;
 
511
 
 
512
static gboolean
 
513
swap_sources (gpointer user_data)
 
514
{
 
515
  SwappingTestData *data = user_data;
 
516
 
 
517
  if (data->old_child)
 
518
    {
 
519
      g_source_remove_child_source (data->parent, data->old_child);
 
520
      g_clear_pointer (&data->old_child, g_source_unref);
 
521
    }
 
522
 
 
523
  if (!data->new_child)
 
524
    {
 
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);
 
528
    }
 
529
 
 
530
  return G_SOURCE_CONTINUE;
 
531
}
 
532
 
 
533
static gboolean
 
534
assert_not_reached_callback (gpointer user_data)
 
535
{
 
536
  g_assert_not_reached ();
 
537
 
 
538
  return G_SOURCE_REMOVE;
 
539
}
 
540
 
 
541
static void
 
542
test_swapping_child_sources (void)
 
543
{
 
544
  GMainContext *ctx;
 
545
  GMainLoop *loop;
 
546
  SwappingTestData data;
 
547
 
 
548
  ctx = g_main_context_new ();
 
549
  loop = g_main_loop_new (ctx, FALSE);
 
550
 
 
551
  data.parent = g_timeout_source_new (50);
 
552
  data.loop = loop;
 
553
  g_source_set_callback (data.parent, swap_sources, &data, NULL);
 
554
  g_source_attach (data.parent, ctx);
 
555
 
 
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);
 
559
 
 
560
  data.new_child = NULL;
 
561
  g_main_loop_run (loop);
 
562
 
 
563
  g_source_destroy (data.parent);
 
564
  g_source_unref (data.parent);
 
565
  g_source_unref (data.new_child);
 
566
 
 
567
  g_main_loop_unref (loop);
 
568
  g_main_context_unref (ctx);
 
569
}
 
570
 
 
571
typedef struct {
 
572
  GMainContext *ctx;
 
573
  GMainLoop *loop;
 
574
 
 
575
  GSource *timeout1, *timeout2;
 
576
  gint64 time1;
 
577
} TimeTestData;
 
578
 
 
579
static gboolean
 
580
timeout1_callback (gpointer user_data)
 
581
{
 
582
  TimeTestData *data = user_data;
 
583
  GSource *source;
 
584
  gint64 mtime1, mtime2, time2;
 
585
 
 
586
  source = g_main_current_source ();
 
587
  g_assert (source == data->timeout1);
 
588
 
 
589
  if (data->time1 == -1)
 
590
    {
 
591
      /* First iteration */
 
592
      g_assert (!g_source_is_destroyed (data->timeout2));
 
593
 
 
594
      mtime1 = g_get_monotonic_time ();
 
595
      data->time1 = g_source_get_time (source);
 
596
 
 
597
      /* g_source_get_time() does not change during a single callback */
 
598
      g_usleep (1000000);
 
599
      mtime2 = g_get_monotonic_time ();
 
600
      time2 = g_source_get_time (source);
 
601
 
 
602
      g_assert_cmpint (mtime1, <, mtime2);
 
603
      g_assert_cmpint (data->time1, ==, time2);
 
604
    }
 
605
  else
 
606
    {
 
607
      /* Second iteration */
 
608
      g_assert (g_source_is_destroyed (data->timeout2));
 
609
 
 
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()
 
612
       * last time.
 
613
       */
 
614
      time2 = g_source_get_time (source);
 
615
      g_assert_cmpint (data->time1, <, time2);
 
616
 
 
617
      g_main_loop_quit (data->loop);
 
618
    }
 
619
 
 
620
  return TRUE;
 
621
}
 
622
 
 
623
static gboolean
 
624
timeout2_callback (gpointer user_data)
 
625
{
 
626
  TimeTestData *data = user_data;
 
627
  GSource *source;
 
628
  gint64 time2, time3;
 
629
 
 
630
  source = g_main_current_source ();
 
631
  g_assert (source == data->timeout2);
 
632
 
 
633
  g_assert (!g_source_is_destroyed (data->timeout1));
 
634
 
 
635
  /* g_source_get_time() does not change between different sources in
 
636
   * a single iteration of the mainloop.
 
637
   */
 
638
  time2 = g_source_get_time (source);
 
639
  g_assert_cmpint (data->time1, ==, time2);
 
640
 
 
641
  /* The source should still have a valid time even after being
 
642
   * destroyed, since it's currently running.
 
643
   */
 
644
  g_source_destroy (source);
 
645
  time3 = g_source_get_time (source);
 
646
  g_assert_cmpint (time2, ==, time3);
 
647
 
 
648
  return FALSE;
 
649
}
 
650
 
 
651
static void
 
652
test_source_time (void)
 
653
{
 
654
  TimeTestData data;
 
655
 
 
656
  data.ctx = g_main_context_new ();
 
657
  data.loop = g_main_loop_new (data.ctx, FALSE);
 
658
 
 
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);
 
662
 
 
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);
 
666
 
 
667
  data.time1 = -1;
 
668
 
 
669
  g_main_loop_run (data.loop);
 
670
 
 
671
  g_assert (!g_source_is_destroyed (data.timeout1));
 
672
  g_assert (g_source_is_destroyed (data.timeout2));
 
673
 
 
674
  g_source_destroy (data.timeout1);
 
675
  g_source_unref (data.timeout1);
 
676
  g_source_unref (data.timeout2);
 
677
 
 
678
  g_main_loop_unref (data.loop);
 
679
  g_main_context_unref (data.ctx);
 
680
}
 
681
 
 
682
typedef struct {
 
683
  guint outstanding_ops;
 
684
  GMainLoop *loop;
 
685
} TestOverflowData;
 
686
 
 
687
static gboolean
 
688
on_source_fired_cb (gpointer user_data)
 
689
{
 
690
  TestOverflowData *data = user_data;
 
691
  GSource *current_source;
 
692
  GMainContext *current_context;
 
693
  guint source_id;
 
694
 
 
695
  data->outstanding_ops--;
 
696
 
 
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);
 
703
 
 
704
  if (data->outstanding_ops == 0)
 
705
    g_main_loop_quit (data->loop);
 
706
  return FALSE;
 
707
}
 
708
 
 
709
static GSource *
 
710
add_idle_source (GMainContext *ctx,
 
711
                 TestOverflowData *data)
 
712
{
 
713
  GSource *source;
 
714
 
 
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++;
 
720
 
 
721
  return source;
 
722
}
 
723
 
 
724
/* https://bugzilla.gnome.org/show_bug.cgi?id=687098 */
 
725
static void
 
726
test_mainloop_overflow (void)
 
727
{
 
728
  GMainContext *ctx;
 
729
  GMainLoop *loop;
 
730
  GSource *source;
 
731
  TestOverflowData data;
 
732
  guint i;
 
733
 
 
734
  memset (&data, 0, sizeof (data));
 
735
 
 
736
  ctx = GLIB_PRIVATE_CALL (g_main_context_new_with_next_id) (G_MAXUINT-1);
 
737
 
 
738
  loop = g_main_loop_new (ctx, TRUE);
 
739
  data.outstanding_ops = 0;
 
740
  data.loop = loop;
 
741
 
 
742
  source = add_idle_source (ctx, &data);
 
743
  g_assert_cmpint (source->source_id, ==, G_MAXUINT-1);
 
744
 
 
745
  source = add_idle_source (ctx, &data);
 
746
  g_assert_cmpint (source->source_id, ==, G_MAXUINT);
 
747
 
 
748
  source = add_idle_source (ctx, &data);
 
749
  g_assert_cmpint (source->source_id, !=, 0);
 
750
 
 
751
  /* Now, a lot more sources */
 
752
  for (i = 0; i < 50; i++)
 
753
    {
 
754
      source = add_idle_source (ctx, &data);
 
755
      g_assert_cmpint (source->source_id, !=, 0);
 
756
    }
 
757
 
 
758
  g_main_loop_run (loop);
 
759
  g_assert_cmpint (data.outstanding_ops, ==, 0);
 
760
 
 
761
  g_main_loop_unref (loop);
 
762
  g_main_context_unref (ctx);
 
763
}
 
764
 
 
765
static volatile gint ready_time_dispatched;
 
766
 
 
767
static gboolean
 
768
ready_time_dispatch (GSource     *source,
 
769
                     GSourceFunc  callback,
 
770
                     gpointer     user_data)
 
771
{
 
772
  g_atomic_int_set (&ready_time_dispatched, TRUE);
 
773
 
 
774
  g_source_set_ready_time (source, -1);
 
775
 
 
776
  return TRUE;
 
777
}
 
778
 
 
779
static gpointer
 
780
run_context (gpointer user_data)
 
781
{
 
782
  g_main_loop_run (user_data);
 
783
 
 
784
  return NULL;
 
785
}
 
786
 
 
787
static void
 
788
test_ready_time (void)
 
789
{
 
790
  GThread *thread;
 
791
  GSource *source;
 
792
  GSourceFuncs source_funcs = {
 
793
    NULL, NULL, ready_time_dispatch
 
794
  };
 
795
  GMainLoop *loop;
 
796
 
 
797
  source = g_source_new (&source_funcs, sizeof (GSource));
 
798
  g_source_attach (source, NULL);
 
799
  g_source_unref (source);
 
800
 
 
801
  /* Unfortunately we can't do too many things with respect to timing
 
802
   * without getting into trouble on slow systems or heavily loaded
 
803
   * builders.
 
804
   *
 
805
   * We can test that the basics are working, though.
 
806
   */
 
807
 
 
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);
 
812
 
 
813
  /* The ready time should not have been changed */
 
814
  g_assert_cmpint (g_source_get_ready_time (source), ==, -1);
 
815
 
 
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);
 
819
 
 
820
  /* A source with a ready time set to tomorrow should not fire on any
 
821
   * builder, no matter how badly loaded...
 
822
   */
 
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);
 
828
 
 
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);
 
835
 
 
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);
 
843
 
 
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);
 
850
 
 
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);
 
857
 
 
858
  /* Now do some tests of cross-thread wakeups.
 
859
   *
 
860
   * Make sure it wakes up right away from the start.
 
861
   */
 
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));
 
866
 
 
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));
 
872
 
 
873
  /* kill the thread */
 
874
  g_main_loop_quit (loop);
 
875
  g_thread_join (thread);
 
876
  g_main_loop_unref (loop);
 
877
 
 
878
  g_source_destroy (source);
 
879
}
 
880
 
 
881
#ifdef G_OS_UNIX
 
882
 
 
883
#include <glib-unix.h>
 
884
#include <unistd.h>
 
885
 
 
886
static gchar zeros[1024];
 
887
 
 
888
static gsize
 
889
fill_a_pipe (gint fd)
 
890
{
 
891
  gsize written = 0;
 
892
  GPollFD pfd;
 
893
 
 
894
  pfd.fd = 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);
 
899
 
 
900
  return written;
 
901
}
 
902
 
 
903
static gboolean
 
904
write_bytes (gint         fd,
 
905
             GIOCondition condition,
 
906
             gpointer     user_data)
 
907
{
 
908
  gssize *to_write = user_data;
 
909
  gint limit;
 
910
 
 
911
  if (*to_write == 0)
 
912
    return FALSE;
 
913
 
 
914
  /* Detect if we run before we should */
 
915
  g_assert (*to_write >= 0);
 
916
 
 
917
  limit = MIN (*to_write, sizeof zeros);
 
918
  *to_write -= write (fd, zeros, limit);
 
919
 
 
920
  return TRUE;
 
921
}
 
922
 
 
923
static gboolean
 
924
read_bytes (gint         fd,
 
925
            GIOCondition condition,
 
926
            gpointer     user_data)
 
927
{
 
928
  static gchar buffer[1024];
 
929
  gssize *to_read = user_data;
 
930
 
 
931
  *to_read -= read (fd, buffer, sizeof buffer);
 
932
 
 
933
  /* The loop will exit when there is nothing else to read, then we will
 
934
   * use g_source_remove() to destroy this source.
 
935
   */
 
936
  return TRUE;
 
937
}
 
938
 
 
939
static void
 
940
test_unix_fd (void)
 
941
{
 
942
  gssize to_write = -1;
 
943
  gssize to_read;
 
944
  gint fds[2];
 
945
  gint a, b;
 
946
  gint s;
 
947
  GSource *source_a;
 
948
  GSource *source_b;
 
949
 
 
950
  s = pipe (fds);
 
951
  g_assert (s == 0);
 
952
 
 
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));
 
959
 
 
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));
 
964
 
 
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.
 
968
   */
 
969
  while (TRUE)
 
970
    {
 
971
      gssize to_write_was = to_write;
 
972
      gssize to_read_was = to_read;
 
973
 
 
974
      if (!g_main_context_iteration (NULL, FALSE))
 
975
        break;
 
976
 
 
977
      /* Since the sources are at different priority, only one of them
 
978
       * should possibly have run.
 
979
       */
 
980
      g_assert (to_write == to_write_was || to_read == to_read_was);
 
981
    }
 
982
 
 
983
  g_assert (to_write == 0);
 
984
  g_assert (to_read == 0);
 
985
 
 
986
  /* 'a' is already removed by itself */
 
987
  g_assert (g_source_is_destroyed (source_a));
 
988
  g_source_unref (source_a);
 
989
  g_source_remove (b);
 
990
  g_assert (g_source_is_destroyed (source_b));
 
991
  g_source_unref (source_b);
 
992
  close (fds[1]);
 
993
  close (fds[0]);
 
994
}
 
995
 
 
996
static void
 
997
assert_main_context_state (gint n_to_poll,
 
998
                           ...)
 
999
{
 
1000
  GMainContext *context;
 
1001
  gboolean consumed[10] = { };
 
1002
  GPollFD poll_fds[10];
 
1003
  gboolean immediate;
 
1004
  gint max_priority;
 
1005
  gint timeout;
 
1006
  gint n;
 
1007
  gint i, j;
 
1008
  va_list ap;
 
1009
 
 
1010
  context = g_main_context_default ();
 
1011
 
 
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 */
 
1016
 
 
1017
  va_start (ap, n_to_poll);
 
1018
  for (i = 0; i < n_to_poll; i++)
 
1019
    {
 
1020
      gint expected_fd = va_arg (ap, gint);
 
1021
      GIOCondition expected_events = va_arg (ap, GIOCondition);
 
1022
      GIOCondition report_events = va_arg (ap, GIOCondition);
 
1023
 
 
1024
      for (j = 0; j < n; j++)
 
1025
        if (!consumed[j] && poll_fds[j].fd == expected_fd && poll_fds[j].events == expected_events)
 
1026
          {
 
1027
            poll_fds[j].revents = report_events;
 
1028
            consumed[j] = TRUE;
 
1029
            break;
 
1030
          }
 
1031
 
 
1032
      if (j == n)
 
1033
        g_error ("Unable to find fd %d (index %d) with events 0x%x\n", expected_fd, i, (guint) expected_events);
 
1034
    }
 
1035
  va_end (ap);
 
1036
 
 
1037
  /* find the gwakeup, flag as non-ready */
 
1038
  for (i = 0; i < n; i++)
 
1039
    if (!consumed[i])
 
1040
      poll_fds[i].revents = 0;
 
1041
 
 
1042
  if (g_main_context_check (context, max_priority, poll_fds, n))
 
1043
    g_main_context_dispatch (context);
 
1044
}
 
1045
 
 
1046
static gboolean
 
1047
flag_bool (gint         fd,
 
1048
           GIOCondition condition,
 
1049
           gpointer     user_data)
 
1050
{
 
1051
  gboolean *flag = user_data;
 
1052
 
 
1053
  *flag = TRUE;
 
1054
 
 
1055
  return TRUE;
 
1056
}
 
1057
 
 
1058
static void
 
1059
test_unix_fd_source (void)
 
1060
{
 
1061
  GSource *out_source;
 
1062
  GSource *in_source;
 
1063
  GSource *source;
 
1064
  gboolean out, in;
 
1065
  gint fds[2];
 
1066
  gint s;
 
1067
 
 
1068
  assert_main_context_state (0);
 
1069
 
 
1070
  s = pipe (fds);
 
1071
  g_assert (s == 0);
 
1072
 
 
1073
  source = g_unix_fd_source_new (fds[1], G_IO_OUT);
 
1074
  g_source_attach (source, NULL);
 
1075
 
 
1076
  /* Check that a source with no callback gets successfully detached
 
1077
   * with a warning printed.
 
1078
   */
 
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);
 
1084
 
 
1085
  out = in = FALSE;
 
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);
 
1092
 
 
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);
 
1102
 
 
1103
  /* raise the priority of the in source to higher than out*/
 
1104
  in = out = FALSE;
 
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);
 
1110
 
 
1111
  /* now, let them be equal */
 
1112
  in = out = FALSE;
 
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);
 
1118
 
 
1119
  g_source_destroy (out_source);
 
1120
  g_source_destroy (in_source);
 
1121
  close (fds[1]);
 
1122
  close (fds[0]);
 
1123
}
 
1124
 
 
1125
typedef struct
 
1126
{
 
1127
  GSource parent;
 
1128
  gboolean flagged;
 
1129
} FlagSource;
 
1130
 
 
1131
static gboolean
 
1132
return_true (GSource *source, GSourceFunc callback, gpointer user_data)
 
1133
{
 
1134
  FlagSource *flag_source = (FlagSource *) source;
 
1135
 
 
1136
  flag_source->flagged = TRUE;
 
1137
 
 
1138
  return TRUE;
 
1139
}
 
1140
 
 
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
 
1144
 
 
1145
static void
 
1146
test_source_unix_fd_api (void)
 
1147
{
 
1148
  GSourceFuncs no_funcs = {
 
1149
    NULL, NULL, return_true
 
1150
  };
 
1151
  GSource *source_a;
 
1152
  GSource *source_b;
 
1153
  gpointer tag1, tag2;
 
1154
  gint fds_a[2];
 
1155
  gint fds_b[2];
 
1156
 
 
1157
  pipe (fds_a);
 
1158
  pipe (fds_b);
 
1159
 
 
1160
  source_a = g_source_new (&no_funcs, sizeof (FlagSource));
 
1161
  source_b = g_source_new (&no_funcs, sizeof (FlagSource));
 
1162
 
 
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);
 
1171
 
 
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);
 
1181
 
 
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);
 
1194
 
 
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);
 
1206
 
 
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);
 
1219
 
 
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);
 
1228
 
 
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);
 
1236
 
 
1237
  /* destroy the sources */
 
1238
  g_source_destroy (source_a);
 
1239
  g_source_destroy (source_b);
 
1240
  assert_main_context_state (0);
 
1241
 
 
1242
  g_source_unref (source_a);
 
1243
  g_source_unref (source_b);
 
1244
  close (fds_a[0]);
 
1245
  close (fds_a[1]);
 
1246
  close (fds_b[0]);
 
1247
  close (fds_b[1]);
 
1248
}
 
1249
 
 
1250
#endif
 
1251
 
 
1252
int
 
1253
main (int argc, char *argv[])
 
1254
{
 
1255
  g_test_init (&argc, &argv, NULL);
 
1256
 
 
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);
 
1268
#ifdef G_OS_UNIX
 
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);
 
1272
#endif
 
1273
 
 
1274
  return g_test_run ();
 
1275
}