lib: media_track: add new members
[vlc.git] / src / test / thread.c
blob703bcc2afaad1fa994e36a41257b2b40a6be9279
1 /*****************************************************************************
2 * thread.c: Test for thread API
3 *****************************************************************************
4 * Copyright (C) 2020 Marvin Scholz
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program 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
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #undef NDEBUG
29 #include <assert.h>
31 #include <vlc_common.h>
33 static int thread_data_magic = 0x1234;
34 static int thread_return_magic = 0x4321;
36 // Join thread and verify return
37 #define TEST_THREAD_JOIN(th, eret) \
38 do { \
39 void *r; \
40 vlc_join(th, &r); \
41 assert(r == eret); \
42 } while (0)
44 // Cancels thread, joins and verifies return
45 #define TEST_THREAD_CANCEL_JOIN(th) \
46 do { \
47 vlc_cancel(th); \
48 TEST_THREAD_JOIN(th, VLC_THREAD_CANCELED); \
49 } while (0)
51 // Join thread and verify magic return value
52 #define TEST_THREAD_JOIN_MAGIC(th) \
53 TEST_THREAD_JOIN(th, &thread_return_magic)
55 // Spawn thread
56 #define TEST_THREAD_CLONE(th, f, data) \
57 assert(vlc_clone(th, f, data, VLC_THREAD_PRIORITY_LOW) == 0)
59 // Spawn thread with magic data
60 #define TEST_THREAD_CLONE_MAGIC(th, f) \
61 TEST_THREAD_CLONE(th, f, &thread_data_magic)
64 // Structure for the condition tests
65 struct cond_data
67 int state; // Count of threads starting, or -1 when threads may exit
68 vlc_mutex_t mutex;
69 vlc_cond_t cond_started; // Signalled when a thread started
70 vlc_cond_t cond_end; // Waited on by thread before terminating
73 static void cond_data_init(struct cond_data *data, int count)
75 assert(count > 0);
77 data->state = count;
78 vlc_mutex_init(&data->mutex);
79 vlc_cond_init(&data->cond_started);
80 vlc_cond_init(&data->cond_end);
85 * Test simple thread creation
87 static void *thread_func_noop(void *data)
89 assert(data == &thread_data_magic);
90 return &thread_return_magic;
93 static void test__thread_create()
95 vlc_thread_t th;
96 TEST_THREAD_CLONE_MAGIC(&th, thread_func_noop);
97 TEST_THREAD_JOIN_MAGIC(th);
102 * Test simple thread cancelation
104 static void *thread_func_loop(void *data)
106 assert(data == &thread_data_magic);
107 while(1) {
108 sleep(10);
110 return &thread_return_magic;
113 static void test__thread_cancelation()
115 vlc_thread_t th;
116 TEST_THREAD_CLONE_MAGIC(&th, thread_func_loop);
117 TEST_THREAD_CANCEL_JOIN(th);
122 * Test thread cancellation with cleanup
124 static void thread_func_cleanup(void *data)
126 int *cleanup_state = data;
127 assert(*cleanup_state == 0);
128 *cleanup_state = 1;
131 static void *thread_func_loop_cleanup(void *data)
133 int *cleanup_state = data;
134 assert(*cleanup_state == 0);
136 vlc_cleanup_push(thread_func_cleanup, data);
137 while(1) {
138 vlc_testcancel();
140 vlc_cleanup_pop();
142 return &thread_return_magic;
145 static void test__thread_cancelation_with_cleanup()
147 vlc_thread_t th;
148 int th_cleanup_state = 0;
150 TEST_THREAD_CLONE(&th, thread_func_loop_cleanup, &th_cleanup_state);
151 TEST_THREAD_CANCEL_JOIN(th);
152 assert(th_cleanup_state == 1);
157 * - Test broadcasting a condition, waking several threads
158 * - Test waiting on condition
160 static void *thread_func_cond(void *ptr)
162 struct cond_data *data = ptr;
164 // Decrement state and signal start of thread
165 vlc_mutex_lock(&data->mutex);
166 data->state -= 1;
167 vlc_cond_signal(&data->cond_started);
168 vlc_mutex_unlock(&data->mutex);
170 // Wait until termination is allowed
171 vlc_mutex_lock(&data->mutex);
172 mutex_cleanup_push(&data->mutex);
173 while(data->state != -1) {
174 vlc_cond_wait(&data->cond_end, &data->mutex);
176 vlc_cleanup_pop();
177 vlc_mutex_unlock(&data->mutex);
179 return &thread_return_magic;
182 static void test__cond_broadcast()
184 struct cond_data data;
185 vlc_thread_t threads[20];
187 cond_data_init(&data, ARRAY_SIZE(threads));
189 // Spawn all threads
190 for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
191 TEST_THREAD_CLONE(&threads[i], thread_func_cond, &data);
194 // Wait for all threads to start
195 vlc_mutex_lock(&data.mutex);
196 while(data.state > 0) {
197 vlc_cond_wait(&data.cond_started, &data.mutex);
199 vlc_mutex_unlock(&data.mutex);
201 // Broadcast threads-may-end condition to all threads
202 vlc_mutex_lock(&data.mutex);
203 data.state = -1;
204 vlc_cond_broadcast(&data.cond_end);
205 vlc_mutex_unlock(&data.mutex);
207 // Wait for all threads to exit
208 for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
209 TEST_THREAD_JOIN_MAGIC(threads[i]);
213 static void test__cond_wait()
215 struct cond_data data;
216 cond_data_init(&data, 1);
218 vlc_thread_t th;
219 TEST_THREAD_CLONE(&th, thread_func_cond, &data);
221 // Wait for thread to start
222 vlc_mutex_lock(&data.mutex);
223 while(data.state != 0) {
224 vlc_cond_wait(&data.cond_started, &data.mutex);
226 vlc_mutex_unlock(&data.mutex);
228 // Signal threads-may-end condition to thread
229 vlc_mutex_lock(&data.mutex);
230 data.state = -1;
231 vlc_cond_signal(&data.cond_end);
232 vlc_mutex_unlock(&data.mutex);
234 // Wait for thread to exit
235 TEST_THREAD_JOIN_MAGIC(th);
240 * Test waiting on condition and let it timeout
242 static void *thread_func_cond_timeout(void *ptr)
244 struct cond_data *data = ptr;
246 // Decrement state and signal start of thread
247 vlc_mutex_lock(&data->mutex);
248 data->state -= 1;
249 vlc_cond_signal(&data->cond_started);
250 vlc_mutex_unlock(&data->mutex);
252 vlc_mutex_lock(&data->mutex);
253 mutex_cleanup_push(&data->mutex);
255 // Wait until termination is allowed (which is never signalled)
256 vlc_tick_t now = vlc_tick_now();
257 vlc_tick_t deadline = now + VLC_TICK_FROM_MS(25);
258 int ret = vlc_cond_timedwait(&data->cond_end, &data->mutex, deadline);
259 assert(ret == ETIMEDOUT);
261 vlc_tick_t elapsed = vlc_tick_now() - now;
262 assert(elapsed >= VLC_TICK_FROM_MS(25));
264 vlc_cleanup_pop();
265 vlc_mutex_unlock(&data->mutex);
267 return &thread_return_magic;
270 static void test__cond_wait_timeout()
272 struct cond_data data;
273 cond_data_init(&data, 1);
275 vlc_thread_t th;
276 TEST_THREAD_CLONE(&th, thread_func_cond_timeout, &data);
278 // Wait for thread to start
279 vlc_mutex_lock(&data.mutex);
280 while(data.state != 0) {
281 vlc_cond_wait(&data.cond_started, &data.mutex);
283 vlc_mutex_unlock(&data.mutex);
285 // Never signal that the thread may end, on purpose
286 // as it should timeout.
288 // Wait for thread exit
289 TEST_THREAD_JOIN_MAGIC(th);
294 * Test cancelling vlc_tick_sleep
296 static void *thread_func_tick_sleep(void *data)
298 assert(data == &thread_data_magic);
299 vlc_tick_sleep(VLC_TICK_FROM_SEC(10));
300 return &thread_return_magic;
303 static void test__vlc_tick_sleep_cancelation()
305 vlc_thread_t th;
306 TEST_THREAD_CLONE_MAGIC(&th, thread_func_tick_sleep);
307 TEST_THREAD_CANCEL_JOIN(th);
312 * Test sleeping for delay with vlc_tick_sleep
314 static void test__vlc_tick_sleep()
316 vlc_tick_t now = vlc_tick_now();
318 vlc_tick_sleep(VLC_TICK_FROM_MS(25));
320 vlc_tick_t elapsed = vlc_tick_now() - now;
321 assert(elapsed >= VLC_TICK_FROM_MS(25));
326 * Main function executing all tests above
328 int main(void)
330 alarm(4);
332 test__thread_create();
333 test__thread_cancelation();
334 test__thread_cancelation_with_cleanup();
335 test__cond_wait();
336 test__cond_wait_timeout();
337 test__cond_broadcast();
338 test__vlc_tick_sleep_cancelation();
339 test__vlc_tick_sleep();
341 return 0;