qml: make TabButtonExt text bold
[vlc.git] / src / test / executor.c
blob9acc25c076e39c4908c3f1c013ba2fc582681882
1 /*****************************************************************************
2 * src/test/executor.c
3 *****************************************************************************
4 * Copyright (C) 2020 Videolabs, VLC authors and VideoLAN
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 #undef NDEBUG
27 #include <assert.h>
29 #include <vlc_common.h>
30 #include <vlc_executor.h>
31 #include <vlc_tick.h>
33 struct data
35 vlc_mutex_t lock;
36 vlc_cond_t cond;
37 int started;
38 int ended;
39 vlc_tick_t delay;
42 static void InitData(struct data *data)
44 vlc_mutex_init(&data->lock);
45 vlc_cond_init(&data->cond);
46 data->started = 0;
47 data->ended = 0;
48 data->delay = 0;
51 static void RunIncrement(void *userdata)
53 struct data *data = userdata;
55 vlc_mutex_lock(&data->lock);
56 ++data->started;
57 vlc_mutex_unlock(&data->lock);
59 if (data->delay > 0)
60 vlc_tick_sleep(data->delay);
62 vlc_mutex_lock(&data->lock);
63 ++data->ended;
64 vlc_mutex_unlock(&data->lock);
66 vlc_cond_signal(&data->cond);
69 static void test_single_runnable(void)
71 vlc_executor_t *executor = vlc_executor_New(1);
72 assert(executor);
74 struct data data;
75 InitData(&data);
77 struct vlc_runnable runnable = {
78 .run = RunIncrement,
79 .userdata = &data,
82 vlc_executor_Submit(executor, &runnable);
84 vlc_mutex_lock(&data.lock);
85 while (data.ended == 0)
86 vlc_cond_wait(&data.cond, &data.lock);
87 vlc_mutex_unlock(&data.lock);
89 assert(data.ended == 1);
91 vlc_executor_Delete(executor);
94 static void test_multiple_runnables(void)
96 vlc_executor_t *executor = vlc_executor_New(3);
97 assert(executor);
99 struct data shared_data;
100 InitData(&shared_data);
102 struct vlc_runnable runnables[300];
103 for (int i = 0; i < 300; ++i)
105 struct vlc_runnable *runnable = &runnables[i];
106 runnable->run = RunIncrement;
107 runnable->userdata = &shared_data;
108 vlc_executor_Submit(executor, runnable);
111 vlc_mutex_lock(&shared_data.lock);
112 while (shared_data.ended < 300)
113 vlc_cond_wait(&shared_data.cond, &shared_data.lock);
114 vlc_mutex_unlock(&shared_data.lock);
116 assert(shared_data.ended == 300);
118 vlc_executor_Delete(executor);
121 static void test_blocking_delete(void)
123 vlc_executor_t *executor = vlc_executor_New(1);
124 assert(executor);
126 struct data data;
127 InitData(&data);
129 data.delay = VLC_TICK_FROM_MS(100);
131 struct vlc_runnable runnable = {
132 .run = RunIncrement,
133 .userdata = &data,
136 vlc_executor_Submit(executor, &runnable);
138 /* Wait for the runnable to be started */
139 vlc_mutex_lock(&data.lock);
140 while (data.started == 0)
141 vlc_cond_wait(&data.cond, &data.lock);
142 vlc_mutex_unlock(&data.lock);
144 /* The runnable sleeps for about 100ms */
146 vlc_executor_Delete(executor);
148 vlc_mutex_lock(&data.lock);
149 /* The executor must wait the end of running tasks on delete */
150 assert(data.ended == 1);
151 vlc_mutex_unlock(&data.lock);
154 static void test_cancel(void)
156 vlc_executor_t *executor = vlc_executor_New(4);
157 assert(executor);
159 struct data shared_data;
160 InitData(&shared_data);
162 shared_data.delay = VLC_TICK_FROM_MS(100);
164 /* Submit 40 tasks taking at least 100ms on an executor with at most 4
165 * threads */
167 struct vlc_runnable runnables[40];
168 for (int i = 0; i < 40; ++i)
170 struct vlc_runnable *runnable = &runnables[i];
171 runnable->run = RunIncrement;
172 runnable->userdata = &shared_data;
173 vlc_executor_Submit(executor, runnable);
176 /* Wait a bit (in two lines to avoid harmful_delay() warning) */
177 vlc_tick_t delay = VLC_TICK_FROM_MS(150);
178 vlc_tick_sleep(delay);
180 int canceled = 0;
181 for (int i = 0; i < 40; ++i)
183 if (vlc_executor_Cancel(executor, &runnables[i]))
184 ++canceled;
187 vlc_mutex_lock(&shared_data.lock);
188 /* All started must not be canceled (but some non-started-yet may not be
189 * canceled either) */
190 assert(canceled + shared_data.started <= 40);
191 vlc_mutex_unlock(&shared_data.lock);
193 vlc_executor_Delete(executor);
195 /* Every started task must also be ended */
196 assert(shared_data.started == shared_data.ended);
197 /* Every task is either canceled or ended */
198 assert(canceled + shared_data.ended == 40);
201 struct doubler_task
203 vlc_executor_t *executor;
204 int *array;
205 size_t count;
206 struct vlc_runnable runnable;
209 static void DoublerRun(void *);
211 static bool
212 SpawnDoublerTask(vlc_executor_t *executor, int *array, size_t count)
214 struct doubler_task *task = malloc(sizeof(*task));
215 if (!task)
216 return false;
218 task->executor = executor;
219 task->array = array;
220 task->count = count;
221 task->runnable.run = DoublerRun;
222 task->runnable.userdata = task;
224 vlc_executor_Submit(executor, &task->runnable);
226 return true;
229 static void DoublerRun(void *userdata)
231 struct doubler_task *task = userdata;
233 if (task->count == 1)
234 task->array[0] *= 2; /* double the value */
235 else
237 /* Spawn tasks doubling halves of the array recursively */
238 bool ok;
240 ok = SpawnDoublerTask(task->executor, task->array, task->count / 2);
241 assert(ok);
243 ok = SpawnDoublerTask(task->executor, task->array + task->count / 2,
244 task->count - task->count / 2);
245 assert(ok);
248 free(task);
251 static void test_task_chain(void)
253 vlc_executor_t *executor = vlc_executor_New(4);
254 assert(executor);
256 /* Numbers from 0 to 99 */
257 int array[100];
258 for (int i = 0; i < 100; ++i)
259 array[i] = i;
261 /* Double all values in the array from tasks spawning smaller tasks
262 * recursively, until the array has size 1, where the single value is
263 * doubled */
264 SpawnDoublerTask(executor, array, 100);
266 vlc_executor_WaitIdle(executor);
267 vlc_executor_Delete(executor);
269 /* All values must have been doubled */
270 for (int i = 0; i < 100; ++i)
271 assert(array[i] == 2 * i);
274 int main(void)
276 test_single_runnable();
277 test_multiple_runnables();
278 test_blocking_delete();
279 test_cancel();
280 test_task_chain();
281 return 0;