Asterisk - The Open Source Telephony Project GIT-master-77d630f
test_taskpool.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2025, Sangoma Technologies Inc
5 *
6 * Joshua Colp <jcolp@sangoma.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*!
20 * \file
21 * \brief taskpool unit tests
22 *
23 * \author Joshua Colp <jcolp@sangoma.com>
24 *
25 */
26
27/*** MODULEINFO
28 <depend>TEST_FRAMEWORK</depend>
29 <support_level>core</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include "asterisk/astobj2.h"
35#include "asterisk/lock.h"
36#include "asterisk/logger.h"
37#include "asterisk/module.h"
39#include "asterisk/test.h"
40#include "asterisk/taskpool.h"
41#include "asterisk/cli.h"
42
43struct test_data {
48};
49
50static struct test_data *test_alloc(void)
51{
52 struct test_data *td = ast_calloc(1, sizeof(*td));
53 if (!td) {
54 return NULL;
55 }
56 ast_mutex_init(&td->lock);
57 ast_cond_init(&td->cond, NULL);
58 return td;
59}
60
61static void test_destroy(struct test_data *td)
62{
65 ast_free(td);
66}
67
68static int simple_task(void *data)
69{
70 struct test_data *td = data;
71 SCOPED_MUTEX(lock, &td->lock);
73 td->executed = 1;
75 return 0;
76}
77
78AST_TEST_DEFINE(taskpool_push)
79{
80 struct ast_taskpool *pool = NULL;
81 struct test_data *td = NULL;
84 .idle_timeout = 0,
85 .auto_increment = 0,
86 .minimum_size = 1,
87 .initial_size = 1,
88 .max_size = 1,
89 };
91 struct timeval start;
92 struct timespec end;
93
94 switch (cmd) {
95 case TEST_INIT:
96 info->name = "push";
97 info->category = "/main/taskpool/";
98 info->summary = "Taskpool pushing test";
99 info->description =
100 "Pushes a single task into a taskpool asynchronously and ensures it is executed.";
101 return AST_TEST_NOT_RUN;
102 case TEST_EXECUTE:
103 break;
104 }
105 td = test_alloc();
106 if (!td) {
107 return AST_TEST_FAIL;
108 }
109
110 pool = ast_taskpool_create(info->name, &options);
111 if (!pool) {
112 goto end;
113 }
114
115 if (ast_taskpool_push(pool, simple_task, td)) {
116 goto end;
117 }
118
119 /* It should not take more than 5 seconds for a single simple task to execute */
120 start = ast_tvnow();
121 end.tv_sec = start.tv_sec + 5;
122 end.tv_nsec = start.tv_usec * 1000;
123
124 ast_mutex_lock(&td->lock);
125 while (!td->executed && ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
126 }
128
129 if (!td->executed) {
130 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
131 res = AST_TEST_FAIL;
132 }
133
134end:
136 test_destroy(td);
137 return res;
138}
139
140AST_TEST_DEFINE(taskpool_push_synchronous)
141{
142 struct ast_taskpool *pool = NULL;
143 struct test_data *td = NULL;
146 .idle_timeout = 0,
147 .auto_increment = 0,
148 .minimum_size = 1,
149 .initial_size = 1,
150 .max_size = 1,
151 };
153
154 switch (cmd) {
155 case TEST_INIT:
156 info->name = "push_synchronous";
157 info->category = "/main/taskpool/";
158 info->summary = "Taskpool synchronous pushing test";
159 info->description =
160 "Pushes a single task into a taskpool synchronously and ensures it is executed.";
161 return AST_TEST_NOT_RUN;
162 case TEST_EXECUTE:
163 break;
164 }
165 td = test_alloc();
166 if (!td) {
167 return AST_TEST_FAIL;
168 }
169
170 pool = ast_taskpool_create(info->name, &options);
171 if (!pool) {
172 goto end;
173 }
174
175 if (ast_taskpool_push_wait(pool, simple_task, td)) {
176 goto end;
177 }
178
179 if (!td->executed) {
180 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
181 res = AST_TEST_FAIL;
182 }
183
184end:
186 test_destroy(td);
187 return res;
188}
189
190AST_TEST_DEFINE(taskpool_push_serializer)
191{
192 struct ast_taskpool *pool = NULL;
193 struct test_data *td = NULL;
196 .idle_timeout = 0,
197 .auto_increment = 0,
198 .minimum_size = 1,
199 .initial_size = 1,
200 .max_size = 1,
201 };
204 struct timeval start;
205 struct timespec end;
206
207 switch (cmd) {
208 case TEST_INIT:
209 info->name = "push_serializer";
210 info->category = "/main/taskpool/";
211 info->summary = "Taskpool serializer pushing test";
212 info->description =
213 "Pushes a single task into a taskpool serializer and ensures it is executed.";
214 return AST_TEST_NOT_RUN;
215 case TEST_EXECUTE:
216 break;
217 }
218 td = test_alloc();
219 if (!td) {
220 return AST_TEST_FAIL;
221 }
222
223 pool = ast_taskpool_create(info->name, &options);
224 if (!pool) {
225 goto end;
226 }
227
228 serializer = ast_taskpool_serializer("serializer", pool);
229 if (!serializer) {
230 goto end;
231 }
232
234 goto end;
235 }
236
237 /* It should not take more than 5 seconds for a single simple task to execute */
238 start = ast_tvnow();
239 end.tv_sec = start.tv_sec + 5;
240 end.tv_nsec = start.tv_usec * 1000;
241
242 ast_mutex_lock(&td->lock);
243 while (!td->executed && ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
244 }
246
247 if (!td->executed) {
248 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
249 res = AST_TEST_FAIL;
250 }
251
252 if (td->taskprocessor != serializer) {
253 ast_test_status_update(test, "Expected taskprocessor to be same as serializer but it was not\n");
254 res = AST_TEST_FAIL;
255 }
256
257end:
260 test_destroy(td);
261 return res;
262}
263
264AST_TEST_DEFINE(taskpool_push_serializer_synchronous)
265{
266 struct ast_taskpool *pool = NULL;
267 struct test_data *td = NULL;
270 .idle_timeout = 0,
271 .auto_increment = 0,
272 .minimum_size = 1,
273 .initial_size = 1,
274 .max_size = 1,
275 };
278
279 switch (cmd) {
280 case TEST_INIT:
281 info->name = "push_serializer_synchronous";
282 info->category = "/main/taskpool/";
283 info->summary = "Taskpool serializer synchronous pushing test";
284 info->description =
285 "Pushes a single task into a taskpool serializer synchronously and ensures it is executed.";
286 return AST_TEST_NOT_RUN;
287 case TEST_EXECUTE:
288 break;
289 }
290 td = test_alloc();
291 if (!td) {
292 return AST_TEST_FAIL;
293 }
294
295 pool = ast_taskpool_create(info->name, &options);
296 if (!pool) {
297 goto end;
298 }
299
300 serializer = ast_taskpool_serializer("serializer", pool);
301 if (!serializer) {
302 goto end;
303 }
304
306 goto end;
307 }
308
309 if (!td->executed) {
310 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
311 res = AST_TEST_FAIL;
312 }
313
314 if (td->taskprocessor != serializer) {
315 ast_test_status_update(test, "Expected taskprocessor to be same as serializer but it was not\n");
316 res = AST_TEST_FAIL;
317 }
318
319end:
322 test_destroy(td);
323 return res;
324}
325
326static int requeue_task(void *data)
327{
329}
330
331AST_TEST_DEFINE(taskpool_push_serializer_synchronous_requeue)
332{
333 struct ast_taskpool *pool = NULL;
334 struct test_data *td = NULL;
337 .idle_timeout = 0,
338 .auto_increment = 0,
339 .minimum_size = 1,
340 .initial_size = 1,
341 .max_size = 1,
342 };
345
346 switch (cmd) {
347 case TEST_INIT:
348 info->name = "push_serializer_synchronous_requeue";
349 info->category = "/main/taskpool/";
350 info->summary = "Taskpool serializer synchronous requeueing test";
351 info->description =
352 "Pushes a single task into a taskpool serializer synchronously and ensures it is requeued and executed.";
353 return AST_TEST_NOT_RUN;
354 case TEST_EXECUTE:
355 break;
356 }
357 td = test_alloc();
358 if (!td) {
359 return AST_TEST_FAIL;
360 }
361
362 pool = ast_taskpool_create(info->name, &options);
363 if (!pool) {
364 goto end;
365 }
366
367 serializer = ast_taskpool_serializer("serializer", pool);
368 if (!serializer) {
369 goto end;
370 }
371
373 goto end;
374 }
375
376 if (!td->executed) {
377 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
378 res = AST_TEST_FAIL;
379 }
380
381 if (td->taskprocessor != serializer) {
382 ast_test_status_update(test, "Expected taskprocessor to be same as serializer but it was not\n");
383 res = AST_TEST_FAIL;
384 }
385
386end:
389 test_destroy(td);
390 return res;
391}
392
393AST_TEST_DEFINE(taskpool_push_grow)
394{
395 struct ast_taskpool *pool = NULL;
396 struct test_data *td = NULL;
399 .idle_timeout = 0,
400 .auto_increment = 1,
401 .minimum_size = 0,
402 .initial_size = 0,
403 .max_size = 1,
404 };
406 struct timeval start;
407 struct timespec end;
408
409 switch (cmd) {
410 case TEST_INIT:
411 info->name = "push_grow";
412 info->category = "/main/taskpool/";
413 info->summary = "Taskpool pushing test with auto-grow enabled";
414 info->description =
415 "Pushes a single task into a taskpool asynchronously, ensures it is executed and the pool grows.";
416 return AST_TEST_NOT_RUN;
417 case TEST_EXECUTE:
418 break;
419 }
420 td = test_alloc();
421 if (!td) {
422 return AST_TEST_FAIL;
423 }
424
425 pool = ast_taskpool_create(info->name, &options);
426 if (!pool) {
427 goto end;
428 }
429
430 if (ast_taskpool_taskprocessors_count(pool) != 0) {
431 ast_test_status_update(test, "Expected taskpool to have 0 taskprocessors but it has %zu\n", ast_taskpool_taskprocessors_count(pool));
432 res = AST_TEST_FAIL;
433 goto end;
434 }
435
436 if (ast_taskpool_push(pool, simple_task, td)) {
437 goto end;
438 }
439
440 if (ast_taskpool_taskprocessors_count(pool) != 1) {
441 ast_test_status_update(test, "Expected taskpool to have 1 taskprocessor but it has %zu\n", ast_taskpool_taskprocessors_count(pool));
442 res = AST_TEST_FAIL;
443 goto end;
444 }
445
446 /* It should not take more than 5 seconds for a single simple task to execute */
447 start = ast_tvnow();
448 end.tv_sec = start.tv_sec + 5;
449 end.tv_nsec = start.tv_usec * 1000;
450
451 ast_mutex_lock(&td->lock);
452 while (!td->executed && ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
453 }
455
456 if (!td->executed) {
457 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
458 res = AST_TEST_FAIL;
459 }
460
461end:
463 test_destroy(td);
464 return res;
465}
466
467AST_TEST_DEFINE(taskpool_push_shrink)
468{
469 struct ast_taskpool *pool = NULL;
470 struct test_data *td = NULL;
473 .idle_timeout = 1,
474 .auto_increment = 1,
475 .minimum_size = 0,
476 .initial_size = 0,
477 .max_size = 1,
478 };
480 struct timeval start;
481 struct timespec end;
482 int iterations = 0;
483
484 switch (cmd) {
485 case TEST_INIT:
486 info->name = "push_shrink";
487 info->category = "/main/taskpool/";
488 info->summary = "Taskpool pushing test with auto-shrink enabled";
489 info->description =
490 "Pushes a single task into a taskpool asynchronously, ensures it is executed and the pool shrinks.";
491 return AST_TEST_NOT_RUN;
492 case TEST_EXECUTE:
493 break;
494 }
495 td = test_alloc();
496 if (!td) {
497 return AST_TEST_FAIL;
498 }
499
500 pool = ast_taskpool_create(info->name, &options);
501 if (!pool) {
502 goto end;
503 }
504
505 if (ast_taskpool_taskprocessors_count(pool) != 0) {
506 ast_test_status_update(test, "Expected taskpool to have 0 taskprocessors but it has %zu\n", ast_taskpool_taskprocessors_count(pool));
507 res = AST_TEST_FAIL;
508 goto end;
509 }
510
511 if (ast_taskpool_push(pool, simple_task, td)) {
512 res = AST_TEST_FAIL;
513 goto end;
514 }
515
516 if (ast_taskpool_taskprocessors_count(pool) != 1) {
517 ast_test_status_update(test, "Expected taskpool to have 1 taskprocessor but it has %zu\n", ast_taskpool_taskprocessors_count(pool));
518 res = AST_TEST_FAIL;
519 goto end;
520 }
521
522 /* We give 10 seconds for the pool to shrink back to normal, but if it happens earlier we
523 * stop our check early.
524 */
525 ast_mutex_lock(&td->lock);
526 do {
527 start = ast_tvnow();
528 end.tv_sec = start.tv_sec + 1;
529 end.tv_nsec = start.tv_usec * 1000;
530
531 if (ast_cond_timedwait(&td->cond, &td->lock, &end) == ETIMEDOUT) {
532 iterations++;
533 }
534 } while (ast_taskpool_taskprocessors_count(pool) != 0 && iterations != 10);
535
536 if (!td->executed) {
537 ast_test_status_update(test, "Expected simple task to be executed but it was not\n");
538 res = AST_TEST_FAIL;
539 }
540
541 if (ast_taskpool_taskprocessors_count(pool) != 0) {
542 ast_test_status_update(test, "Expected taskpool to have 0 taskprocessors but it has %zu\n", ast_taskpool_taskprocessors_count(pool));
543 res = AST_TEST_FAIL;
544 goto end;
545 }
546
547end:
549 test_destroy(td);
550 return res;
551}
552
557};
558
559static int efficiency_task(void *data)
560{
561 struct efficiency_task_data *etd = data;
562
563 if (etd->shutdown) {
564 ao2_ref(etd->pool, -1);
565 return 0;
566 }
567
569
570 if (ast_taskpool_push(etd->pool, efficiency_task, etd)) {
571 ao2_ref(etd->pool, -1);
572 return -1;
573 }
574
575 return 0;
576}
577
578static char *handle_cli_taskpool_push_efficiency(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
579{
580 struct ast_taskpool *pool = NULL;
581 struct test_data *td = NULL;
584 .idle_timeout = 0,
585 .auto_increment = 0,
586 .minimum_size = 5,
587 .initial_size = 5,
588 .max_size = 5,
589 };
590 struct efficiency_task_data etd = {
591 .pool = NULL,
592 .num_tasks_executed = 0,
593 .shutdown = 0,
594 };
595 struct timeval start;
596 struct timespec end;
597 int i;
598
599 switch (cmd) {
600 case CLI_INIT:
601 e->command = "taskpool push efficiency";
602 e->usage =
603 "Usage: taskpool push efficiency\n"
604 " Pushes 200 tasks to a taskpool and measures\n"
605 " the number of tasks executed within 30 seconds.\n";
606 return NULL;
607 case CLI_GENERATE:
608 return NULL;
609 }
610
611 td = test_alloc();
612 if (!td) {
613 return CLI_SUCCESS;
614 }
615
616 pool = ast_taskpool_create("taskpool_push_efficiency", &options);
617 if (!pool) {
618 goto end;
619 }
620
621 etd.pool = pool;
622
623 /* Push in 200 tasks, cause why not */
624 for (i = 0; i < 200; i++) {
625 /* Ensure that the task has a reference to the pool */
626 ao2_bump(pool);
627 if (ast_taskpool_push(pool, efficiency_task, &etd)) {
628 goto end;
629 }
630 }
631
632 /* Wait for 30 seconds */
633 start = ast_tvnow();
634 end.tv_sec = start.tv_sec + 30;
635 end.tv_nsec = start.tv_usec * 1000;
636
637 ast_mutex_lock(&td->lock);
638 while (ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
639 }
641
642 /* Give the total tasks executed, and tell each task to not requeue */
643 ast_cli(a->fd, "Total tasks executed in 30 seconds: %d\n", etd.num_tasks_executed);
644
645end:
646 etd.shutdown = 1;
648 test_destroy(td);
649 return CLI_SUCCESS;
650}
651
656};
657
658static int serializer_efficiency_task(void *data)
659{
660 struct serializer_efficiency_task_data *etd = data;
661 struct ast_taskprocessor *taskprocessor = etd->serializer[0];
662
663 if (*etd->shutdown) {
664 return 0;
665 }
666
668
669 /* We ping pong a task between a pair of taskprocessors to ensure that
670 * a single taskprocessor does not receive a thread from the threadpool
671 * exclusively.
672 */
673 if (taskprocessor == ast_taskpool_serializer_get_current()) {
674 taskprocessor = etd->serializer[1];
675 }
676
677 if (ast_taskprocessor_push(taskprocessor,
679 return -1;
680 }
681
682 return 0;
683}
684
686{
687 struct ast_taskpool *pool = NULL;
688 struct test_data *td = NULL;
691 .idle_timeout = 0,
692 .auto_increment = 0,
693 .minimum_size = 5,
694 .initial_size = 5,
695 .max_size = 5,
696 };
697 struct serializer_efficiency_task_data etd[200];
698 struct timeval start;
699 struct timespec end;
700 int i;
701 int num_tasks_executed = 0;
702 int shutdown = 0;
703
704 switch (cmd) {
705 case CLI_INIT:
706 e->command = "taskpool push serializer efficiency";
707 e->usage =
708 "Usage: taskpool push serializer efficiency\n"
709 " Pushes 200 tasks to a taskpool in serializers and measures\n"
710 " the number of tasks executed within 30 seconds.\n";
711 return NULL;
712 case CLI_GENERATE:
713 return NULL;
714 }
715 td = test_alloc();
716 if (!td) {
717 return CLI_SUCCESS;
718 }
719
720 memset(&etd, 0, sizeof(etd));
721
722 pool = ast_taskpool_create("taskpool_push_serializer_efficiency", &options);
723 if (!pool) {
724 goto end;
725 }
726
727 /* We create 400 (200 pairs) of serializers */
728 for (i = 0; i < 200; i++) {
729 char serializer_name[AST_TASKPROCESSOR_MAX_NAME + 1];
730
731 ast_taskprocessor_build_name(serializer_name, sizeof(serializer_name), "serializer%d", i);
732 etd[i].serializer[0] = ast_taskpool_serializer(serializer_name, pool);
733 if (!etd[i].serializer[0]) {
734 goto end;
735 }
736
737 ast_taskprocessor_build_name(serializer_name, sizeof(serializer_name), "serializer%d", i);
738 etd[i].serializer[1] = ast_taskpool_serializer(serializer_name, pool);
739 if (!etd[i].serializer[1]) {
740 goto end;
741 }
742
743 etd[i].num_tasks_executed = &num_tasks_executed;
744 etd[i].shutdown = &shutdown;
745 }
746
747 /* And once created we push in 200 tasks */
748 for (i = 0; i < 200; i++) {
750 goto end;
751 }
752 }
753
754 /* Wait for 30 seconds */
755 start = ast_tvnow();
756 end.tv_sec = start.tv_sec + 30;
757 end.tv_nsec = start.tv_usec * 1000;
758
759 ast_mutex_lock(&td->lock);
760 while (ast_cond_timedwait(&td->cond, &td->lock, &end) != ETIMEDOUT) {
761 }
763
764 /* Give the total tasks executed, and tell each task to not requeue */
765 ast_cli(a->fd, "Total tasks executed in 30 seconds: %d\n", num_tasks_executed);
766 shutdown = 1;
767
768end:
769 /* We need to unreference each serializer */
770 for (i = 0; i < 200; i++) {
773 }
775 test_destroy(td);
776 return CLI_SUCCESS;
777}
778
779static struct ast_cli_entry cli[] = {
780 AST_CLI_DEFINE(handle_cli_taskpool_push_efficiency, "Push tasks to a taskpool and measure efficiency"),
781 AST_CLI_DEFINE(handle_cli_taskpool_push_serializer_efficiency, "Push tasks to a taskpool in serializers and measure efficiency"),
782};
783
784static int unload_module(void)
785{
787 AST_TEST_UNREGISTER(taskpool_push);
788 AST_TEST_UNREGISTER(taskpool_push_synchronous);
789 AST_TEST_UNREGISTER(taskpool_push_serializer);
790 AST_TEST_UNREGISTER(taskpool_push_serializer_synchronous);
791 AST_TEST_UNREGISTER(taskpool_push_serializer_synchronous_requeue);
792 AST_TEST_UNREGISTER(taskpool_push_grow);
793 AST_TEST_UNREGISTER(taskpool_push_shrink);
794 return 0;
795}
796
797static int load_module(void)
798{
800 AST_TEST_REGISTER(taskpool_push);
801 AST_TEST_REGISTER(taskpool_push_synchronous);
802 AST_TEST_REGISTER(taskpool_push_serializer);
803 AST_TEST_REGISTER(taskpool_push_serializer_synchronous);
804 AST_TEST_REGISTER(taskpool_push_serializer_synchronous_requeue);
805 AST_TEST_REGISTER(taskpool_push_grow);
806 AST_TEST_REGISTER(taskpool_push_shrink);
808}
809
ast_mutex_t lock
Definition: app_sla.c:337
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
Standard Command Line Interface.
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
char * end
Definition: eagi_proxy.c:73
Support for logging to various files, console and syslog Configuration in file logger....
Asterisk locking-related definitions:
#define ast_cond_destroy(cond)
Definition: lock.h:209
#define ast_cond_init(cond, attr)
Definition: lock.h:208
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:213
#define ast_mutex_init(pmutex)
Definition: lock.h:193
#define ast_mutex_unlock(a)
Definition: lock.h:197
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
pthread_cond_t ast_cond_t
Definition: lock.h:185
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition: lock.h:596
#define ast_mutex_destroy(a)
Definition: lock.h:195
#define ast_mutex_lock(a)
Definition: lock.h:196
#define ast_cond_signal(cond)
Definition: lock.h:210
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:581
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
def info(msg)
#define NULL
Definition: resample.c:96
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure for mutex and tracking information.
Definition: lock.h:142
An opaque taskpool structure.
Definition: taskpool.c:62
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
struct ast_taskpool * pool
struct ast_taskprocessor * serializer[2]
Sorcery object created based on backend data.
struct ast_taskprocessor * taskprocessor
Definition: test_taskpool.c:47
#define AST_TASKPOOL_OPTIONS_VERSION
Definition: taskpool.h:69
size_t ast_taskpool_taskprocessors_count(struct ast_taskpool *pool)
Get the current number of taskprocessors in the taskpool.
Definition: taskpool.c:451
struct ast_taskprocessor * ast_taskpool_serializer(const char *name, struct ast_taskpool *pool)
Serialized execution of tasks within a ast_taskpool.
Definition: taskpool.c:819
void ast_taskpool_shutdown(struct ast_taskpool *pool)
Shut down a taskpool and remove the underlying taskprocessors.
Definition: taskpool.c:653
struct ast_taskprocessor * ast_taskpool_serializer_get_current(void)
Get the taskpool serializer currently associated with this thread.
Definition: taskpool.c:784
int ast_taskpool_push(struct ast_taskpool *pool, int(*task)(void *data), void *data) attribute_warn_unused_result
Push a task to the taskpool.
Definition: taskpool.c:522
int ast_taskpool_serializer_push_wait(struct ast_taskprocessor *serializer, int(*task)(void *data), void *data)
Push a task to a serializer, and wait for completion.
Definition: taskpool.c:832
struct ast_taskpool * ast_taskpool_create(const char *name, const struct ast_taskpool_options *options)
Create a new taskpool.
Definition: taskpool.c:324
int ast_taskpool_push_wait(struct ast_taskpool *pool, int(*task)(void *data), void *data) attribute_warn_unused_result
Push a task to the taskpool, and wait for completion.
Definition: taskpool.c:623
An API for managing task processing threads that can be shared across modules.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int(*task_exe)(void *datap), void *datap) attribute_warn_unused_result
Push a task into the specified taskprocessor queue and signal the taskprocessor thread.
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).
Definition: taskprocessor.h:61
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
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_val a
static struct test_data * test_alloc(void)
Definition: test_taskpool.c:50
static char * handle_cli_taskpool_push_efficiency(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int requeue_task(void *data)
static int serializer_efficiency_task(void *data)
static void test_destroy(struct test_data *td)
Definition: test_taskpool.c:61
static struct ast_cli_entry cli[]
static int load_module(void)
static char * handle_cli_taskpool_push_serializer_efficiency(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int unload_module(void)
AST_TEST_DEFINE(taskpool_push)
Definition: test_taskpool.c:78
static int simple_task(void *data)
Definition: test_taskpool.c:68
static int efficiency_task(void *data)
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
#define ARRAY_LEN(a)
Definition: utils.h:703