two test fixes for ARM
[platform/upstream/glib.git] / glib / tests / gwakeuptest.c
1 #include <unistd.h>
2 #include <glib.h>
3 #include <glib/gwakeup.h>
4
5 #ifdef _WIN32
6 void alarm (int sec) { }
7 #endif
8
9 static gboolean
10 check_signaled (GWakeup *wakeup)
11 {
12   GPollFD fd;
13
14   g_wakeup_get_pollfd (wakeup, &fd);
15   return g_poll (&fd, 1, 0);
16 }
17
18 static void
19 wait_for_signaled (GWakeup *wakeup)
20 {
21   GPollFD fd;
22
23   g_wakeup_get_pollfd (wakeup, &fd);
24   g_poll (&fd, 1, -1);
25 }
26
27 static void
28 test_semantics (void)
29 {
30   GWakeup *wakeup;
31   gint i;
32
33   /* prevent the test from deadlocking */
34   alarm (60);
35
36   wakeup = g_wakeup_new ();
37   g_assert (!check_signaled (wakeup));
38
39   g_wakeup_signal (wakeup);
40   g_assert (check_signaled (wakeup));
41
42   g_wakeup_acknowledge (wakeup);
43   g_assert (!check_signaled (wakeup));
44
45   g_wakeup_free (wakeup);
46
47   /* free unused */
48   wakeup = g_wakeup_new ();
49   g_wakeup_free (wakeup);
50
51   /* free while signaled */
52   wakeup = g_wakeup_new ();
53   g_wakeup_signal (wakeup);
54   g_wakeup_free (wakeup);
55
56   /* ensure excessive signalling doesn't deadlock */
57   wakeup = g_wakeup_new ();
58   for (i = 0; i < 1000000; i++)
59     g_wakeup_signal (wakeup);
60   g_assert (check_signaled (wakeup));
61
62   /* ensure a single acknowledgement is sufficient */
63   g_wakeup_acknowledge (wakeup);
64   g_assert (!check_signaled (wakeup));
65
66   g_wakeup_free (wakeup);
67
68   /* cancel the alarm */
69   alarm (0);
70 }
71
72 struct token
73 {
74   gpointer owner;
75   gint ttl;
76 };
77
78 struct context
79 {
80   GSList *pending_tokens;
81   GMutex lock;
82   GWakeup *wakeup;
83   gboolean quit;
84 };
85
86 #define NUM_THREADS     50
87 #define NUM_TOKENS       5
88 #define TOKEN_TTL   100000
89
90 static struct context contexts[NUM_THREADS];
91 static GThread *threads[NUM_THREADS];
92 static GWakeup *last_token_wakeup;
93 static volatile gint tokens_alive;
94
95 static void
96 context_init (struct context *ctx)
97 {
98   ctx->pending_tokens = NULL;
99   g_mutex_init (&ctx->lock);
100   ctx->wakeup = g_wakeup_new ();
101   ctx->quit = FALSE;
102 }
103
104 static void
105 context_clear (struct context *ctx)
106 {
107   g_assert (ctx->pending_tokens == NULL);
108   g_assert (ctx->quit);
109
110   g_wakeup_free (ctx->wakeup);
111 }
112
113 static void
114 context_quit (struct context *ctx)
115 {
116   ctx->quit = TRUE;
117   g_wakeup_signal (ctx->wakeup);
118 }
119
120 static struct token *
121 context_pop_token (struct context *ctx)
122 {
123   struct token *token;
124
125   g_mutex_lock (&ctx->lock);
126   token = ctx->pending_tokens->data;
127   ctx->pending_tokens = g_slist_delete_link (ctx->pending_tokens,
128                                              ctx->pending_tokens);
129   g_mutex_unlock (&ctx->lock);
130
131   return token;
132 }
133
134 static void
135 context_push_token (struct context *ctx,
136                     struct token   *token)
137 {
138   g_assert (token->owner == ctx);
139
140   g_mutex_lock (&ctx->lock);
141   ctx->pending_tokens = g_slist_prepend (ctx->pending_tokens, token);
142   g_mutex_unlock (&ctx->lock);
143
144   g_wakeup_signal (ctx->wakeup);
145 }
146
147 static void
148 dispatch_token (struct token *token)
149 {
150   if (token->ttl > 0)
151     {
152       struct context *ctx;
153       gint next_ctx;
154
155       next_ctx = g_test_rand_int_range (0, NUM_THREADS);
156       ctx = &contexts[next_ctx];
157       token->owner = ctx;
158       token->ttl--;
159
160       context_push_token (ctx, token);
161     }
162   else
163     {
164       g_slice_free (struct token, token);
165
166       if (g_atomic_int_dec_and_test (&tokens_alive))
167         g_wakeup_signal (last_token_wakeup);
168     }
169 }
170
171 static struct token *
172 token_new (int ttl)
173 {
174   struct token *token;
175
176   token = g_slice_new (struct token);
177   token->ttl = ttl;
178
179   g_atomic_int_inc (&tokens_alive);
180
181   return token;
182 }
183
184 static gpointer
185 thread_func (gpointer data)
186 {
187   struct context *ctx = data;
188
189   while (!ctx->quit)
190     {
191       wait_for_signaled (ctx->wakeup);
192       g_wakeup_acknowledge (ctx->wakeup);
193
194       while (ctx->pending_tokens)
195         {
196           struct token *token;
197
198           token = context_pop_token (ctx);
199           g_assert (token->owner == ctx);
200           dispatch_token (token);
201         }
202     }
203
204   return NULL;
205 }
206
207 static void
208 test_threaded (void)
209 {
210   gint i;
211
212   /* make sure we don't block forever */
213   alarm (60);
214
215   /* simple mainloop test based on GWakeup.
216    *
217    * create a bunch of contexts and a thread to 'run' each one.  create
218    * some tokens and randomly pass them between the threads, until the
219    * TTL on each token is zero.
220    *
221    * when no tokens are left, signal that we are done.  the mainthread
222    * will then signal each worker thread to exit and join them to make
223    * sure that works.
224    */
225
226   last_token_wakeup = g_wakeup_new ();
227
228   /* create contexts, assign to threads */
229   for (i = 0; i < NUM_THREADS; i++)
230     {
231       context_init (&contexts[i]);
232       threads[i] = g_thread_new ("test", thread_func, &contexts[i]);
233     }
234
235   /* dispatch tokens */
236   for (i = 0; i < NUM_TOKENS; i++)
237     dispatch_token (token_new (TOKEN_TTL));
238
239   /* wait until all tokens are gone */
240   wait_for_signaled (last_token_wakeup);
241
242   /* ask threads to quit, join them, cleanup */
243   for (i = 0; i < NUM_THREADS; i++)
244     {
245       context_quit (&contexts[i]);
246       g_thread_join (threads[i]);
247       context_clear (&contexts[i]);
248     }
249
250   g_wakeup_free (last_token_wakeup);
251
252   /* cancel alarm */
253   alarm (0);
254 }
255
256 int
257 main (int argc, char **argv)
258 {
259   g_test_init (&argc, &argv, NULL);
260
261 #ifdef TEST_EVENTFD_FALLBACK
262 #define TESTNAME_SUFFIX "-fallback"
263 #else
264 #define TESTNAME_SUFFIX
265 #endif
266
267
268   g_test_add_func ("/gwakeup/semantics" TESTNAME_SUFFIX, test_semantics);
269   g_test_add_func ("/gwakeup/threaded" TESTNAME_SUFFIX, test_threaded);
270
271   return g_test_run ();
272 }