Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
Data Structures | Macros | Functions | Variables
test_taskpool.c File Reference

taskpool unit tests More...

#include "asterisk.h"
#include "asterisk/astobj2.h"
#include "asterisk/lock.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/test.h"
#include "asterisk/taskpool.h"
#include "asterisk/cli.h"
Include dependency graph for test_taskpool.c:

Go to the source code of this file.

Data Structures

struct  efficiency_task_data
 
struct  sel_data
 
struct  serializer_efficiency_task_data
 
struct  test_data
 Sorcery object created based on backend data. More...
 

Macros

#define SEL_POOL   4
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
 AST_TEST_DEFINE (taskpool_push)
 
 AST_TEST_DEFINE (taskpool_push_grow)
 
 AST_TEST_DEFINE (taskpool_push_serializer)
 
 AST_TEST_DEFINE (taskpool_push_serializer_synchronous)
 
 AST_TEST_DEFINE (taskpool_push_serializer_synchronous_requeue)
 
 AST_TEST_DEFINE (taskpool_push_shrink)
 
 AST_TEST_DEFINE (taskpool_push_synchronous)
 
 AST_TEST_DEFINE (taskpool_selector_skips_busy_executor)
 
 AST_TEST_DEFINE (taskpool_serializer_multiple_suspension)
 
 AST_TEST_DEFINE (taskpool_serializer_push_wait_while_suspended_from_other_serializer)
 
 AST_TEST_DEFINE (taskpool_serializer_suspension)
 
static int cascade_task (void *data)
 
static int efficiency_task (void *data)
 
static char * handle_cli_taskpool_push_efficiency (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_cli_taskpool_push_serializer_efficiency (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int load_module (void)
 
static int requeue_task (void *data)
 
static int sel_blocking_task (void *data)
 
static int sel_probe_task (void *data)
 
static int sel_run_case (struct ast_test *test, int probe_first, const char *label)
 
static int serializer_efficiency_task (void *data)
 
static int simple_task (void *data)
 
static struct test_datatest_alloc (void)
 
static void test_destroy (struct test_data *td)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "taskpool test module" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_cli_entry cli []
 

Detailed Description

taskpool unit tests

Author
Joshua Colp jcolp.nosp@m.@san.nosp@m.goma..nosp@m.com

Definition in file test_taskpool.c.

Macro Definition Documentation

◆ SEL_POOL

#define SEL_POOL   4

Definition at line 1070 of file test_taskpool.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1317 of file test_taskpool.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1317 of file test_taskpool.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1317 of file test_taskpool.c.

◆ AST_TEST_DEFINE() [1/11]

AST_TEST_DEFINE ( taskpool_push  )

Definition at line 79 of file test_taskpool.c.

80{
81 struct ast_taskpool *pool = NULL;
82 struct test_data *td = NULL;
85 .idle_timeout = 0,
86 .auto_increment = 0,
87 .minimum_size = 1,
88 .initial_size = 1,
89 .max_size = 1,
90 };
92 struct timeval start;
93 struct timespec end;
94
95 switch (cmd) {
96 case TEST_INIT:
97 info->name = "push";
98 info->category = "/main/taskpool/";
99 info->summary = "Taskpool pushing test";
100 info->description =
101 "Pushes a single task into a taskpool asynchronously and ensures it is executed.";
102 return AST_TEST_NOT_RUN;
103 case TEST_EXECUTE:
104 break;
105 }
106 td = test_alloc();
107 if (!td) {
108 return AST_TEST_FAIL;
109 }
110
111 pool = ast_taskpool_create(info->name, &options);
112 if (!pool) {
113 goto end;
114 }
115
116 if (ast_taskpool_push(pool, simple_task, td)) {
117 goto end;
118 }
119
120 /* It should not take more than 5 seconds for a single simple task to execute */
121 start = ast_tvnow();
122 end.tv_sec = start.tv_sec + 5;
123 end.tv_nsec = start.tv_usec * 1000;
124
125 ast_mutex_lock(&td->lock);
126 while (!td->executed && ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
127 }
129
130 if (!td->executed) {
131 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
132 res = AST_TEST_FAIL;
133 }
134
135end:
137 test_destroy(td);
138 return res;
139}
char * end
Definition eagi_proxy.c:73
#define ast_cond_timedwait(cond, mutex, time)
Definition lock.h:213
#define ast_mutex_unlock(a)
Definition lock.h:197
#define ast_mutex_lock(a)
Definition lock.h:196
#define NULL
Definition resample.c:96
An opaque taskpool structure.
Definition taskpool.c:62
Sorcery object created based on backend data.
#define AST_TASKPOOL_OPTIONS_VERSION
Definition taskpool.h:76
void ast_taskpool_shutdown(struct ast_taskpool *pool)
Shut down a taskpool and remove the underlying taskprocessors.
Definition taskpool.c:692
struct ast_taskpool * ast_taskpool_create(const char *name, const struct ast_taskpool_options *options)
Create a new taskpool.
Definition taskpool.c:341
#define ast_taskpool_push(pool, task, data)
Definition taskpool.h:210
@ TEST_INIT
Definition test.h:200
@ TEST_EXECUTE
Definition test.h:201
#define ast_test_status_update(a, b, c...)
Definition test.h:129
ast_test_result_state
Definition test.h:193
@ AST_TEST_PASS
Definition test.h:195
@ AST_TEST_FAIL
Definition test.h:196
@ AST_TEST_NOT_RUN
Definition test.h:194
static struct test_options options
static struct test_data * test_alloc(void)
static void test_destroy(struct test_data *td)
static int simple_task(void *data)
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159

References ast_cond_timedwait, ast_mutex_lock, ast_mutex_unlock, ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_push, ast_taskpool_shutdown(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), test_data::cond, end, test_data::executed, test_data::lock, NULL, options, simple_task(), test_alloc(), test_destroy(), TEST_EXECUTE, and TEST_INIT.

◆ AST_TEST_DEFINE() [2/11]

AST_TEST_DEFINE ( taskpool_push_grow  )

Definition at line 394 of file test_taskpool.c.

395{
396 struct ast_taskpool *pool = NULL;
397 struct test_data *td = NULL;
400 .idle_timeout = 0,
401 .auto_increment = 1,
402 .minimum_size = 0,
403 .initial_size = 0,
404 .max_size = 1,
405 };
407 struct timeval start;
408 struct timespec end;
409
410 switch (cmd) {
411 case TEST_INIT:
412 info->name = "push_grow";
413 info->category = "/main/taskpool/";
414 info->summary = "Taskpool pushing test with auto-grow enabled";
415 info->description =
416 "Pushes a single task into a taskpool asynchronously, ensures it is executed and the pool grows.";
417 return AST_TEST_NOT_RUN;
418 case TEST_EXECUTE:
419 break;
420 }
421 td = test_alloc();
422 if (!td) {
423 return AST_TEST_FAIL;
424 }
425
426 pool = ast_taskpool_create(info->name, &options);
427 if (!pool) {
428 goto end;
429 }
430
431 if (ast_taskpool_taskprocessors_count(pool) != 0) {
432 ast_test_status_update(test, "Expected taskpool to have 0 taskprocessors but it has %zu\n", ast_taskpool_taskprocessors_count(pool));
433 res = AST_TEST_FAIL;
434 goto end;
435 }
436
437 if (ast_taskpool_push(pool, simple_task, td)) {
438 goto end;
439 }
440
441 if (ast_taskpool_taskprocessors_count(pool) != 1) {
442 ast_test_status_update(test, "Expected taskpool to have 1 taskprocessor but it has %zu\n", ast_taskpool_taskprocessors_count(pool));
443 res = AST_TEST_FAIL;
444 goto end;
445 }
446
447 /* It should not take more than 5 seconds for a single simple task to execute */
448 start = ast_tvnow();
449 end.tv_sec = start.tv_sec + 5;
450 end.tv_nsec = start.tv_usec * 1000;
451
452 ast_mutex_lock(&td->lock);
453 while (!td->executed && ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
454 }
456
457 if (!td->executed) {
458 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
459 res = AST_TEST_FAIL;
460 }
461
462end:
464 test_destroy(td);
465 return res;
466}
size_t ast_taskpool_taskprocessors_count(struct ast_taskpool *pool)
Get the current number of taskprocessors in the taskpool.
Definition taskpool.c:468

References ast_cond_timedwait, ast_mutex_lock, ast_mutex_unlock, ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_push, ast_taskpool_shutdown(), ast_taskpool_taskprocessors_count(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), test_data::cond, end, test_data::executed, test_data::lock, NULL, options, simple_task(), test_alloc(), test_destroy(), TEST_EXECUTE, and TEST_INIT.

◆ AST_TEST_DEFINE() [3/11]

AST_TEST_DEFINE ( taskpool_push_serializer  )

Definition at line 191 of file test_taskpool.c.

192{
193 struct ast_taskpool *pool = NULL;
194 struct test_data *td = NULL;
197 .idle_timeout = 0,
198 .auto_increment = 0,
199 .minimum_size = 1,
200 .initial_size = 1,
201 .max_size = 1,
202 };
205 struct timeval start;
206 struct timespec end;
207
208 switch (cmd) {
209 case TEST_INIT:
210 info->name = "push_serializer";
211 info->category = "/main/taskpool/";
212 info->summary = "Taskpool serializer pushing test";
213 info->description =
214 "Pushes a single task into a taskpool serializer and ensures it is executed.";
215 return AST_TEST_NOT_RUN;
216 case TEST_EXECUTE:
217 break;
218 }
219 td = test_alloc();
220 if (!td) {
221 return AST_TEST_FAIL;
222 }
223
224 pool = ast_taskpool_create(info->name, &options);
225 if (!pool) {
226 goto end;
227 }
228
229 serializer = ast_taskpool_serializer("serializer", pool);
230 if (!serializer) {
231 goto end;
232 }
233
235 goto end;
236 }
237
238 /* It should not take more than 5 seconds for a single simple task to execute */
239 start = ast_tvnow();
240 end.tv_sec = start.tv_sec + 5;
241 end.tv_nsec = start.tv_usec * 1000;
242
243 ast_mutex_lock(&td->lock);
244 while (!td->executed && ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
245 }
247
248 if (!td->executed) {
249 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
250 res = AST_TEST_FAIL;
251 }
252
253 if (td->taskprocessor != serializer) {
254 ast_test_status_update(test, "Expected taskprocessor to be same as serializer but it was not\n");
255 res = AST_TEST_FAIL;
256 }
257
258end:
261 test_destroy(td);
262 return res;
263}
A ast_taskprocessor structure is a singleton by name.
struct ast_taskprocessor * taskprocessor
struct ast_taskprocessor * ast_taskpool_serializer(const char *name, struct ast_taskpool *pool)
Serialized execution of tasks within a ast_taskpool.
Definition taskpool.c:877
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
#define ast_taskprocessor_push(tps, task_exe, datap)

References ast_cond_timedwait, ast_mutex_lock, ast_mutex_unlock, ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_serializer(), ast_taskpool_shutdown(), ast_taskprocessor_push, ast_taskprocessor_unreference(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), test_data::cond, end, test_data::executed, test_data::lock, NULL, options, simple_task(), test_data::taskprocessor, test_alloc(), test_destroy(), TEST_EXECUTE, and TEST_INIT.

◆ AST_TEST_DEFINE() [4/11]

AST_TEST_DEFINE ( taskpool_push_serializer_synchronous  )

Definition at line 265 of file test_taskpool.c.

266{
267 struct ast_taskpool *pool = NULL;
268 struct test_data *td = NULL;
271 .idle_timeout = 0,
272 .auto_increment = 0,
273 .minimum_size = 1,
274 .initial_size = 1,
275 .max_size = 1,
276 };
279
280 switch (cmd) {
281 case TEST_INIT:
282 info->name = "push_serializer_synchronous";
283 info->category = "/main/taskpool/";
284 info->summary = "Taskpool serializer synchronous pushing test";
285 info->description =
286 "Pushes a single task into a taskpool serializer synchronously and ensures it is executed.";
287 return AST_TEST_NOT_RUN;
288 case TEST_EXECUTE:
289 break;
290 }
291 td = test_alloc();
292 if (!td) {
293 return AST_TEST_FAIL;
294 }
295
296 pool = ast_taskpool_create(info->name, &options);
297 if (!pool) {
298 goto end;
299 }
300
301 serializer = ast_taskpool_serializer("serializer", pool);
302 if (!serializer) {
303 goto end;
304 }
305
307 goto end;
308 }
309
310 if (!td->executed) {
311 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
312 res = AST_TEST_FAIL;
313 }
314
315 if (td->taskprocessor != serializer) {
316 ast_test_status_update(test, "Expected taskprocessor to be same as serializer but it was not\n");
317 res = AST_TEST_FAIL;
318 }
319
320end:
323 test_destroy(td);
324 return res;
325}
#define ast_taskpool_serializer_push_wait(pool, task, data)
Definition taskpool.h:335

References ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_serializer(), ast_taskpool_serializer_push_wait, ast_taskpool_shutdown(), ast_taskprocessor_unreference(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, end, test_data::executed, NULL, options, simple_task(), test_data::taskprocessor, test_alloc(), test_destroy(), TEST_EXECUTE, and TEST_INIT.

◆ AST_TEST_DEFINE() [5/11]

AST_TEST_DEFINE ( taskpool_push_serializer_synchronous_requeue  )

Definition at line 332 of file test_taskpool.c.

333{
334 struct ast_taskpool *pool = NULL;
335 struct test_data *td = NULL;
338 .idle_timeout = 0,
339 .auto_increment = 0,
340 .minimum_size = 1,
341 .initial_size = 1,
342 .max_size = 1,
343 };
346
347 switch (cmd) {
348 case TEST_INIT:
349 info->name = "push_serializer_synchronous_requeue";
350 info->category = "/main/taskpool/";
351 info->summary = "Taskpool serializer synchronous requeueing test";
352 info->description =
353 "Pushes a single task into a taskpool serializer synchronously and ensures it is requeued and executed.";
354 return AST_TEST_NOT_RUN;
355 case TEST_EXECUTE:
356 break;
357 }
358 td = test_alloc();
359 if (!td) {
360 return AST_TEST_FAIL;
361 }
362
363 pool = ast_taskpool_create(info->name, &options);
364 if (!pool) {
365 goto end;
366 }
367
368 serializer = ast_taskpool_serializer("serializer", pool);
369 if (!serializer) {
370 goto end;
371 }
372
374 goto end;
375 }
376
377 if (!td->executed) {
378 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
379 res = AST_TEST_FAIL;
380 }
381
382 if (td->taskprocessor != serializer) {
383 ast_test_status_update(test, "Expected taskprocessor to be same as serializer but it was not\n");
384 res = AST_TEST_FAIL;
385 }
386
387end:
390 test_destroy(td);
391 return res;
392}
static int requeue_task(void *data)

References ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_serializer(), ast_taskpool_serializer_push_wait, ast_taskpool_shutdown(), ast_taskprocessor_unreference(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, end, test_data::executed, NULL, options, requeue_task(), test_data::taskprocessor, test_alloc(), test_destroy(), TEST_EXECUTE, and TEST_INIT.

◆ AST_TEST_DEFINE() [6/11]

AST_TEST_DEFINE ( taskpool_push_shrink  )

Definition at line 468 of file test_taskpool.c.

469{
470 struct ast_taskpool *pool = NULL;
471 struct test_data *td = NULL;
474 .idle_timeout = 1,
475 .auto_increment = 1,
476 .minimum_size = 0,
477 .initial_size = 0,
478 .max_size = 1,
479 };
481 struct timeval start;
482 struct timespec end;
483 int iterations = 0;
484
485 switch (cmd) {
486 case TEST_INIT:
487 info->name = "push_shrink";
488 info->category = "/main/taskpool/";
489 info->summary = "Taskpool pushing test with auto-shrink enabled";
490 info->description =
491 "Pushes a single task into a taskpool asynchronously, ensures it is executed and the pool shrinks.";
492 return AST_TEST_NOT_RUN;
493 case TEST_EXECUTE:
494 break;
495 }
496 td = test_alloc();
497 if (!td) {
498 return AST_TEST_FAIL;
499 }
500
501 pool = ast_taskpool_create(info->name, &options);
502 if (!pool) {
503 goto end;
504 }
505
506 if (ast_taskpool_taskprocessors_count(pool) != 0) {
507 ast_test_status_update(test, "Expected taskpool to have 0 taskprocessors but it has %zu\n", ast_taskpool_taskprocessors_count(pool));
508 res = AST_TEST_FAIL;
509 goto end;
510 }
511
512 if (ast_taskpool_push(pool, simple_task, td)) {
513 res = AST_TEST_FAIL;
514 goto end;
515 }
516
517 if (ast_taskpool_taskprocessors_count(pool) != 1) {
518 ast_test_status_update(test, "Expected taskpool to have 1 taskprocessor but it has %zu\n", ast_taskpool_taskprocessors_count(pool));
519 res = AST_TEST_FAIL;
520 goto end;
521 }
522
523 /* We give 10 seconds for the pool to shrink back to normal, but if it happens earlier we
524 * stop our check early.
525 */
526 ast_mutex_lock(&td->lock);
527 do {
528 start = ast_tvnow();
529 end.tv_sec = start.tv_sec + 1;
530 end.tv_nsec = start.tv_usec * 1000;
531
532 if (ast_cond_timedwait(&td->cond, &td->lock, &end) == ETIMEDOUT) {
533 iterations++;
534 }
535 } while (ast_taskpool_taskprocessors_count(pool) != 0 && iterations != 10);
536
537 if (!td->executed) {
538 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
539 res = AST_TEST_FAIL;
540 }
541
542 if (ast_taskpool_taskprocessors_count(pool) != 0) {
543 ast_test_status_update(test, "Expected taskpool to have 0 taskprocessors but it has %zu\n", ast_taskpool_taskprocessors_count(pool));
544 res = AST_TEST_FAIL;
545 goto end;
546 }
547
548end:
550 test_destroy(td);
551 return res;
552}

References ast_cond_timedwait, ast_mutex_lock, ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_push, ast_taskpool_shutdown(), ast_taskpool_taskprocessors_count(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), test_data::cond, end, test_data::executed, test_data::lock, NULL, options, simple_task(), test_alloc(), test_destroy(), TEST_EXECUTE, and TEST_INIT.

◆ AST_TEST_DEFINE() [7/11]

AST_TEST_DEFINE ( taskpool_push_synchronous  )

Definition at line 141 of file test_taskpool.c.

142{
143 struct ast_taskpool *pool = NULL;
144 struct test_data *td = NULL;
147 .idle_timeout = 0,
148 .auto_increment = 0,
149 .minimum_size = 1,
150 .initial_size = 1,
151 .max_size = 1,
152 };
154
155 switch (cmd) {
156 case TEST_INIT:
157 info->name = "push_synchronous";
158 info->category = "/main/taskpool/";
159 info->summary = "Taskpool synchronous pushing test";
160 info->description =
161 "Pushes a single task into a taskpool synchronously and ensures it is executed.";
162 return AST_TEST_NOT_RUN;
163 case TEST_EXECUTE:
164 break;
165 }
166 td = test_alloc();
167 if (!td) {
168 return AST_TEST_FAIL;
169 }
170
171 pool = ast_taskpool_create(info->name, &options);
172 if (!pool) {
173 goto end;
174 }
175
176 if (ast_taskpool_push_wait(pool, simple_task, td)) {
177 goto end;
178 }
179
180 if (!td->executed) {
181 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
182 res = AST_TEST_FAIL;
183 }
184
185end:
187 test_destroy(td);
188 return res;
189}
#define ast_taskpool_push_wait(pool, task, data)
Definition taskpool.h:230

References ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_push_wait, ast_taskpool_shutdown(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, end, test_data::executed, NULL, options, simple_task(), test_alloc(), test_destroy(), TEST_EXECUTE, and TEST_INIT.

◆ AST_TEST_DEFINE() [8/11]

AST_TEST_DEFINE ( taskpool_selector_skips_busy_executor  )

Definition at line 1242 of file test_taskpool.c.

1243{
1244 int ran_after;
1245 int ran_before;
1246
1247 switch (cmd) {
1248 case TEST_INIT:
1249 info->name = "selector_skips_busy_executor";
1250 info->category = "/main/taskpool/";
1251 info->summary = "A task should not be assigned to an executor that is busy";
1252 info->description =
1253 "Occupies one executor of a four-executor pool with a task that "
1254 "blocks until released, then pushes a trivial task on a different "
1255 "serializer while three executors are free. Runs the scenario "
1256 "twice: once with the second serializer created after the blocking "
1257 "task is already running, and once with it created beforehand, so "
1258 "the result cannot be attributed to both serializers having been "
1259 "created while the pool was idle.";
1260 return AST_TEST_NOT_RUN;
1261 case TEST_EXECUTE:
1262 break;
1263 }
1264
1265 ran_after = sel_run_case(test, 0, "serializer created while an executor is busy");
1266 ran_before = sel_run_case(test, 1, "serializer created while the pool is idle");
1267
1268 if (!ran_after || !ran_before) {
1270 "a trivial task was queued behind the blocked executor while %d "
1271 "executors were free\n", SEL_POOL - 1);
1272 return AST_TEST_FAIL;
1273 }
1274
1275 return AST_TEST_PASS;
1276}
static int sel_run_case(struct ast_test *test, int probe_first, const char *label)
#define SEL_POOL

References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, SEL_POOL, sel_run_case(), TEST_EXECUTE, and TEST_INIT.

◆ AST_TEST_DEFINE() [9/11]

AST_TEST_DEFINE ( taskpool_serializer_multiple_suspension  )

Definition at line 642 of file test_taskpool.c.

643{
644 struct ast_taskpool *pool = NULL;
645 struct test_data *td = NULL;
649 .idle_timeout = 0,
650 .auto_increment = 0,
651 .minimum_size = 1,
652 .initial_size = 1,
653 .max_size = 1,
654 };
656 struct timeval start;
657 struct timespec end;
658
659 switch (cmd) {
660 case TEST_INIT:
661 info->name = "serializer_multiple_suspension";
662 info->category = "/main/taskpool/";
663 info->summary = "Taskpool serializer multiple suspension test";
664 info->description =
665 "Pushes a single task into a taskpool serializer asynchronously while suspended multiple times, and ensures it only executes after unsuspension.";
666 return AST_TEST_NOT_RUN;
667 case TEST_EXECUTE:
668 break;
669 }
670 td = test_alloc();
671 if (!td) {
672 return AST_TEST_FAIL;
673 }
674
675 pool = ast_taskpool_create(info->name, &options);
676 if (!pool) {
677 goto end;
678 }
679
680 serializer = ast_taskpool_serializer("serializer", pool);
681 if (!serializer) {
682 goto end;
683 }
684
687
689 goto end;
690 }
691
692 /* Give 5 seconds to ensure the task isn't executed */
693 start = ast_tvnow();
694 end.tv_sec = start.tv_sec + 5;
695 end.tv_nsec = start.tv_usec * 1000;
696
697 ast_mutex_lock(&td->lock);
698 while (!td->executed && ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
699 }
701
702 if (td->executed) {
703 ast_test_status_update(test, "Expected simple task to not be executed but it was\n");
704 res = AST_TEST_FAIL;
705 }
706
709
710 /* Give 5 seconds to ensure the task is executed */
711 start = ast_tvnow();
712 end.tv_sec = start.tv_sec + 5;
713 end.tv_nsec = start.tv_usec * 1000;
714
715 ast_mutex_lock(&td->lock);
716 while (!td->executed && ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
717 }
719
720 if (!td->executed) {
721 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
722 res = AST_TEST_FAIL;
723 }
724
725end:
728 test_destroy(td);
729 return res;
730}
int ast_taskpool_serializer_unsuspend(struct ast_taskprocessor *serializer)
Unsuspend a serializer, causing tasks to be executed.
Definition taskpool.c:1067
int ast_taskpool_serializer_suspend(struct ast_taskprocessor *serializer)
Suspend a serializer, causing tasks to be queued until unsuspended.
Definition taskpool.c:1018

References ast_cond_timedwait, ast_mutex_lock, ast_mutex_unlock, ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_serializer(), ast_taskpool_serializer_suspend(), ast_taskpool_serializer_unsuspend(), ast_taskpool_shutdown(), ast_taskprocessor_push, ast_taskprocessor_unreference(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), test_data::cond, end, test_data::executed, test_data::lock, NULL, options, simple_task(), test_alloc(), test_destroy(), TEST_EXECUTE, and TEST_INIT.

◆ AST_TEST_DEFINE() [10/11]

AST_TEST_DEFINE ( taskpool_serializer_push_wait_while_suspended_from_other_serializer  )

Definition at line 743 of file test_taskpool.c.

744{
745 struct ast_taskpool *pool = NULL;
746 struct test_data *td = NULL;
747 struct ast_taskprocessor *suspended_serializer = NULL;
748 struct ast_taskprocessor *push_serializer = NULL;
751 .idle_timeout = 0,
752 .auto_increment = 0,
753 .minimum_size = 1,
754 .initial_size = 1,
755 .max_size = 1,
756 };
758 struct timeval start;
759 struct timespec end;
760
761 switch (cmd) {
762 case TEST_INIT:
763 info->name = "serializer_push_wait_while_suspended_from_other_serializer";
764 info->category = "/main/taskpool/";
765 info->summary = "Taskpool serializer push wait while suspended from other serializer test";
766 info->description =
767 "Pushes a single task into a taskpool serializer synchronously from another serializer while suspended, and ensures it only executes after unsuspension.";
768 return AST_TEST_NOT_RUN;
769 case TEST_EXECUTE:
770 break;
771 }
772 td = test_alloc();
773 if (!td) {
774 return AST_TEST_FAIL;
775 }
776
777 pool = ast_taskpool_create(info->name, &options);
778 if (!pool) {
779 goto end;
780 }
781
782 suspended_serializer = ast_taskpool_serializer("suspended_serializer", pool);
783 if (!suspended_serializer) {
784 goto end;
785 }
786
787 td->test_specific_data = suspended_serializer;
788
789 push_serializer = ast_taskpool_serializer("push_serializer", pool);
790 if (!push_serializer) {
791 goto end;
792 }
793
794 ast_taskpool_serializer_suspend(suspended_serializer);
795
796 /* We push a task to the unsuspended serializer which will push a task to the suspended serializer
797 * in a synchronous fashion. That task can not execute until the suspended serializer becomes
798 * unsuspended.
799 */
800 if (ast_taskprocessor_push(push_serializer, cascade_task, td)) {
801 goto end;
802 }
803
804 /* Give 5 seconds to ensure the task isn't executed */
805 start = ast_tvnow();
806 end.tv_sec = start.tv_sec + 5;
807 end.tv_nsec = start.tv_usec * 1000;
808
809 ast_mutex_lock(&td->lock);
810 while (!td->executed && ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
811 }
813
814 if (td->executed) {
815 ast_test_status_update(test, "Expected simple task to not be executed but it was\n");
816 res = AST_TEST_FAIL;
817 }
818
819 ast_taskpool_serializer_unsuspend(suspended_serializer);
820
821 /* Give 5 seconds to ensure the task is executed */
822 start = ast_tvnow();
823 end.tv_sec = start.tv_sec + 5;
824 end.tv_nsec = start.tv_usec * 1000;
825
826 ast_mutex_lock(&td->lock);
827 while (!td->executed && ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
828 }
830
831 if (!td->executed) {
832 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
833 res = AST_TEST_FAIL;
834 }
835
836end:
837 ast_taskprocessor_unreference(suspended_serializer);
838 ast_taskprocessor_unreference(push_serializer);
840 test_destroy(td);
841 return res;
842}
void * test_specific_data
static int cascade_task(void *data)

References ast_cond_timedwait, ast_mutex_lock, ast_mutex_unlock, ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_serializer(), ast_taskpool_serializer_suspend(), ast_taskpool_serializer_unsuspend(), ast_taskpool_shutdown(), ast_taskprocessor_push, ast_taskprocessor_unreference(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), cascade_task(), test_data::cond, end, test_data::executed, test_data::lock, NULL, options, test_alloc(), test_destroy(), TEST_EXECUTE, TEST_INIT, and test_data::test_specific_data.

◆ AST_TEST_DEFINE() [11/11]

AST_TEST_DEFINE ( taskpool_serializer_suspension  )

Definition at line 554 of file test_taskpool.c.

555{
556 struct ast_taskpool *pool = NULL;
557 struct test_data *td = NULL;
561 .idle_timeout = 0,
562 .auto_increment = 0,
563 .minimum_size = 1,
564 .initial_size = 1,
565 .max_size = 1,
566 };
568 struct timeval start;
569 struct timespec end;
570
571 switch (cmd) {
572 case TEST_INIT:
573 info->name = "serializer_suspension";
574 info->category = "/main/taskpool/";
575 info->summary = "Taskpool serializer suspension test";
576 info->description =
577 "Pushes a single task into a taskpool serializer asynchronously while suspended, and ensures it only executes after unsuspension.";
578 return AST_TEST_NOT_RUN;
579 case TEST_EXECUTE:
580 break;
581 }
582 td = test_alloc();
583 if (!td) {
584 return AST_TEST_FAIL;
585 }
586
587 pool = ast_taskpool_create(info->name, &options);
588 if (!pool) {
589 goto end;
590 }
591
592 serializer = ast_taskpool_serializer("serializer", pool);
593 if (!serializer) {
594 goto end;
595 }
596
598
600 goto end;
601 }
602
603 /* Give 5 seconds to ensure the task isn't executed */
604 start = ast_tvnow();
605 end.tv_sec = start.tv_sec + 5;
606 end.tv_nsec = start.tv_usec * 1000;
607
608 ast_mutex_lock(&td->lock);
609 while (!td->executed && ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
610 }
612
613 if (td->executed) {
614 ast_test_status_update(test, "Expected simple task to not be executed but it was\n");
615 res = AST_TEST_FAIL;
616 }
617
619
620 /* Give 5 seconds to ensure the task is executed */
621 start = ast_tvnow();
622 end.tv_sec = start.tv_sec + 5;
623 end.tv_nsec = start.tv_usec * 1000;
624
625 ast_mutex_lock(&td->lock);
626 while (!td->executed && ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
627 }
629
630 if (!td->executed) {
631 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
632 res = AST_TEST_FAIL;
633 }
634
635end:
638 test_destroy(td);
639 return res;
640}

References ast_cond_timedwait, ast_mutex_lock, ast_mutex_unlock, ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_serializer(), ast_taskpool_serializer_suspend(), ast_taskpool_serializer_unsuspend(), ast_taskpool_shutdown(), ast_taskprocessor_push, ast_taskprocessor_unreference(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), test_data::cond, end, test_data::executed, test_data::lock, NULL, options, simple_task(), test_alloc(), test_destroy(), TEST_EXECUTE, and TEST_INIT.

◆ cascade_task()

static int cascade_task ( void *  data)
static

Definition at line 732 of file test_taskpool.c.

733{
734 struct test_data *td = data;
735
737 return -1;
738 }
739
740 return 0;
741}

References ast_taskpool_serializer_push_wait, simple_task(), and test_data::test_specific_data.

Referenced by AST_TEST_DEFINE().

◆ efficiency_task()

static int efficiency_task ( void *  data)
static

Definition at line 850 of file test_taskpool.c.

851{
852 struct efficiency_task_data *etd = data;
853
854 if (etd->shutdown) {
855 ao2_ref(etd->pool, -1);
856 return 0;
857 }
858
860
861 if (ast_taskpool_push(etd->pool, efficiency_task, etd)) {
862 ao2_ref(etd->pool, -1);
863 return -1;
864 }
865
866 return 0;
867}
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition lock.h:764
struct ast_taskpool * pool
static int efficiency_task(void *data)

References ao2_ref, ast_atomic_fetchadd_int(), ast_taskpool_push, efficiency_task(), efficiency_task_data::num_tasks_executed, efficiency_task_data::pool, and efficiency_task_data::shutdown.

Referenced by efficiency_task(), and handle_cli_taskpool_push_efficiency().

◆ handle_cli_taskpool_push_efficiency()

static char * handle_cli_taskpool_push_efficiency ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 869 of file test_taskpool.c.

870{
871 struct ast_taskpool *pool = NULL;
872 struct test_data *td = NULL;
875 .idle_timeout = 0,
876 .auto_increment = 0,
877 .minimum_size = 5,
878 .initial_size = 5,
879 .max_size = 5,
880 };
881 struct efficiency_task_data etd = {
882 .pool = NULL,
883 .num_tasks_executed = 0,
884 .shutdown = 0,
885 };
886 struct timeval start;
887 struct timespec end;
888 int i;
889
890 switch (cmd) {
891 case CLI_INIT:
892 e->command = "taskpool push efficiency";
893 e->usage =
894 "Usage: taskpool push efficiency\n"
895 " Pushes 200 tasks to a taskpool and measures\n"
896 " the number of tasks executed within 30 seconds.\n";
897 return NULL;
898 case CLI_GENERATE:
899 return NULL;
900 }
901
902 td = test_alloc();
903 if (!td) {
904 return CLI_SUCCESS;
905 }
906
907 pool = ast_taskpool_create("taskpool_push_efficiency", &options);
908 if (!pool) {
909 goto end;
910 }
911
912 etd.pool = pool;
913
914 /* Push in 200 tasks, cause why not */
915 for (i = 0; i < 200; i++) {
916 /* Ensure that the task has a reference to the pool */
917 ao2_bump(pool);
918 if (ast_taskpool_push(pool, efficiency_task, &etd)) {
919 goto end;
920 }
921 }
922
923 /* Wait for 30 seconds */
924 start = ast_tvnow();
925 end.tv_sec = start.tv_sec + 30;
926 end.tv_nsec = start.tv_usec * 1000;
927
928 ast_mutex_lock(&td->lock);
929 while (ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
930 }
932
933 /* Give the total tasks executed, and tell each task to not requeue */
934 ast_cli(a->fd, "Total tasks executed in 30 seconds: %d (%d per second)\n", etd.num_tasks_executed, etd.num_tasks_executed / 30);
935
936end:
937 etd.shutdown = 1;
939 test_destroy(td);
940 return CLI_SUCCESS;
941}
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
#define CLI_SUCCESS
Definition cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
static struct test_val a

References a, ao2_bump, ast_cli(), ast_cond_timedwait, ast_mutex_lock, ast_mutex_unlock, ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_push, ast_taskpool_shutdown(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, test_data::cond, efficiency_task(), end, test_data::lock, NULL, efficiency_task_data::num_tasks_executed, options, efficiency_task_data::pool, efficiency_task_data::shutdown, test_alloc(), test_destroy(), and ast_cli_entry::usage.

◆ handle_cli_taskpool_push_serializer_efficiency()

static char * handle_cli_taskpool_push_serializer_efficiency ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 976 of file test_taskpool.c.

977{
978 struct ast_taskpool *pool = NULL;
979 struct test_data *td = NULL;
982 .idle_timeout = 0,
983 .auto_increment = 0,
984 .minimum_size = 5,
985 .initial_size = 5,
986 .max_size = 5,
987 };
988 struct serializer_efficiency_task_data etd[200];
989 struct timeval start;
990 struct timespec end;
991 int i;
992 int num_tasks_executed = 0;
993 int shutdown = 0;
994
995 switch (cmd) {
996 case CLI_INIT:
997 e->command = "taskpool push serializer efficiency";
998 e->usage =
999 "Usage: taskpool push serializer efficiency\n"
1000 " Pushes 200 tasks to a taskpool in serializers and measures\n"
1001 " the number of tasks executed within 30 seconds.\n";
1002 return NULL;
1003 case CLI_GENERATE:
1004 return NULL;
1005 }
1006 td = test_alloc();
1007 if (!td) {
1008 return CLI_SUCCESS;
1009 }
1010
1011 memset(&etd, 0, sizeof(etd));
1012
1013 pool = ast_taskpool_create("taskpool_push_serializer_efficiency", &options);
1014 if (!pool) {
1015 goto end;
1016 }
1017
1018 /* We create 400 (200 pairs) of serializers */
1019 for (i = 0; i < 200; i++) {
1020 char serializer_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1021
1022 ast_taskprocessor_build_name(serializer_name, sizeof(serializer_name), "serializer%d", i);
1023 etd[i].serializer[0] = ast_taskpool_serializer(serializer_name, pool);
1024 if (!etd[i].serializer[0]) {
1025 goto end;
1026 }
1027
1028 ast_taskprocessor_build_name(serializer_name, sizeof(serializer_name), "serializer%d", i);
1029 etd[i].serializer[1] = ast_taskpool_serializer(serializer_name, pool);
1030 if (!etd[i].serializer[1]) {
1031 goto end;
1032 }
1033
1034 etd[i].num_tasks_executed = &num_tasks_executed;
1035 etd[i].shutdown = &shutdown;
1036 }
1037
1038 /* And once created we push in 200 tasks */
1039 for (i = 0; i < 200; i++) {
1041 goto end;
1042 }
1043 }
1044
1045 /* Wait for 30 seconds */
1046 start = ast_tvnow();
1047 end.tv_sec = start.tv_sec + 30;
1048 end.tv_nsec = start.tv_usec * 1000;
1049
1050 ast_mutex_lock(&td->lock);
1051 while (ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
1052 }
1053 ast_mutex_unlock(&td->lock);
1054
1055 /* Give the total tasks executed, and tell each task to not requeue */
1056 ast_cli(a->fd, "Total tasks executed in 30 seconds: %d (%d per second)\n", num_tasks_executed, num_tasks_executed / 30);
1057 shutdown = 1;
1058
1059end:
1060 /* We need to unreference each serializer */
1061 for (i = 0; i < 200; i++) {
1064 }
1066 test_destroy(td);
1067 return CLI_SUCCESS;
1068}
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
static int serializer_efficiency_task(void *data)

References a, ast_cli(), ast_cond_timedwait, ast_mutex_lock, ast_mutex_unlock, ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_serializer(), ast_taskpool_shutdown(), ast_taskprocessor_build_name(), AST_TASKPROCESSOR_MAX_NAME, ast_taskprocessor_push, ast_taskprocessor_unreference(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, test_data::cond, end, test_data::lock, NULL, serializer_efficiency_task_data::num_tasks_executed, options, serializer_efficiency_task_data::serializer, serializer_efficiency_task(), serializer_efficiency_task_data::shutdown, test_alloc(), test_destroy(), and ast_cli_entry::usage.

◆ load_module()

static int load_module ( void  )
static

Definition at line 1300 of file test_taskpool.c.

1301{
1303 AST_TEST_REGISTER(taskpool_push);
1304 AST_TEST_REGISTER(taskpool_push_synchronous);
1305 AST_TEST_REGISTER(taskpool_push_serializer);
1306 AST_TEST_REGISTER(taskpool_push_serializer_synchronous);
1307 AST_TEST_REGISTER(taskpool_push_serializer_synchronous_requeue);
1308 AST_TEST_REGISTER(taskpool_push_grow);
1309 AST_TEST_REGISTER(taskpool_push_shrink);
1310 AST_TEST_REGISTER(taskpool_serializer_suspension);
1311 AST_TEST_REGISTER(taskpool_serializer_multiple_suspension);
1312 AST_TEST_REGISTER(taskpool_serializer_push_wait_while_suspended_from_other_serializer);
1313 AST_TEST_REGISTER(taskpool_selector_skips_busy_executor);
1315}
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
#define AST_TEST_REGISTER(cb)
Definition test.h:127
static struct ast_cli_entry cli[]
#define ARRAY_LEN(a)
Definition utils.h:706

References ARRAY_LEN, ast_cli_register_multiple, AST_MODULE_LOAD_SUCCESS, AST_TEST_REGISTER, and cli.

◆ requeue_task()

static int requeue_task ( void *  data)
static

Definition at line 327 of file test_taskpool.c.

328{
330}
struct ast_taskprocessor * ast_taskpool_serializer_get_current(void)
Get the taskpool serializer currently associated with this thread.
Definition taskpool.c:842

References ast_taskpool_serializer_get_current(), ast_taskpool_serializer_push_wait, and simple_task().

Referenced by AST_TEST_DEFINE().

◆ sel_blocking_task()

static int sel_blocking_task ( void *  data)
static

Definition at line 1081 of file test_taskpool.c.

1082{
1083 struct sel_data *sd = data;
1084
1085 ast_mutex_lock(&sd->lock);
1086 sd->blocker_running = 1;
1088 while (!sd->blocker_release) {
1089 ast_cond_wait(&sd->cond, &sd->lock);
1090 }
1091 sd->blocker_done = 1;
1093 ast_mutex_unlock(&sd->lock);
1094 return 0;
1095}
#define ast_cond_wait(cond, mutex)
Definition lock.h:212
#define ast_cond_broadcast(cond)
Definition lock.h:211
int blocker_running
ast_cond_t cond
int blocker_release
ast_mutex_t lock

References ast_cond_broadcast, ast_cond_wait, ast_mutex_lock, ast_mutex_unlock, sel_data::blocker_done, sel_data::blocker_release, sel_data::blocker_running, sel_data::cond, and sel_data::lock.

Referenced by sel_run_case().

◆ sel_probe_task()

static int sel_probe_task ( void *  data)
static

Definition at line 1097 of file test_taskpool.c.

1098{
1099 struct sel_data *sd = data;
1100
1101 ast_mutex_lock(&sd->lock);
1102 sd->probe_ran = 1;
1104 ast_mutex_unlock(&sd->lock);
1105 return 0;
1106}

References ast_cond_broadcast, ast_mutex_lock, ast_mutex_unlock, sel_data::cond, sel_data::lock, and sel_data::probe_ran.

Referenced by sel_run_case().

◆ sel_run_case()

static int sel_run_case ( struct ast_test *  test,
int  probe_first,
const char *  label 
)
static

Definition at line 1118 of file test_taskpool.c.

1119{
1120 struct ast_taskpool *pool = NULL;
1121 struct sel_data *sd = NULL;
1122 struct ast_taskpool_options options = {
1124 .idle_timeout = 0,
1125 .auto_increment = 0,
1126 .minimum_size = SEL_POOL,
1127 .initial_size = SEL_POOL,
1128 .max_size = SEL_POOL,
1129 };
1130 struct ast_taskprocessor *blocker_ser = NULL;
1131 struct ast_taskprocessor *probe_ser = NULL;
1132 int ran = 0;
1133 int running;
1134 struct timeval start;
1135 struct timespec end;
1136
1137 sd = ast_calloc(1, sizeof(*sd));
1138 if (!sd) {
1139 return 0;
1140 }
1141 ast_mutex_init(&sd->lock);
1142 ast_cond_init(&sd->cond, NULL);
1143
1144 pool = ast_taskpool_create(label, &options);
1145 if (!pool) {
1146 ast_test_status_update(test, "%s: could not create pool\n", label);
1147 goto cleanup;
1148 }
1149
1150 blocker_ser = ast_taskpool_serializer("blocker", pool);
1151 if (!blocker_ser) {
1152 goto cleanup;
1153 }
1154
1155 if (probe_first) {
1156 probe_ser = ast_taskpool_serializer("probe", pool);
1157 if (!probe_ser) {
1158 goto cleanup;
1159 }
1160 }
1161
1162 if (ast_taskprocessor_push(blocker_ser, sel_blocking_task, sd)) {
1163 goto cleanup;
1164 }
1165
1166 /* Wait until the blocker is definitely inside its task. */
1167 start = ast_tvnow();
1168 end.tv_sec = start.tv_sec + 5;
1169 end.tv_nsec = start.tv_usec * 1000;
1170
1171 ast_mutex_lock(&sd->lock);
1172 while (!sd->blocker_running
1173 && ast_cond_timedwait(&sd->cond, &sd->lock, &end) != ETIMEDOUT) {
1174 }
1175 running = sd->blocker_running;
1176 ast_mutex_unlock(&sd->lock);
1177
1178 if (!running) {
1179 ast_test_status_update(test, "%s: blocking task never started\n", label);
1180 goto release;
1181 }
1182
1183 /*
1184 * With probe_first == 0 the probe serializer is created here, while one
1185 * executor is already busy and three are free.
1186 */
1187 if (!probe_first) {
1188 probe_ser = ast_taskpool_serializer("probe", pool);
1189 if (!probe_ser) {
1190 goto release;
1191 }
1192 }
1193
1194 if (ast_taskprocessor_push(probe_ser, sel_probe_task, sd)) {
1195 goto release;
1196 }
1197
1198 start = ast_tvnow();
1199 end.tv_sec = start.tv_sec + 3;
1200 end.tv_nsec = start.tv_usec * 1000;
1201
1202 ast_mutex_lock(&sd->lock);
1203 while (!sd->probe_ran
1204 && ast_cond_timedwait(&sd->cond, &sd->lock, &end) != ETIMEDOUT) {
1205 }
1206 ran = sd->probe_ran;
1207 ast_mutex_unlock(&sd->lock);
1208
1210 "%s: one executor busy, %d of %d free -> probe %s\n",
1211 label, SEL_POOL - 1, SEL_POOL,
1212 ran ? "ran on a free executor" : "did NOT run within 3s");
1213
1214release:
1215 /* Wait for the blocking task to leave so the pool is idle before shutdown */
1216 start = ast_tvnow();
1217 end.tv_sec = start.tv_sec + 3;
1218 end.tv_nsec = start.tv_usec * 1000;
1219
1220 ast_mutex_lock(&sd->lock);
1221 sd->blocker_release = 1;
1223 while (!sd->blocker_done
1224 && ast_cond_timedwait(&sd->cond, &sd->lock, &end) != ETIMEDOUT) {
1225 }
1226 ast_mutex_unlock(&sd->lock);
1227
1228cleanup:
1229 ast_taskprocessor_unreference(blocker_ser);
1231 if (pool) {
1233 }
1234 if (sd) {
1235 ast_mutex_destroy(&sd->lock);
1236 ast_cond_destroy(&sd->cond);
1237 ast_free(sd);
1238 }
1239 return ran;
1240}
#define ast_free(a)
Definition astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_cond_destroy(cond)
Definition lock.h:209
#define ast_cond_init(cond, attr)
Definition lock.h:208
#define ast_mutex_init(pmutex)
Definition lock.h:193
#define ast_mutex_destroy(a)
Definition lock.h:195
static void cleanup(void)
Clean up any old apps that we don't need any more.
Definition res_stasis.c:327
static int sel_probe_task(void *data)
static int sel_blocking_task(void *data)

References ast_calloc, ast_cond_broadcast, ast_cond_destroy, ast_cond_init, ast_cond_timedwait, ast_free, ast_mutex_destroy, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_serializer(), ast_taskpool_shutdown(), ast_taskprocessor_push, ast_taskprocessor_unreference(), ast_test_status_update, ast_tvnow(), sel_data::blocker_done, sel_data::blocker_release, sel_data::blocker_running, cleanup(), sel_data::cond, end, sel_data::lock, NULL, options, sel_data::probe_ran, sel_blocking_task(), SEL_POOL, and sel_probe_task().

Referenced by AST_TEST_DEFINE().

◆ serializer_efficiency_task()

static int serializer_efficiency_task ( void *  data)
static

Definition at line 949 of file test_taskpool.c.

950{
951 struct serializer_efficiency_task_data *etd = data;
952 struct ast_taskprocessor *taskprocessor = etd->serializer[0];
953
954 if (*etd->shutdown) {
955 return 0;
956 }
957
959
960 /* We ping pong a task between a pair of taskprocessors to ensure that
961 * a single taskprocessor does not receive a thread from the threadpool
962 * exclusively.
963 */
964 if (taskprocessor == ast_taskpool_serializer_get_current()) {
965 taskprocessor = etd->serializer[1];
966 }
967
968 if (ast_taskprocessor_push(taskprocessor,
970 return -1;
971 }
972
973 return 0;
974}
struct ast_taskprocessor * serializer[2]

References ast_atomic_fetchadd_int(), ast_taskpool_serializer_get_current(), ast_taskprocessor_push, serializer_efficiency_task_data::num_tasks_executed, serializer_efficiency_task_data::serializer, serializer_efficiency_task(), and serializer_efficiency_task_data::shutdown.

Referenced by handle_cli_taskpool_push_serializer_efficiency(), and serializer_efficiency_task().

◆ simple_task()

static int simple_task ( void *  data)
static

Definition at line 69 of file test_taskpool.c.

70{
71 struct test_data *td = data;
72 SCOPED_MUTEX(lock, &td->lock);
74 td->executed = 1;
76 return 0;
77}
ast_mutex_t lock
Definition app_sla.c:337
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition lock.h:596
#define ast_cond_signal(cond)
Definition lock.h:210

References ast_cond_signal, ast_taskpool_serializer_get_current(), test_data::cond, test_data::executed, lock, test_data::lock, SCOPED_MUTEX, and test_data::taskprocessor.

Referenced by AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), cascade_task(), and requeue_task().

◆ test_alloc()

static struct test_data * test_alloc ( void  )
static

◆ test_destroy()

static void test_destroy ( struct test_data td)
static

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1283 of file test_taskpool.c.

1284{
1286 AST_TEST_UNREGISTER(taskpool_push);
1287 AST_TEST_UNREGISTER(taskpool_push_synchronous);
1288 AST_TEST_UNREGISTER(taskpool_push_serializer);
1289 AST_TEST_UNREGISTER(taskpool_push_serializer_synchronous);
1290 AST_TEST_UNREGISTER(taskpool_push_serializer_synchronous_requeue);
1291 AST_TEST_UNREGISTER(taskpool_push_grow);
1292 AST_TEST_UNREGISTER(taskpool_push_shrink);
1293 AST_TEST_UNREGISTER(taskpool_serializer_suspension);
1294 AST_TEST_UNREGISTER(taskpool_serializer_multiple_suspension);
1295 AST_TEST_UNREGISTER(taskpool_serializer_push_wait_while_suspended_from_other_serializer);
1296 AST_TEST_UNREGISTER(taskpool_selector_skips_busy_executor);
1297 return 0;
1298}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
#define AST_TEST_UNREGISTER(cb)
Definition test.h:128

References ARRAY_LEN, ast_cli_unregister_multiple(), AST_TEST_UNREGISTER, and cli.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "taskpool test module" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 1317 of file test_taskpool.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1317 of file test_taskpool.c.

◆ cli

struct ast_cli_entry cli[]
static
Initial value:
= {
{ .handler = handle_cli_taskpool_push_efficiency , .summary = "Push tasks to a taskpool and measure efficiency" ,},
{ .handler = handle_cli_taskpool_push_serializer_efficiency , .summary = "Push tasks to a taskpool in serializers and measure efficiency" ,},
}
static char * handle_cli_taskpool_push_efficiency(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_taskpool_push_serializer_efficiency(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Definition at line 1278 of file test_taskpool.c.

1278 {
1279 AST_CLI_DEFINE(handle_cli_taskpool_push_efficiency, "Push tasks to a taskpool and measure efficiency"),
1280 AST_CLI_DEFINE(handle_cli_taskpool_push_serializer_efficiency, "Push tasks to a taskpool in serializers and measure efficiency"),
1281};
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197

Referenced by load_module(), and unload_module().