Mark some functions 'static' in glib/tests
[platform/upstream/glib.git] / glib / tests / cond.c
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   next = value;
37   if (g_test_verbose ())
38     g_print ("Thread %p producing next value: %d\n", g_thread_self (), value);
39   if (value % 10 == 0)
40     g_cond_broadcast (&cond);
41   else
42     g_cond_signal (&cond);
43   g_mutex_unlock (&mutex);
44 }
45
46 static gint
47 pop_value (void)
48 {
49   gint value;
50
51   g_mutex_lock (&mutex);
52   while (next == 0)
53     {
54       if (g_test_verbose ())
55         g_print ("Thread %p waiting for cond\n", g_thread_self ());
56       g_cond_wait (&cond, &mutex);
57     }
58   value = next;
59   next = 0;
60   if (g_test_verbose ())
61     g_print ("Thread %p consuming value %d\n", g_thread_self (), value);
62   g_mutex_unlock (&mutex);
63
64   return value;
65 }
66
67 static gpointer
68 produce_values (gpointer data)
69 {
70   gint total;
71   gint i;
72
73   total = 0;
74
75   for (i = 1; i < 100; i++)
76     {
77       total += i;
78       push_value (i);
79       g_usleep (1000);
80     }
81
82   push_value (-1);
83   g_usleep (1000);
84   push_value (-1);
85
86   if (g_test_verbose ())
87     g_print ("Thread %p produced %d altogether\n", g_thread_self (), total);
88
89   return GINT_TO_POINTER (total);
90 }
91
92 static gpointer
93 consume_values (gpointer data)
94 {
95   gint accum = 0;
96   gint value;
97
98   while (TRUE)
99     {
100       value = pop_value ();
101       if (value == -1)
102         break;
103
104       accum += value;
105     }
106
107   if (g_test_verbose ())
108     g_print ("Thread %p accumulated %d\n", g_thread_self (), accum);
109
110   return GINT_TO_POINTER (accum);
111 }
112
113 static GThread *producer, *consumer1, *consumer2;
114
115 static void
116 test_cond1 (void)
117 {
118   gint total, acc1, acc2;
119
120   producer = g_thread_create (produce_values, NULL, TRUE, NULL);
121   consumer1 = g_thread_create (consume_values, NULL, TRUE, NULL);
122   consumer2 = g_thread_create (consume_values, NULL, TRUE, NULL);
123
124   total = GPOINTER_TO_INT (g_thread_join (producer));
125   acc1 = GPOINTER_TO_INT (g_thread_join (consumer1));
126   acc2 = GPOINTER_TO_INT (g_thread_join (consumer2));
127
128   g_assert_cmpint (total, ==, acc1 + acc2);
129 }
130
131 typedef struct
132 {
133   GMutex mutex;
134   GCond  cond;
135   gint   limit;
136   gint   count;
137 } Barrier;
138
139 static void
140 barrier_init (Barrier *barrier,
141               gint     limit)
142 {
143   g_mutex_init (&barrier->mutex);
144   g_cond_init (&barrier->cond);
145   barrier->limit = limit;
146   barrier->count = limit;
147 }
148
149 static gint
150 barrier_wait (Barrier *barrier)
151 {
152   gint ret;
153
154   g_mutex_lock (&barrier->mutex);
155   barrier->count--;
156   if (barrier->count == 0)
157     {
158       ret = -1;
159       barrier->count = barrier->limit;
160       g_cond_broadcast (&barrier->cond);
161     }
162   else
163     {
164       ret = 0;
165       while (barrier->count != barrier->limit)
166         g_cond_wait (&barrier->cond, &barrier->mutex);
167     }
168   g_mutex_unlock (&barrier->mutex);
169
170   return ret;
171 }
172
173 static Barrier b;
174 static gint check;
175
176 static gpointer
177 cond2_func (gpointer data)
178 {
179   gint value = GPOINTER_TO_INT (data);
180   gint ret;
181
182   g_atomic_int_inc (&check);
183
184   if (g_test_verbose ())
185     g_print ("thread %d starting, check %d\n", value, g_atomic_int_get (&check));
186
187   g_usleep (10000 * value);
188
189   g_atomic_int_inc (&check);
190
191   if (g_test_verbose ())
192     g_print ("thread %d reaching barrier, check %d\n", value, g_atomic_int_get (&check));
193
194   ret = barrier_wait (&b);
195
196   g_assert_cmpint (g_atomic_int_get (&check), ==, 10);
197
198   if (g_test_verbose ())
199     g_print ("thread %d leaving barrier (%d), check %d\n", value, ret, g_atomic_int_get (&check));
200
201   return NULL;
202 }
203
204 /* this test demonstrates how to use a condition variable
205  * to implement a barrier
206  */
207 static void
208 test_cond2 (void)
209 {
210   gint i;
211   GThread *threads[5];
212
213   g_atomic_int_set (&check, 0);
214
215   barrier_init (&b, 5);
216   for (i = 0; i < 5; i++)
217     threads[i] = g_thread_create (cond2_func, GINT_TO_POINTER (i), TRUE, NULL);
218
219   for (i = 0; i < 5; i++)
220     g_thread_join (threads[i]);
221
222   g_assert_cmpint (g_atomic_int_get (&check), ==, 10);
223 }
224
225 int
226 main (int argc, char *argv[])
227 {
228   g_test_init (&argc, &argv, NULL);
229
230   g_test_add_func ("/thread/cond1", test_cond1);
231   g_test_add_func ("/thread/cond2", test_cond2);
232
233   return g_test_run ();
234 }