1 /* Unit tests for GCond
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 /* We are testing some deprecated APIs here */
24 #define GLIB_DISABLE_DEPRECATION_WARNINGS
30 static volatile gint next
;
33 push_value (gint value
)
35 g_mutex_lock (&mutex
);
37 g_cond_wait (&cond
, &mutex
);
39 if (g_test_verbose ())
40 g_printerr ("Thread %p producing next value: %d\n", g_thread_self (), value
);
42 g_cond_broadcast (&cond
);
44 g_cond_signal (&cond
);
45 g_mutex_unlock (&mutex
);
53 g_mutex_lock (&mutex
);
56 if (g_test_verbose ())
57 g_printerr ("Thread %p waiting for cond\n", g_thread_self ());
58 g_cond_wait (&cond
, &mutex
);
62 g_cond_broadcast (&cond
);
63 if (g_test_verbose ())
64 g_printerr ("Thread %p consuming value %d\n", g_thread_self (), value
);
65 g_mutex_unlock (&mutex
);
71 produce_values (gpointer data
)
78 for (i
= 1; i
< 100; i
++)
87 if (g_test_verbose ())
88 g_printerr ("Thread %p produced %d altogether\n", g_thread_self (), total
);
90 return GINT_TO_POINTER (total
);
94 consume_values (gpointer data
)
101 value
= pop_value ();
108 if (g_test_verbose ())
109 g_printerr ("Thread %p accumulated %d\n", g_thread_self (), accum
);
111 return GINT_TO_POINTER (accum
);
114 static GThread
*producer
, *consumer1
, *consumer2
;
119 gint total
, acc1
, acc2
;
121 producer
= g_thread_create (produce_values
, NULL
, TRUE
, NULL
);
122 consumer1
= g_thread_create (consume_values
, NULL
, TRUE
, NULL
);
123 consumer2
= g_thread_create (consume_values
, NULL
, TRUE
, NULL
);
125 total
= GPOINTER_TO_INT (g_thread_join (producer
));
126 acc1
= GPOINTER_TO_INT (g_thread_join (consumer1
));
127 acc2
= GPOINTER_TO_INT (g_thread_join (consumer2
));
129 g_assert_cmpint (total
, ==, acc1
+ acc2
);
141 barrier_init (Barrier
*barrier
,
144 g_mutex_init (&barrier
->mutex
);
145 g_cond_init (&barrier
->cond
);
146 barrier
->limit
= limit
;
147 barrier
->count
= limit
;
151 barrier_wait (Barrier
*barrier
)
155 g_mutex_lock (&barrier
->mutex
);
157 if (barrier
->count
== 0)
160 barrier
->count
= barrier
->limit
;
161 g_cond_broadcast (&barrier
->cond
);
166 while (barrier
->count
!= barrier
->limit
)
167 g_cond_wait (&barrier
->cond
, &barrier
->mutex
);
169 g_mutex_unlock (&barrier
->mutex
);
175 barrier_clear (Barrier
*barrier
)
177 g_mutex_clear (&barrier
->mutex
);
178 g_cond_clear (&barrier
->cond
);
185 cond2_func (gpointer data
)
187 gint value
= GPOINTER_TO_INT (data
);
190 g_atomic_int_inc (&check
);
192 if (g_test_verbose ())
193 g_printerr ("thread %d starting, check %d\n", value
, g_atomic_int_get (&check
));
195 g_usleep (10000 * value
);
197 g_atomic_int_inc (&check
);
199 if (g_test_verbose ())
200 g_printerr ("thread %d reaching barrier, check %d\n", value
, g_atomic_int_get (&check
));
202 ret
= barrier_wait (&b
);
204 g_assert_cmpint (g_atomic_int_get (&check
), ==, 10);
206 if (g_test_verbose ())
207 g_printerr ("thread %d leaving barrier (%d), check %d\n", value
, ret
, g_atomic_int_get (&check
));
212 /* this test demonstrates how to use a condition variable
213 * to implement a barrier
221 g_atomic_int_set (&check
, 0);
223 barrier_init (&b
, 5);
224 for (i
= 0; i
< 5; i
++)
225 threads
[i
] = g_thread_create (cond2_func
, GINT_TO_POINTER (i
), TRUE
, NULL
);
227 for (i
= 0; i
< 5; i
++)
228 g_thread_join (threads
[i
]);
230 g_assert_cmpint (g_atomic_int_get (&check
), ==, 10);
236 test_wait_until (void)
242 /* This test will make sure we don't wait too much or too little.
244 * We check the 'too long' with a timeout of 60 seconds.
246 * We check the 'too short' by verifying a guarantee of the API: we
247 * should not wake up until the specified time has passed.
249 g_mutex_init (&lock
);
252 until
= g_get_monotonic_time () + G_TIME_SPAN_SECOND
;
254 /* Could still have spurious wakeups, so we must loop... */
255 g_mutex_lock (&lock
);
256 while (g_cond_wait_until (&cond
, &lock
, until
))
258 g_mutex_unlock (&lock
);
260 /* Make sure it's after the until time */
261 g_assert_cmpint (until
, <=, g_get_monotonic_time ());
263 /* Make sure it returns FALSE on timeout */
264 until
= g_get_monotonic_time () + G_TIME_SPAN_SECOND
/ 50;
265 g_mutex_lock (&lock
);
266 g_assert (g_cond_wait_until (&cond
, &lock
, until
) == FALSE
);
267 g_mutex_unlock (&lock
);
269 g_mutex_clear (&lock
);
270 g_cond_clear (&cond
);
274 main (int argc
, char *argv
[])
276 g_test_init (&argc
, &argv
, NULL
);
278 g_test_add_func ("/thread/cond1", test_cond1
);
279 g_test_add_func ("/thread/cond2", test_cond2
);
280 g_test_add_func ("/thread/cond/wait-until", test_wait_until
);
282 return g_test_run ();