nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* Unit tests for GCond
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 /* We are testing some deprecated APIs here */
24 #define GLIB_DISABLE_DEPRECATION_WARNINGS
25  
26 #include <glib.h>
27  
28 static GCond cond;
29 static GMutex mutex;
30 static volatile gint next;
31  
32 static void
33 push_value (gint value)
34 {
35 g_mutex_lock (&mutex);
36 while (next != 0)
37 g_cond_wait (&cond, &mutex);
38 next = value;
39 if (g_test_verbose ())
40 g_printerr ("Thread %p producing next value: %d\n", g_thread_self (), value);
41 if (value % 10 == 0)
42 g_cond_broadcast (&cond);
43 else
44 g_cond_signal (&cond);
45 g_mutex_unlock (&mutex);
46 }
47  
48 static gint
49 pop_value (void)
50 {
51 gint value;
52  
53 g_mutex_lock (&mutex);
54 while (next == 0)
55 {
56 if (g_test_verbose ())
57 g_printerr ("Thread %p waiting for cond\n", g_thread_self ());
58 g_cond_wait (&cond, &mutex);
59 }
60 value = next;
61 next = 0;
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);
66  
67 return value;
68 }
69  
70 static gpointer
71 produce_values (gpointer data)
72 {
73 gint total;
74 gint i;
75  
76 total = 0;
77  
78 for (i = 1; i < 100; i++)
79 {
80 total += i;
81 push_value (i);
82 }
83  
84 push_value (-1);
85 push_value (-1);
86  
87 if (g_test_verbose ())
88 g_printerr ("Thread %p produced %d altogether\n", g_thread_self (), total);
89  
90 return GINT_TO_POINTER (total);
91 }
92  
93 static gpointer
94 consume_values (gpointer data)
95 {
96 gint accum = 0;
97 gint value;
98  
99 while (TRUE)
100 {
101 value = pop_value ();
102 if (value == -1)
103 break;
104  
105 accum += value;
106 }
107  
108 if (g_test_verbose ())
109 g_printerr ("Thread %p accumulated %d\n", g_thread_self (), accum);
110  
111 return GINT_TO_POINTER (accum);
112 }
113  
114 static GThread *producer, *consumer1, *consumer2;
115  
116 static void
117 test_cond1 (void)
118 {
119 gint total, acc1, acc2;
120  
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);
124  
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));
128  
129 g_assert_cmpint (total, ==, acc1 + acc2);
130 }
131  
132 typedef struct
133 {
134 GMutex mutex;
135 GCond cond;
136 gint limit;
137 gint count;
138 } Barrier;
139  
140 static void
141 barrier_init (Barrier *barrier,
142 gint limit)
143 {
144 g_mutex_init (&barrier->mutex);
145 g_cond_init (&barrier->cond);
146 barrier->limit = limit;
147 barrier->count = limit;
148 }
149  
150 static gint
151 barrier_wait (Barrier *barrier)
152 {
153 gint ret;
154  
155 g_mutex_lock (&barrier->mutex);
156 barrier->count--;
157 if (barrier->count == 0)
158 {
159 ret = -1;
160 barrier->count = barrier->limit;
161 g_cond_broadcast (&barrier->cond);
162 }
163 else
164 {
165 ret = 0;
166 while (barrier->count != barrier->limit)
167 g_cond_wait (&barrier->cond, &barrier->mutex);
168 }
169 g_mutex_unlock (&barrier->mutex);
170  
171 return ret;
172 }
173  
174 static void
175 barrier_clear (Barrier *barrier)
176 {
177 g_mutex_clear (&barrier->mutex);
178 g_cond_clear (&barrier->cond);
179 }
180  
181 static Barrier b;
182 static gint check;
183  
184 static gpointer
185 cond2_func (gpointer data)
186 {
187 gint value = GPOINTER_TO_INT (data);
188 gint ret;
189  
190 g_atomic_int_inc (&check);
191  
192 if (g_test_verbose ())
193 g_printerr ("thread %d starting, check %d\n", value, g_atomic_int_get (&check));
194  
195 g_usleep (10000 * value);
196  
197 g_atomic_int_inc (&check);
198  
199 if (g_test_verbose ())
200 g_printerr ("thread %d reaching barrier, check %d\n", value, g_atomic_int_get (&check));
201  
202 ret = barrier_wait (&b);
203  
204 g_assert_cmpint (g_atomic_int_get (&check), ==, 10);
205  
206 if (g_test_verbose ())
207 g_printerr ("thread %d leaving barrier (%d), check %d\n", value, ret, g_atomic_int_get (&check));
208  
209 return NULL;
210 }
211  
212 /* this test demonstrates how to use a condition variable
213 * to implement a barrier
214 */
215 static void
216 test_cond2 (void)
217 {
218 gint i;
219 GThread *threads[5];
220  
221 g_atomic_int_set (&check, 0);
222  
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);
226  
227 for (i = 0; i < 5; i++)
228 g_thread_join (threads[i]);
229  
230 g_assert_cmpint (g_atomic_int_get (&check), ==, 10);
231  
232 barrier_clear (&b);
233 }
234  
235 static void
236 test_wait_until (void)
237 {
238 gint64 until;
239 GMutex lock;
240 GCond cond;
241  
242 /* This test will make sure we don't wait too much or too little.
243 *
244 * We check the 'too long' with a timeout of 60 seconds.
245 *
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.
248 */
249 g_mutex_init (&lock);
250 g_cond_init (&cond);
251  
252 until = g_get_monotonic_time () + G_TIME_SPAN_SECOND;
253  
254 /* Could still have spurious wakeups, so we must loop... */
255 g_mutex_lock (&lock);
256 while (g_cond_wait_until (&cond, &lock, until))
257 ;
258 g_mutex_unlock (&lock);
259  
260 /* Make sure it's after the until time */
261 g_assert_cmpint (until, <=, g_get_monotonic_time ());
262  
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);
268  
269 g_mutex_clear (&lock);
270 g_cond_clear (&cond);
271 }
272  
273 int
274 main (int argc, char *argv[])
275 {
276 g_test_init (&argc, &argv, NULL);
277  
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);
281  
282 return g_test_run ();
283 }