task: Fix pause/stop race condition
[platform/upstream/gstreamer.git] / tests / check / gst / gsttask.c
1 /* GStreamer
2  * Copyright (C) 2005 Thomas Vander Stichele <thomas at apestaart dot org>
3  *
4  * gsttask.c: Unit test for GstTask
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include <gst/check/gstcheck.h>
23
24 static GMutex task_lock;
25 static GCond task_cond;
26
27 static GRecMutex task_mutex;
28
29 #define TEST_RACE_ITERATIONS 1000
30
31 static void
32 task_signal_pause_func (void *data)
33 {
34   GstTask **t = data;
35
36   g_mutex_lock (&task_lock);
37   GST_DEBUG ("signal");
38   g_cond_signal (&task_cond);
39
40   gst_task_pause (*t);
41   g_mutex_unlock (&task_lock);
42 }
43
44 GST_START_TEST (test_pause_stop_race)
45 {
46   guint it = TEST_RACE_ITERATIONS;
47   GstTask *t;
48   gboolean ret;
49
50   t = gst_task_new (task_signal_pause_func, &t, NULL);
51   fail_if (t == NULL);
52
53   g_rec_mutex_init (&task_mutex);
54   gst_task_set_lock (t, &task_mutex);
55
56   g_cond_init (&task_cond);
57   g_mutex_init (&task_lock);
58
59   while (it-- > 0) {
60     g_mutex_lock (&task_lock);
61     GST_DEBUG ("starting");
62     ret = gst_task_start (t);
63     fail_unless (ret == TRUE);
64     /* wait for it to spin up */
65     GST_DEBUG ("waiting");
66     g_cond_wait (&task_cond, &task_lock);
67     GST_DEBUG ("done waiting");
68     g_mutex_unlock (&task_lock);
69
70     GST_DEBUG ("starting");
71     ret = gst_task_stop (t);
72     fail_unless (ret == TRUE);
73
74     GST_DEBUG ("joining");
75     ret = gst_task_join (t);
76     fail_unless (ret == TRUE);
77   }
78
79   g_cond_clear (&task_cond);
80   g_mutex_clear (&task_lock);
81
82   gst_object_unref (t);
83 }
84
85 GST_END_TEST;
86
87 static void
88 task_func2 (void *data)
89 {
90   gboolean ret;
91   GstTask *t = *((GstTask **) data);
92
93   g_mutex_lock (&task_lock);
94   GST_DEBUG ("signal");
95   g_cond_signal (&task_cond);
96   g_mutex_unlock (&task_lock);
97
98   ASSERT_WARNING (ret = gst_task_join (t));
99   fail_unless (ret == FALSE);
100 }
101
102 GST_START_TEST (test_join)
103 {
104   GstTask *t;
105   gboolean ret;
106
107   t = gst_task_new (task_func2, &t, NULL);
108   fail_if (t == NULL);
109
110   g_rec_mutex_init (&task_mutex);
111   gst_task_set_lock (t, &task_mutex);
112
113   g_cond_init (&task_cond);
114   g_mutex_init (&task_lock);
115
116   g_mutex_lock (&task_lock);
117   GST_DEBUG ("starting");
118   ret = gst_task_start (t);
119   fail_unless (ret == TRUE);
120   /* wait for it to spin up */
121   GST_DEBUG ("waiting");
122   g_cond_wait (&task_cond, &task_lock);
123   GST_DEBUG ("done waiting");
124   g_mutex_unlock (&task_lock);
125
126   GST_DEBUG ("joining");
127   ret = gst_task_join (t);
128   fail_unless (ret == TRUE);
129
130   gst_task_cleanup_all ();
131
132   gst_object_unref (t);
133 }
134
135 GST_END_TEST;
136
137 static void
138 task_func (void *data)
139 {
140   g_mutex_lock (&task_lock);
141   GST_DEBUG ("signal");
142   g_cond_signal (&task_cond);
143   g_mutex_unlock (&task_lock);
144 }
145
146 GST_START_TEST (test_lock_start)
147 {
148   GstTask *t;
149   gboolean ret;
150
151   t = gst_task_new (task_func, NULL, NULL);
152   fail_if (t == NULL);
153
154   g_rec_mutex_init (&task_mutex);
155   gst_task_set_lock (t, &task_mutex);
156
157   g_cond_init (&task_cond);
158   g_mutex_init (&task_lock);
159
160   g_mutex_lock (&task_lock);
161   GST_DEBUG ("starting");
162   ret = gst_task_start (t);
163   fail_unless (ret == TRUE);
164   /* wait for it to spin up */
165   GST_DEBUG ("waiting");
166   g_cond_wait (&task_cond, &task_lock);
167   GST_DEBUG ("done waiting");
168   g_mutex_unlock (&task_lock);
169
170   /* cannot set mutex now */
171   ASSERT_WARNING (gst_task_set_lock (t, &task_mutex));
172
173   GST_DEBUG ("joining");
174   ret = gst_task_join (t);
175   fail_unless (ret == TRUE);
176
177   gst_task_cleanup_all ();
178
179   gst_object_unref (t);
180 }
181
182 GST_END_TEST;
183
184 GST_START_TEST (test_lock)
185 {
186   GstTask *t;
187   gboolean ret;
188
189   t = gst_task_new (task_func, NULL, NULL);
190   fail_if (t == NULL);
191
192   g_rec_mutex_init (&task_mutex);
193   gst_task_set_lock (t, &task_mutex);
194
195   GST_DEBUG ("pause");
196   ret = gst_task_pause (t);
197   fail_unless (ret == TRUE);
198
199   g_usleep (1 * G_USEC_PER_SEC / 2);
200
201   GST_DEBUG ("joining");
202   ret = gst_task_join (t);
203   fail_unless (ret == TRUE);
204
205   g_usleep (1 * G_USEC_PER_SEC / 2);
206
207   gst_object_unref (t);
208 }
209
210 GST_END_TEST;
211
212 GST_START_TEST (test_no_lock)
213 {
214   GstTask *t;
215   gboolean ret;
216
217   t = gst_task_new (task_func, NULL, NULL);
218   fail_if (t == NULL);
219
220   /* stop should be possible without lock */
221   gst_task_stop (t);
222
223   /* pause should give a warning */
224   ASSERT_WARNING (ret = gst_task_pause (t));
225   fail_unless (ret == FALSE);
226
227   /* start should give a warning */
228   ASSERT_WARNING (ret = gst_task_start (t));
229   fail_unless (ret == FALSE);
230
231   /* stop should be possible without lock */
232   gst_task_stop (t);
233
234   gst_object_unref (t);
235 }
236
237 GST_END_TEST;
238
239 GST_START_TEST (test_create)
240 {
241   GstTask *t;
242
243   t = gst_task_new (task_func, NULL, NULL);
244   fail_if (t == NULL);
245
246   gst_object_unref (t);
247 }
248
249 GST_END_TEST;
250
251
252 static Suite *
253 gst_task_suite (void)
254 {
255   Suite *s = suite_create ("GstTask");
256   TCase *tc_chain = tcase_create ("task tests");
257
258   suite_add_tcase (s, tc_chain);
259   tcase_add_test (tc_chain, test_create);
260   tcase_add_test (tc_chain, test_no_lock);
261   tcase_add_test (tc_chain, test_lock);
262   tcase_add_test (tc_chain, test_lock_start);
263   tcase_add_test (tc_chain, test_join);
264   tcase_add_test (tc_chain, test_pause_stop_race);
265
266   return s;
267 }
268
269 GST_CHECK_MAIN (gst_task);