Asterisk - The Open Source Telephony Project GIT-master-77d630f
Data Structures | Functions | Variables
test_threadpool.c File Reference

threadpool 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/threadpool.h"
Include dependency graph for test_threadpool.c:

Go to the source code of this file.

Data Structures

struct  complex_task_data
 
struct  efficiency_task_data
 
struct  serializer_efficiency_task_data
 
struct  simple_task_data
 
struct  test_listener_data
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
 AST_TEST_DEFINE (threadpool_auto_increment)
 
 AST_TEST_DEFINE (threadpool_initial_threads)
 
 AST_TEST_DEFINE (threadpool_max_size)
 
 AST_TEST_DEFINE (threadpool_more_destruction)
 
 AST_TEST_DEFINE (threadpool_one_task_one_thread)
 
 AST_TEST_DEFINE (threadpool_one_thread_multiple_tasks)
 
 AST_TEST_DEFINE (threadpool_one_thread_one_task)
 
 AST_TEST_DEFINE (threadpool_push)
 
 AST_TEST_DEFINE (threadpool_reactivation)
 
 AST_TEST_DEFINE (threadpool_serializer)
 
 AST_TEST_DEFINE (threadpool_serializer_dupe)
 
 AST_TEST_DEFINE (threadpool_task_distribution)
 
 AST_TEST_DEFINE (threadpool_thread_creation)
 
 AST_TEST_DEFINE (threadpool_thread_destruction)
 
 AST_TEST_DEFINE (threadpool_thread_timeout)
 
 AST_TEST_DEFINE (threadpool_thread_timeout_thrash)
 
static int complex_task (void *data)
 
static struct complex_task_datacomplex_task_data_alloc (void)
 
static void complex_task_data_free (struct complex_task_data *ctd)
 
static int efficiency_task (void *data)
 
static char * handle_cli_threadpool_push_efficiency (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_cli_threadpool_push_serializer_efficiency (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int has_complex_started (struct complex_task_data *ctd)
 
static enum ast_test_result_state listener_check (struct ast_test *test, struct ast_threadpool_listener *listener, int task_pushed, int was_empty, int num_tasks, int num_active, int num_idle, int empty_notice)
 
static int load_module (void)
 
static void poke_worker (struct complex_task_data *ctd)
 
static int serializer_efficiency_task (void *data)
 
static int simple_task (void *data)
 
static struct simple_task_datasimple_task_data_alloc (void)
 
static void simple_task_data_free (struct simple_task_data *std)
 
static struct test_listener_datatest_alloc (void)
 
static void test_emptied (struct ast_threadpool *pool, struct ast_threadpool_listener *listener)
 
static void test_shutdown (struct ast_threadpool_listener *listener)
 
static void test_state_changed (struct ast_threadpool *pool, struct ast_threadpool_listener *listener, int active_threads, int idle_threads)
 
static void test_task_pushed (struct ast_threadpool *pool, struct ast_threadpool_listener *listener, int was_empty)
 
static int unload_module (void)
 
static enum ast_test_result_state wait_for_completion (struct ast_test *test, struct simple_task_data *std)
 
static enum ast_test_result_state wait_for_complex_completion (struct complex_task_data *ctd)
 
static int wait_for_complex_start (struct complex_task_data *ctd)
 
static enum ast_test_result_state wait_for_empty_notice (struct ast_test *test, struct test_listener_data *tld)
 
static void wait_for_task_pushed (struct ast_threadpool_listener *listener)
 
static enum ast_test_result_state wait_until_thread_state (struct ast_test *test, struct test_listener_data *tld, int num_active, int num_idle)
 
static enum ast_test_result_state wait_until_thread_state_task_pushed (struct ast_test *test, struct test_listener_data *tld, int num_active, int num_idle, int num_tasks)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "threadpool test module" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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 []
 
static const struct ast_threadpool_listener_callbacks test_callbacks
 

Detailed Description

threadpool unit tests

Author
Mark Michelson mmich.nosp@m.elso.nosp@m.n@dig.nosp@m.ium..nosp@m.com

Definition in file test_threadpool.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2100 of file test_threadpool.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 2100 of file test_threadpool.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 2100 of file test_threadpool.c.

◆ AST_TEST_DEFINE() [1/16]

AST_TEST_DEFINE ( threadpool_auto_increment  )

Definition at line 1098 of file test_threadpool.c.

1099{
1100 struct ast_threadpool *pool = NULL;
1102 struct simple_task_data *std1 = NULL;
1103 struct simple_task_data *std2 = NULL;
1104 struct simple_task_data *std3 = NULL;
1105 struct simple_task_data *std4 = NULL;
1107 struct test_listener_data *tld = NULL;
1110 .idle_timeout = 0,
1111 .auto_increment = 3,
1112 .initial_size = 0,
1113 .max_size = 0,
1114 };
1115
1116 switch (cmd) {
1117 case TEST_INIT:
1118 info->name = "auto_increment";
1119 info->category = "/main/threadpool/";
1120 info->summary = "Test that the threadpool grows as tasks are added";
1121 info->description =
1122 "Create an empty threadpool and push a task to it. Once the task is\n"
1123 "pushed, the threadpool should add three threads and be able to\n"
1124 "handle the task. The threads should then go idle";
1125 return AST_TEST_NOT_RUN;
1126 case TEST_EXECUTE:
1127 break;
1128 }
1129
1130 tld = test_alloc();
1131 if (!tld) {
1132 return AST_TEST_FAIL;
1133 }
1134
1136 if (!listener) {
1137 goto end;
1138 }
1139
1140 pool = ast_threadpool_create(info->name, listener, &options);
1141 if (!pool) {
1142 goto end;
1143 }
1144
1145 std1 = simple_task_data_alloc();
1146 std2 = simple_task_data_alloc();
1147 std3 = simple_task_data_alloc();
1148 std4 = simple_task_data_alloc();
1149 if (!std1 || !std2 || !std3 || !std4) {
1150 goto end;
1151 }
1152
1153 if (ast_threadpool_push(pool, simple_task, std1)) {
1154 goto end;
1155 }
1156
1157 /* Pushing the task should result in the threadpool growing
1158 * by three threads. This will allow the task to actually execute
1159 */
1160 res = wait_for_completion(test, std1);
1161 if (res == AST_TEST_FAIL) {
1162 goto end;
1163 }
1164
1165 res = wait_for_empty_notice(test, tld);
1166 if (res == AST_TEST_FAIL) {
1167 goto end;
1168 }
1169
1170 res = wait_until_thread_state(test, tld, 0, 3);
1171 if (res == AST_TEST_FAIL) {
1172 goto end;
1173 }
1174
1175 /* Now push three tasks into the pool and ensure the pool does not
1176 * grow.
1177 */
1178 res = AST_TEST_FAIL;
1179
1180 if (ast_threadpool_push(pool, simple_task, std2)) {
1181 goto end;
1182 }
1183
1184 if (ast_threadpool_push(pool, simple_task, std3)) {
1185 goto end;
1186 }
1187
1188 if (ast_threadpool_push(pool, simple_task, std4)) {
1189 goto end;
1190 }
1191
1192 res = wait_for_completion(test, std2);
1193 if (res == AST_TEST_FAIL) {
1194 goto end;
1195 }
1196 res = wait_for_completion(test, std3);
1197 if (res == AST_TEST_FAIL) {
1198 goto end;
1199 }
1200 res = wait_for_completion(test, std4);
1201 if (res == AST_TEST_FAIL) {
1202 goto end;
1203 }
1204
1205 res = wait_for_empty_notice(test, tld);
1206 if (res == AST_TEST_FAIL) {
1207 goto end;
1208 }
1209
1210 res = wait_until_thread_state_task_pushed(test, tld, 0, 3, 4);
1211 if (res == AST_TEST_FAIL) {
1212 goto end;
1213 }
1214
1215end:
1222 ast_free(tld);
1223 return res;
1224}
static void * listener(void *unused)
Definition: asterisk.c:1530
#define ast_free(a)
Definition: astmm.h:180
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
char * end
Definition: eagi_proxy.c:73
def info(msg)
#define NULL
Definition: resample.c:96
listener for a threadpool
Definition: threadpool.c:110
An opaque threadpool structure.
Definition: threadpool.c:36
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
ast_test_result_state
Definition: test.h:193
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
static struct test_options options
static struct test_listener_data * test_alloc(void)
static enum ast_test_result_state wait_for_completion(struct ast_test *test, struct simple_task_data *std)
static const struct ast_threadpool_listener_callbacks test_callbacks
static enum ast_test_result_state wait_until_thread_state_task_pushed(struct ast_test *test, struct test_listener_data *tld, int num_active, int num_idle, int num_tasks)
static struct simple_task_data * simple_task_data_alloc(void)
static enum ast_test_result_state wait_until_thread_state(struct ast_test *test, struct test_listener_data *tld, int num_active, int num_idle)
static int simple_task(void *data)
static enum ast_test_result_state wait_for_empty_notice(struct ast_test *test, struct test_listener_data *tld)
static void simple_task_data_free(struct simple_task_data *std)
void ast_threadpool_shutdown(struct ast_threadpool *pool)
Shut down a threadpool and destroy it.
Definition: threadpool.c:966
int ast_threadpool_push(struct ast_threadpool *pool, int(*task)(void *data), void *data) attribute_warn_unused_result
Push a task to the threadpool.
Definition: threadpool.c:957
struct ast_threadpool * ast_threadpool_create(const char *name, struct ast_threadpool_listener *listener, const struct ast_threadpool_options *options)
Create a new threadpool.
Definition: threadpool.c:916
struct ast_threadpool_listener * ast_threadpool_listener_alloc(const struct ast_threadpool_listener_callbacks *callbacks, void *user_data)
Allocate a threadpool listener.
Definition: threadpool.c:894
#define AST_THREADPOOL_OPTIONS_VERSION
Definition: threadpool.h:73

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_push(), ast_threadpool_shutdown(), end, sip_to_pjsip::info(), listener(), NULL, options, simple_task(), simple_task_data_alloc(), simple_task_data_free(), test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, wait_for_completion(), wait_for_empty_notice(), wait_until_thread_state(), and wait_until_thread_state_task_pushed().

◆ AST_TEST_DEFINE() [2/16]

AST_TEST_DEFINE ( threadpool_initial_threads  )

Definition at line 459 of file test_threadpool.c.

460{
461 struct ast_threadpool *pool = NULL;
464 struct test_listener_data *tld = NULL;
467 .idle_timeout = 0,
468 .auto_increment = 0,
469 .initial_size = 3,
470 .max_size = 0,
471 };
472
473 switch (cmd) {
474 case TEST_INIT:
475 info->name = "initial_threads";
476 info->category = "/main/threadpool/";
477 info->summary = "Test threadpool initialization state";
478 info->description =
479 "Ensure that a threadpool created with a specific size contains the\n"
480 "proper number of idle threads.";
481 return AST_TEST_NOT_RUN;
482 case TEST_EXECUTE:
483 break;
484 }
485
486 tld = test_alloc();
487 if (!tld) {
488 return AST_TEST_FAIL;
489 }
490
492 if (!listener) {
493 goto end;
494 }
495
497 if (!pool) {
498 goto end;
499 }
500
501 res = wait_until_thread_state(test, tld, 0, 3);
502
503end:
506 ast_free(tld);
507 return res;
508}

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_shutdown(), end, sip_to_pjsip::info(), listener(), NULL, options, test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, and wait_until_thread_state().

◆ AST_TEST_DEFINE() [3/16]

AST_TEST_DEFINE ( threadpool_max_size  )

Definition at line 1226 of file test_threadpool.c.

1227{
1228 struct ast_threadpool *pool = NULL;
1230 struct simple_task_data *std = NULL;
1232 struct test_listener_data *tld = NULL;
1235 .idle_timeout = 0,
1236 .auto_increment = 3,
1237 .initial_size = 0,
1238 .max_size = 2,
1239 };
1240
1241 switch (cmd) {
1242 case TEST_INIT:
1243 info->name = "max_size";
1244 info->category = "/main/threadpool/";
1245 info->summary = "Test that the threadpool does not exceed its maximum size restriction";
1246 info->description =
1247 "Create an empty threadpool and push a task to it. Once the task is\n"
1248 "pushed, the threadpool should attempt to grow by three threads, but the\n"
1249 "pool's restrictions should only allow two threads to be added.";
1250 return AST_TEST_NOT_RUN;
1251 case TEST_EXECUTE:
1252 break;
1253 }
1254
1255 tld = test_alloc();
1256 if (!tld) {
1257 return AST_TEST_FAIL;
1258 }
1259
1261 if (!listener) {
1262 goto end;
1263 }
1264
1265 pool = ast_threadpool_create(info->name, listener, &options);
1266 if (!pool) {
1267 goto end;
1268 }
1269
1270 std = simple_task_data_alloc();
1271 if (!std) {
1272 goto end;
1273 }
1274
1275 if (ast_threadpool_push(pool, simple_task, std)) {
1276 goto end;
1277 }
1278
1279 res = wait_for_completion(test, std);
1280 if (res == AST_TEST_FAIL) {
1281 goto end;
1282 }
1283
1284 res = wait_until_thread_state(test, tld, 0, 2);
1285 if (res == AST_TEST_FAIL) {
1286 goto end;
1287 }
1288
1289 res = listener_check(test, listener, 1, 1, 1, 0, 2, 1);
1290end:
1294 ast_free(tld);
1295 return res;
1296}
static enum ast_test_result_state listener_check(struct ast_test *test, struct ast_threadpool_listener *listener, int task_pushed, int was_empty, int num_tasks, int num_active, int num_idle, int empty_notice)

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_push(), ast_threadpool_shutdown(), end, sip_to_pjsip::info(), listener(), listener_check(), NULL, options, simple_task(), simple_task_data_alloc(), simple_task_data_free(), test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, wait_for_completion(), and wait_until_thread_state().

◆ AST_TEST_DEFINE() [4/16]

AST_TEST_DEFINE ( threadpool_more_destruction  )

Definition at line 1623 of file test_threadpool.c.

1624{
1625 struct ast_threadpool *pool = NULL;
1627 struct complex_task_data *ctd1 = NULL;
1628 struct complex_task_data *ctd2 = NULL;
1630 struct test_listener_data *tld = NULL;
1633 .idle_timeout = 0,
1634 .auto_increment = 0,
1635 .initial_size = 0,
1636 .max_size = 0,
1637 };
1638
1639 switch (cmd) {
1640 case TEST_INIT:
1641 info->name = "more_destruction";
1642 info->category = "/main/threadpool/";
1643 info->summary = "Test that threads are destroyed as expected";
1644 info->description =
1645 "Push two tasks into a threadpool. Set the threadpool size to 4\n"
1646 "Ensure that there are 2 active and 2 idle threads. Then shrink the\n"
1647 "threadpool down to 1 thread. Ensure that the thread leftover is active\n"
1648 "and ensure that both tasks complete.";
1649 return AST_TEST_NOT_RUN;
1650 case TEST_EXECUTE:
1651 break;
1652 }
1653
1654 tld = test_alloc();
1655 if (!tld) {
1656 return AST_TEST_FAIL;
1657 }
1658
1660 if (!listener) {
1661 goto end;
1662 }
1663
1664 pool = ast_threadpool_create(info->name, listener, &options);
1665 if (!pool) {
1666 goto end;
1667 }
1668
1669 ctd1 = complex_task_data_alloc();
1670 ctd2 = complex_task_data_alloc();
1671 if (!ctd1 || !ctd2) {
1672 goto end;
1673 }
1674
1675 if (ast_threadpool_push(pool, complex_task, ctd1)) {
1676 goto end;
1677 }
1678
1679 if (ast_threadpool_push(pool, complex_task, ctd2)) {
1680 goto end;
1681 }
1682
1683 ast_threadpool_set_size(pool, 4);
1684
1685 res = wait_until_thread_state(test, tld, 2, 2);
1686 if (res == AST_TEST_FAIL) {
1687 goto end;
1688 }
1689
1690 res = listener_check(test, listener, 1, 0, 2, 2, 2, 0);
1691 if (res == AST_TEST_FAIL) {
1692 goto end;
1693 }
1694
1695 ast_threadpool_set_size(pool, 1);
1696
1697 /* Shrinking the threadpool should kill off the two idle threads
1698 * and one of the active threads.
1699 */
1700 res = wait_until_thread_state(test, tld, 1, 0);
1701 if (res == AST_TEST_FAIL) {
1702 goto end;
1703 }
1704
1705 res = listener_check(test, listener, 1, 0, 2, 1, 0, 0);
1706 if (res == AST_TEST_FAIL) {
1707 goto end;
1708 }
1709
1710 /* The tasks are stalled until we poke them */
1711 poke_worker(ctd1);
1712 poke_worker(ctd2);
1713
1714 res = wait_for_complex_completion(ctd1);
1715 if (res == AST_TEST_FAIL) {
1716 goto end;
1717 }
1718 res = wait_for_complex_completion(ctd2);
1719 if (res == AST_TEST_FAIL) {
1720 goto end;
1721 }
1722
1723 res = wait_until_thread_state(test, tld, 0, 1);
1724 if (res == AST_TEST_FAIL) {
1725 goto end;
1726 }
1727
1728 res = listener_check(test, listener, 1, 0, 2, 0, 1, 1);
1729
1730end:
1735 ast_free(tld);
1736 return res;
1737}
static struct complex_task_data * complex_task_data_alloc(void)
static enum ast_test_result_state wait_for_complex_completion(struct complex_task_data *ctd)
static void complex_task_data_free(struct complex_task_data *ctd)
static int complex_task(void *data)
static void poke_worker(struct complex_task_data *ctd)
void ast_threadpool_set_size(struct ast_threadpool *threadpool, unsigned int size)
Set the number of threads for the thread pool.
Definition: threadpool.c:875

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_push(), ast_threadpool_set_size(), ast_threadpool_shutdown(), complex_task(), complex_task_data_alloc(), complex_task_data_free(), end, sip_to_pjsip::info(), listener(), listener_check(), NULL, options, poke_worker(), test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, wait_for_complex_completion(), and wait_until_thread_state().

◆ AST_TEST_DEFINE() [5/16]

AST_TEST_DEFINE ( threadpool_one_task_one_thread  )

Definition at line 788 of file test_threadpool.c.

789{
790 struct ast_threadpool *pool = NULL;
792 struct simple_task_data *std = NULL;
794 struct test_listener_data *tld = NULL;
797 .idle_timeout = 0,
798 .auto_increment = 0,
799 .initial_size = 0,
800 .max_size = 0,
801 };
802
803 switch (cmd) {
804 case TEST_INIT:
805 info->name = "one_task_one_thread";
806 info->category = "/main/threadpool/";
807 info->summary = "Test a single task with a single thread";
808 info->description =
809 "Push a task into an empty threadpool, then add a thread to the pool.";
810 return AST_TEST_NOT_RUN;
811 case TEST_EXECUTE:
812 break;
813 }
814
815 tld = test_alloc();
816 if (!tld) {
817 return AST_TEST_FAIL;
818 }
819
821 if (!listener) {
822 goto end;
823 }
824
826 if (!pool) {
827 goto end;
828 }
829
831 if (!std) {
832 goto end;
833 }
834
835 if (ast_threadpool_push(pool, simple_task, std)) {
836 goto end;
837 }
838
840
841 /* Threads added to the pool are active when they start,
842 * so the newly-created thread should immediately execute
843 * the waiting task.
844 */
845 res = wait_for_completion(test, std);
846 if (res == AST_TEST_FAIL) {
847 goto end;
848 }
849
850 res = wait_for_empty_notice(test, tld);
851 if (res == AST_TEST_FAIL) {
852 goto end;
853 }
854
855 /* After completing the task, the thread should go idle */
856 res = wait_until_thread_state(test, tld, 0, 1);
857 if (res == AST_TEST_FAIL) {
858 goto end;
859 }
860
861 res = listener_check(test, listener, 1, 1, 1, 0, 1, 1);
862
863end:
867 ast_free(tld);
868 return res;
869
870}

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_push(), ast_threadpool_set_size(), ast_threadpool_shutdown(), end, sip_to_pjsip::info(), listener(), listener_check(), NULL, options, simple_task(), simple_task_data_alloc(), simple_task_data_free(), test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, wait_for_completion(), wait_for_empty_notice(), and wait_until_thread_state().

◆ AST_TEST_DEFINE() [6/16]

AST_TEST_DEFINE ( threadpool_one_thread_multiple_tasks  )

Definition at line 957 of file test_threadpool.c.

958{
959 struct ast_threadpool *pool = NULL;
961 struct simple_task_data *std1 = NULL;
962 struct simple_task_data *std2 = NULL;
963 struct simple_task_data *std3 = NULL;
965 struct test_listener_data *tld = NULL;
968 .idle_timeout = 0,
969 .auto_increment = 0,
970 .initial_size = 0,
971 .max_size = 0,
972 };
973
974 switch (cmd) {
975 case TEST_INIT:
976 info->name = "one_thread_multiple_tasks";
977 info->category = "/main/threadpool/";
978 info->summary = "Test a single thread with multiple tasks";
979 info->description =
980 "Add a thread to the pool and then push three tasks to it.";
981 return AST_TEST_NOT_RUN;
982 case TEST_EXECUTE:
983 break;
984 }
985
986 tld = test_alloc();
987 if (!tld) {
988 return AST_TEST_FAIL;
989 }
990
992 if (!listener) {
993 goto end;
994 }
995
997 if (!pool) {
998 goto end;
999 }
1000
1001 std1 = simple_task_data_alloc();
1002 std2 = simple_task_data_alloc();
1003 std3 = simple_task_data_alloc();
1004 if (!std1 || !std2 || !std3) {
1005 goto end;
1006 }
1007
1008 ast_threadpool_set_size(pool, 1);
1009
1010 res = wait_until_thread_state(test, tld, 0, 1);
1011 if (res == AST_TEST_FAIL) {
1012 goto end;
1013 }
1014
1015 res = AST_TEST_FAIL;
1016 if (ast_threadpool_push(pool, simple_task, std1)) {
1017 goto end;
1018 }
1019
1020 if (ast_threadpool_push(pool, simple_task, std2)) {
1021 goto end;
1022 }
1023
1024 if (ast_threadpool_push(pool, simple_task, std3)) {
1025 goto end;
1026 }
1027
1028 res = wait_for_completion(test, std1);
1029 if (res == AST_TEST_FAIL) {
1030 goto end;
1031 }
1032 res = wait_for_completion(test, std2);
1033 if (res == AST_TEST_FAIL) {
1034 goto end;
1035 }
1036 res = wait_for_completion(test, std3);
1037 if (res == AST_TEST_FAIL) {
1038 goto end;
1039 }
1040
1041 res = wait_for_empty_notice(test, tld);
1042 if (res == AST_TEST_FAIL) {
1043 goto end;
1044 }
1045
1046 res = wait_until_thread_state(test, tld, 0, 1);
1047 if (res == AST_TEST_FAIL) {
1048 goto end;
1049 }
1050
1051 res = listener_check(test, listener, 1, 0, 3, 0, 1, 1);
1052
1053end:
1059 ast_free(tld);
1060 return res;
1061}

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_push(), ast_threadpool_set_size(), ast_threadpool_shutdown(), end, sip_to_pjsip::info(), listener(), listener_check(), NULL, options, simple_task(), simple_task_data_alloc(), simple_task_data_free(), test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, wait_for_completion(), wait_for_empty_notice(), and wait_until_thread_state().

◆ AST_TEST_DEFINE() [7/16]

AST_TEST_DEFINE ( threadpool_one_thread_one_task  )

Definition at line 872 of file test_threadpool.c.

873{
874 struct ast_threadpool *pool = NULL;
876 struct simple_task_data *std = NULL;
878 struct test_listener_data *tld = NULL;
881 .idle_timeout = 0,
882 .auto_increment = 0,
883 .initial_size = 0,
884 .max_size = 0,
885 };
886
887 switch (cmd) {
888 case TEST_INIT:
889 info->name = "one_thread_one_task";
890 info->category = "/main/threadpool/";
891 info->summary = "Test a single thread with a single task";
892 info->description =
893 "Add a thread to the pool and then push a task to it.";
894 return AST_TEST_NOT_RUN;
895 case TEST_EXECUTE:
896 break;
897 }
898
899 tld = test_alloc();
900 if (!tld) {
901 return AST_TEST_FAIL;
902 }
903
905 if (!listener) {
906 goto end;
907 }
908
910 if (!pool) {
911 goto end;
912 }
913
915 if (!std) {
916 goto end;
917 }
918
920
921 res = wait_until_thread_state(test, tld, 0, 1);
922 if (res == AST_TEST_FAIL) {
923 goto end;
924 }
925
926 if (ast_threadpool_push(pool, simple_task, std)) {
927 res = AST_TEST_FAIL;
928 goto end;
929 }
930
931 res = wait_for_completion(test, std);
932 if (res == AST_TEST_FAIL) {
933 goto end;
934 }
935
936 res = wait_for_empty_notice(test, tld);
937 if (res == AST_TEST_FAIL) {
938 goto end;
939 }
940
941 /* After completing the task, the thread should go idle */
942 res = wait_until_thread_state(test, tld, 0, 1);
943 if (res == AST_TEST_FAIL) {
944 goto end;
945 }
946
947 res = listener_check(test, listener, 1, 1, 1, 0, 1, 1);
948
949end:
953 ast_free(tld);
954 return res;
955}

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_push(), ast_threadpool_set_size(), ast_threadpool_shutdown(), end, sip_to_pjsip::info(), listener(), listener_check(), NULL, options, simple_task(), simple_task_data_alloc(), simple_task_data_free(), test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, wait_for_completion(), wait_for_empty_notice(), and wait_until_thread_state().

◆ AST_TEST_DEFINE() [8/16]

AST_TEST_DEFINE ( threadpool_push  )

Definition at line 290 of file test_threadpool.c.

291{
292 struct ast_threadpool *pool = NULL;
294 struct simple_task_data *std = NULL;
295 struct test_listener_data *tld = NULL;
299 .idle_timeout = 0,
300 .auto_increment = 0,
301 .initial_size = 0,
302 .max_size = 0,
303 };
304
305 switch (cmd) {
306 case TEST_INIT:
307 info->name = "push";
308 info->category = "/main/threadpool/";
309 info->summary = "Test task";
310 info->description =
311 "Basic threadpool test";
312 return AST_TEST_NOT_RUN;
313 case TEST_EXECUTE:
314 break;
315 }
316 tld = test_alloc();
317 if (!tld) {
318 return AST_TEST_FAIL;
319 }
320
322 if (!listener) {
323 goto end;
324 }
325
327 if (!pool) {
328 goto end;
329 }
330
332 if (!std) {
333 goto end;
334 }
335
336 if (ast_threadpool_push(pool, simple_task, std)) {
337 goto end;
338 }
339
341
342 res = listener_check(test, listener, 1, 1, 1, 0, 0, 0);
343
344end:
348 ast_free(tld);
349 return res;
350}
static void wait_for_task_pushed(struct ast_threadpool_listener *listener)

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_push(), ast_threadpool_shutdown(), end, sip_to_pjsip::info(), listener(), listener_check(), NULL, options, simple_task(), simple_task_data_alloc(), simple_task_data_free(), test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, and wait_for_task_pushed().

◆ AST_TEST_DEFINE() [9/16]

AST_TEST_DEFINE ( threadpool_reactivation  )

Definition at line 1298 of file test_threadpool.c.

1299{
1300 struct ast_threadpool *pool = NULL;
1302 struct simple_task_data *std1 = NULL;
1303 struct simple_task_data *std2 = NULL;
1305 struct test_listener_data *tld = NULL;
1308 .idle_timeout = 0,
1309 .auto_increment = 0,
1310 .initial_size = 0,
1311 .max_size = 0,
1312 };
1313
1314 switch (cmd) {
1315 case TEST_INIT:
1316 info->name = "reactivation";
1317 info->category = "/main/threadpool/";
1318 info->summary = "Test that a threadpool reactivates when work is added";
1319 info->description =
1320 "Push a task into a threadpool. Make sure the task executes and the\n"
1321 "thread goes idle. Then push a second task and ensure that the thread\n"
1322 "awakens and executes the second task.";
1323 return AST_TEST_NOT_RUN;
1324 case TEST_EXECUTE:
1325 break;
1326 }
1327
1328 tld = test_alloc();
1329 if (!tld) {
1330 return AST_TEST_FAIL;
1331 }
1332
1334 if (!listener) {
1335 goto end;
1336 }
1337
1338 pool = ast_threadpool_create(info->name, listener, &options);
1339 if (!pool) {
1340 goto end;
1341 }
1342
1343 std1 = simple_task_data_alloc();
1344 std2 = simple_task_data_alloc();
1345 if (!std1 || !std2) {
1346 goto end;
1347 }
1348
1349 if (ast_threadpool_push(pool, simple_task, std1)) {
1350 goto end;
1351 }
1352
1353 ast_threadpool_set_size(pool, 1);
1354
1355 res = wait_for_completion(test, std1);
1356 if (res == AST_TEST_FAIL) {
1357 goto end;
1358 }
1359
1360 res = wait_for_empty_notice(test, tld);
1361 if (res == AST_TEST_FAIL) {
1362 goto end;
1363 }
1364
1365 res = wait_until_thread_state(test, tld, 0, 1);
1366 if (res == AST_TEST_FAIL) {
1367 goto end;
1368 }
1369
1370 res = listener_check(test, listener, 1, 1, 1, 0, 1, 1);
1371 if (res == AST_TEST_FAIL) {
1372 goto end;
1373 }
1374
1375 /* Now make sure the threadpool reactivates when we add a second task */
1376 if (ast_threadpool_push(pool, simple_task, std2)) {
1377 res = AST_TEST_FAIL;
1378 goto end;
1379 }
1380
1381 res = wait_for_completion(test, std2);
1382 if (res == AST_TEST_FAIL) {
1383 goto end;
1384 }
1385
1386 res = wait_for_empty_notice(test, tld);
1387 if (res == AST_TEST_FAIL) {
1388 goto end;
1389 }
1390
1391 res = wait_until_thread_state(test, tld, 0, 1);
1392 if (res == AST_TEST_FAIL) {
1393 goto end;
1394 }
1395
1396 res = listener_check(test, listener, 1, 1, 2, 0, 1, 1);
1397
1398end:
1403 ast_free(tld);
1404 return res;
1405
1406}

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_push(), ast_threadpool_set_size(), ast_threadpool_shutdown(), end, sip_to_pjsip::info(), listener(), listener_check(), NULL, options, simple_task(), simple_task_data_alloc(), simple_task_data_free(), test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, wait_for_completion(), wait_for_empty_notice(), and wait_until_thread_state().

◆ AST_TEST_DEFINE() [10/16]

AST_TEST_DEFINE ( threadpool_serializer  )

Definition at line 1739 of file test_threadpool.c.

1740{
1741 int started = 0;
1742 int finished = 0;
1744 struct ast_threadpool *pool = NULL;
1745 struct ast_taskprocessor *uut = NULL;
1746 struct complex_task_data *data1 = NULL;
1747 struct complex_task_data *data2 = NULL;
1748 struct complex_task_data *data3 = NULL;
1751 .idle_timeout = 0,
1752 .auto_increment = 0,
1753 .initial_size = 2,
1754 .max_size = 0,
1755 };
1756
1757 switch (cmd) {
1758 case TEST_INIT:
1759 info->name = "threadpool_serializer";
1760 info->category = "/main/threadpool/";
1761 info->summary = "Test that serializers";
1762 info->description =
1763 "Ensures that tasks enqueued to a serialize execute in sequence.";
1764 return AST_TEST_NOT_RUN;
1765 case TEST_EXECUTE:
1766 break;
1767 }
1768
1769 pool = ast_threadpool_create("threadpool_serializer", NULL, &options);
1770 if (!pool) {
1771 ast_test_status_update(test, "Could not create threadpool\n");
1772 goto end;
1773 }
1774 uut = ast_threadpool_serializer("ser1", pool);
1775 data1 = complex_task_data_alloc();
1776 data2 = complex_task_data_alloc();
1777 data3 = complex_task_data_alloc();
1778 if (!uut || !data1 || !data2 || !data3) {
1779 ast_test_status_update(test, "Allocation failed\n");
1780 goto end;
1781 }
1782
1783 /* This should start right away */
1784 if (ast_taskprocessor_push(uut, complex_task, data1)) {
1785 ast_test_status_update(test, "Failed to enqueue data1\n");
1786 goto end;
1787 }
1788 started = wait_for_complex_start(data1);
1789 if (!started) {
1790 ast_test_status_update(test, "Failed to start data1\n");
1791 goto end;
1792 }
1793
1794 /* This should not start until data 1 is complete */
1795 if (ast_taskprocessor_push(uut, complex_task, data2)) {
1796 ast_test_status_update(test, "Failed to enqueue data2\n");
1797 goto end;
1798 }
1799 started = has_complex_started(data2);
1800 if (started) {
1801 ast_test_status_update(test, "data2 started out of order\n");
1802 goto end;
1803 }
1804
1805 /* But the free thread in the pool can still run */
1806 if (ast_threadpool_push(pool, complex_task, data3)) {
1807 ast_test_status_update(test, "Failed to enqueue data3\n");
1808 }
1809 started = wait_for_complex_start(data3);
1810 if (!started) {
1811 ast_test_status_update(test, "Failed to start data3\n");
1812 goto end;
1813 }
1814
1815 /* Finishing data1 should allow data2 to start */
1816 poke_worker(data1);
1817 finished = wait_for_complex_completion(data1) == AST_TEST_PASS;
1818 if (!finished) {
1819 ast_test_status_update(test, "data1 couldn't finish\n");
1820 goto end;
1821 }
1822 started = wait_for_complex_start(data2);
1823 if (!started) {
1824 ast_test_status_update(test, "Failed to start data2\n");
1825 goto end;
1826 }
1827
1828 /* Finish up */
1829 poke_worker(data2);
1830 finished = wait_for_complex_completion(data2) == AST_TEST_PASS;
1831 if (!finished) {
1832 ast_test_status_update(test, "data2 couldn't finish\n");
1833 goto end;
1834 }
1835 poke_worker(data3);
1836 finished = wait_for_complex_completion(data3) == AST_TEST_PASS;
1837 if (!finished) {
1838 ast_test_status_update(test, "data3 couldn't finish\n");
1839 goto end;
1840 }
1841
1842 res = AST_TEST_PASS;
1843
1844end:
1845 poke_worker(data1);
1846 poke_worker(data2);
1847 poke_worker(data3);
1853 return res;
1854}
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
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.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
@ AST_TEST_PASS
Definition: test.h:195
static int has_complex_started(struct complex_task_data *ctd)
static int wait_for_complex_start(struct complex_task_data *ctd)
struct ast_taskprocessor * ast_threadpool_serializer(const char *name, struct ast_threadpool *pool)
Serialized execution of tasks within a ast_threadpool.
Definition: threadpool.c:1331

References ast_taskprocessor_push(), ast_taskprocessor_unreference(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_threadpool_create(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_push(), ast_threadpool_serializer(), ast_threadpool_shutdown(), complex_task(), complex_task_data_alloc(), complex_task_data_free(), end, has_complex_started(), sip_to_pjsip::info(), NULL, options, poke_worker(), TEST_EXECUTE, TEST_INIT, wait_for_complex_completion(), and wait_for_complex_start().

◆ AST_TEST_DEFINE() [11/16]

AST_TEST_DEFINE ( threadpool_serializer_dupe  )

Definition at line 1997 of file test_threadpool.c.

1998{
2000 struct ast_threadpool *pool = NULL;
2001 struct ast_taskprocessor *uut = NULL;
2002 struct ast_taskprocessor *there_can_be_only_one = NULL;
2005 .idle_timeout = 0,
2006 .auto_increment = 0,
2007 .initial_size = 2,
2008 .max_size = 0,
2009 };
2010
2011 switch (cmd) {
2012 case TEST_INIT:
2013 info->name = "threadpool_serializer_dupe";
2014 info->category = "/main/threadpool/";
2015 info->summary = "Test that serializers are uniquely named";
2016 info->description =
2017 "Creating two serializers with the same name should\n"
2018 "result in error.";
2019 return AST_TEST_NOT_RUN;
2020 case TEST_EXECUTE:
2021 break;
2022 }
2023
2024 pool = ast_threadpool_create("threadpool_serializer", NULL, &options);
2025 if (!pool) {
2026 ast_test_status_update(test, "Could not create threadpool\n");
2027 goto end;
2028 }
2029
2030 uut = ast_threadpool_serializer("highlander", pool);
2031 if (!uut) {
2032 ast_test_status_update(test, "Allocation failed\n");
2033 goto end;
2034 }
2035
2036 there_can_be_only_one = ast_threadpool_serializer("highlander", pool);
2037 if (there_can_be_only_one) {
2038 ast_taskprocessor_unreference(there_can_be_only_one);
2039 ast_test_status_update(test, "Duplicate name error\n");
2040 goto end;
2041 }
2042
2043 res = AST_TEST_PASS;
2044
2045end:
2048 return res;
2049}

References ast_taskprocessor_unreference(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_threadpool_create(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_serializer(), ast_threadpool_shutdown(), end, sip_to_pjsip::info(), NULL, options, TEST_EXECUTE, and TEST_INIT.

◆ AST_TEST_DEFINE() [12/16]

AST_TEST_DEFINE ( threadpool_task_distribution  )

Definition at line 1524 of file test_threadpool.c.

1525{
1526 struct ast_threadpool *pool = NULL;
1528 struct complex_task_data *ctd1 = NULL;
1529 struct complex_task_data *ctd2 = NULL;
1531 struct test_listener_data *tld = NULL;
1534 .idle_timeout = 0,
1535 .auto_increment = 0,
1536 .initial_size = 0,
1537 .max_size = 0,
1538 };
1539
1540 switch (cmd) {
1541 case TEST_INIT:
1542 info->name = "task_distribution";
1543 info->category = "/main/threadpool/";
1544 info->summary = "Test that tasks are evenly distributed to threads";
1545 info->description =
1546 "Push two tasks into a threadpool. Ensure that each is handled by\n"
1547 "a separate thread";
1548 return AST_TEST_NOT_RUN;
1549 case TEST_EXECUTE:
1550 break;
1551 }
1552
1553 tld = test_alloc();
1554 if (!tld) {
1555 return AST_TEST_FAIL;
1556 }
1557
1559 if (!listener) {
1560 goto end;
1561 }
1562
1563 pool = ast_threadpool_create(info->name, listener, &options);
1564 if (!pool) {
1565 goto end;
1566 }
1567
1568 ctd1 = complex_task_data_alloc();
1569 ctd2 = complex_task_data_alloc();
1570 if (!ctd1 || !ctd2) {
1571 goto end;
1572 }
1573
1574 if (ast_threadpool_push(pool, complex_task, ctd1)) {
1575 goto end;
1576 }
1577
1578 if (ast_threadpool_push(pool, complex_task, ctd2)) {
1579 goto end;
1580 }
1581
1582 ast_threadpool_set_size(pool, 2);
1583
1584 res = wait_until_thread_state(test, tld, 2, 0);
1585 if (res == AST_TEST_FAIL) {
1586 goto end;
1587 }
1588
1589 res = listener_check(test, listener, 1, 0, 2, 2, 0, 0);
1590 if (res == AST_TEST_FAIL) {
1591 goto end;
1592 }
1593
1594 /* The tasks are stalled until we poke them */
1595 poke_worker(ctd1);
1596 poke_worker(ctd2);
1597
1598 res = wait_for_complex_completion(ctd1);
1599 if (res == AST_TEST_FAIL) {
1600 goto end;
1601 }
1602 res = wait_for_complex_completion(ctd2);
1603 if (res == AST_TEST_FAIL) {
1604 goto end;
1605 }
1606
1607 res = wait_until_thread_state(test, tld, 0, 2);
1608 if (res == AST_TEST_FAIL) {
1609 goto end;
1610 }
1611
1612 res = listener_check(test, listener, 1, 0, 2, 0, 2, 1);
1613
1614end:
1619 ast_free(tld);
1620 return res;
1621}

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_push(), ast_threadpool_set_size(), ast_threadpool_shutdown(), complex_task(), complex_task_data_alloc(), complex_task_data_free(), end, sip_to_pjsip::info(), listener(), listener_check(), NULL, options, poke_worker(), test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, wait_for_complex_completion(), and wait_until_thread_state().

◆ AST_TEST_DEFINE() [13/16]

AST_TEST_DEFINE ( threadpool_thread_creation  )

Definition at line 511 of file test_threadpool.c.

512{
513 struct ast_threadpool *pool = NULL;
516 struct test_listener_data *tld = NULL;
519 .idle_timeout = 0,
520 .auto_increment = 0,
521 .initial_size = 0,
522 .max_size = 0,
523 };
524
525 switch (cmd) {
526 case TEST_INIT:
527 info->name = "thread_creation";
528 info->category = "/main/threadpool/";
529 info->summary = "Test threadpool thread creation";
530 info->description =
531 "Ensure that threads can be added to a threadpool";
532 return AST_TEST_NOT_RUN;
533 case TEST_EXECUTE:
534 break;
535 }
536
537 tld = test_alloc();
538 if (!tld) {
539 return AST_TEST_FAIL;
540 }
541
543 if (!listener) {
544 goto end;
545 }
546
548 if (!pool) {
549 goto end;
550 }
551
552 /* Now let's create a thread. It should start active, then go
553 * idle immediately
554 */
556
557 res = wait_until_thread_state(test, tld, 0, 1);
558
559end:
562 ast_free(tld);
563 return res;
564}

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_set_size(), ast_threadpool_shutdown(), end, sip_to_pjsip::info(), listener(), NULL, options, test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, and wait_until_thread_state().

◆ AST_TEST_DEFINE() [14/16]

AST_TEST_DEFINE ( threadpool_thread_destruction  )

Definition at line 566 of file test_threadpool.c.

567{
568 struct ast_threadpool *pool = NULL;
571 struct test_listener_data *tld = NULL;
574 .idle_timeout = 0,
575 .auto_increment = 0,
576 .initial_size = 0,
577 .max_size = 0,
578 };
579
580 switch (cmd) {
581 case TEST_INIT:
582 info->name = "thread_destruction";
583 info->category = "/main/threadpool/";
584 info->summary = "Test threadpool thread destruction";
585 info->description =
586 "Ensure that threads are properly destroyed in a threadpool";
587 return AST_TEST_NOT_RUN;
588 case TEST_EXECUTE:
589 break;
590 }
591
592 tld = test_alloc();
593 if (!tld) {
594 return AST_TEST_FAIL;
595 }
596
598 if (!listener) {
599 goto end;
600 }
601
603 if (!pool) {
604 goto end;
605 }
606
608
609 res = wait_until_thread_state(test, tld, 0, 3);
610 if (res == AST_TEST_FAIL) {
611 goto end;
612 }
613
614 res = listener_check(test, listener, 0, 0, 0, 0, 3, 0);
615 if (res == AST_TEST_FAIL) {
616 goto end;
617 }
618
620
621 res = wait_until_thread_state(test, tld, 0, 2);
622
623end:
626 ast_free(tld);
627 return res;
628}

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_set_size(), ast_threadpool_shutdown(), end, sip_to_pjsip::info(), listener(), listener_check(), NULL, options, test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, and wait_until_thread_state().

◆ AST_TEST_DEFINE() [15/16]

AST_TEST_DEFINE ( threadpool_thread_timeout  )

Definition at line 630 of file test_threadpool.c.

631{
632 struct ast_threadpool *pool = NULL;
635 struct test_listener_data *tld = NULL;
638 .idle_timeout = 2,
639 .auto_increment = 0,
640 .initial_size = 0,
641 .max_size = 0,
642 };
643
644 switch (cmd) {
645 case TEST_INIT:
646 info->name = "thread_timeout";
647 info->category = "/main/threadpool/";
648 info->summary = "Test threadpool thread timeout";
649 info->description =
650 "Ensure that a thread with a two second timeout dies as expected.";
651 return AST_TEST_NOT_RUN;
652 case TEST_EXECUTE:
653 break;
654 }
655
656 tld = test_alloc();
657 if (!tld) {
658 return AST_TEST_FAIL;
659 }
660
662 if (!listener) {
663 goto end;
664 }
665
667 if (!pool) {
668 goto end;
669 }
670
672
673 res = wait_until_thread_state(test, tld, 0, 1);
674 if (res == AST_TEST_FAIL) {
675 goto end;
676 }
677
678 res = listener_check(test, listener, 0, 0, 0, 0, 1, 0);
679 if (res == AST_TEST_FAIL) {
680 goto end;
681 }
682
683 res = wait_until_thread_state(test, tld, 0, 0);
684 if (res == AST_TEST_FAIL) {
685 goto end;
686 }
687
688 res = listener_check(test, listener, 0, 0, 0, 0, 0, 0);
689
690end:
693 ast_free(tld);
694 return res;
695}

References ao2_cleanup, ast_free, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_set_size(), ast_threadpool_shutdown(), end, sip_to_pjsip::info(), listener(), listener_check(), NULL, options, test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, and wait_until_thread_state().

◆ AST_TEST_DEFINE() [16/16]

AST_TEST_DEFINE ( threadpool_thread_timeout_thrash  )

Definition at line 697 of file test_threadpool.c.

698{
699 struct ast_threadpool *pool = NULL;
702 struct test_listener_data *tld = NULL;
705 .idle_timeout = 1,
706 .auto_increment = 1,
707 .initial_size = 0,
708 .max_size = 1,
709 };
710 int iteration;
711
712 switch (cmd) {
713 case TEST_INIT:
714 info->name = "thread_timeout_thrash";
715 info->category = "/main/threadpool/";
716 info->summary = "Thrash threadpool thread timeout";
717 info->description =
718 "Repeatedly queue a task when a threadpool thread should timeout.";
719 return AST_TEST_NOT_RUN;
720 case TEST_EXECUTE:
721 break;
722 }
723
724 tld = test_alloc();
725 if (!tld) {
726 return AST_TEST_FAIL;
727 }
728
730 if (!listener) {
731 goto end;
732 }
733
735 if (!pool) {
736 goto end;
737 }
738
740
741 for (iteration = 0; iteration < 30; ++iteration) {
742 struct simple_task_data *std = NULL;
743 struct timeval start = ast_tvnow();
744 struct timespec end = {
745 .tv_sec = start.tv_sec + options.idle_timeout,
746 .tv_nsec = start.tv_usec * 1000
747 };
748
750 if (!std) {
751 goto end;
752 }
753
754 /* Wait until the threadpool thread should timeout due to being idle */
755 ast_mutex_lock(&tld->lock);
756 while (ast_cond_timedwait(&tld->cond, &tld->lock, &end) != ETIMEDOUT) {
757 /* This purposely left empty as we want to loop waiting for a time out */
758 }
759 ast_mutex_unlock(&tld->lock);
760
761 if (ast_threadpool_push(pool, simple_task, std)) {
762 res = AST_TEST_FAIL;
763 } else {
764 res = wait_for_completion(test, std);
765 }
766
768
769 if (res == AST_TEST_FAIL) {
770 goto end;
771 }
772 }
773
774 res = wait_until_thread_state(test, tld, 0, 0);
775 if (res == AST_TEST_FAIL) {
776 goto end;
777 }
778
779 res = listener_check(test, listener, 1, 1, 30, 0, 0, 1);
780
781end:
784 ast_free(tld);
785 return res;
786}
#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
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References ao2_cleanup, ast_cond_timedwait, ast_free, ast_mutex_lock, ast_mutex_unlock, AST_TEST_FAIL, AST_TEST_NOT_RUN, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_push(), ast_threadpool_set_size(), ast_threadpool_shutdown(), ast_tvnow(), test_listener_data::cond, end, sip_to_pjsip::info(), listener(), listener_check(), test_listener_data::lock, NULL, options, simple_task(), simple_task_data_alloc(), simple_task_data_free(), test_alloc(), test_callbacks, TEST_EXECUTE, TEST_INIT, wait_for_completion(), and wait_until_thread_state().

◆ complex_task()

static int complex_task ( void *  data)
static

Definition at line 1443 of file test_threadpool.c.

1444{
1445 struct complex_task_data *ctd = data;
1446 SCOPED_MUTEX(lock, &ctd->lock);
1447 /* Notify that we started */
1448 ctd->task_started = 1;
1450 while (!ctd->continue_task) {
1452 }
1453 /* We got poked. Finish up */
1454 ctd->task_executed = 1;
1456 return 0;
1457}
ast_mutex_t lock
Definition: app_sla.c:337
#define ast_cond_wait(cond, mutex)
Definition: lock.h:212
#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_cond_wait, complex_task_data::continue_task, lock, complex_task_data::lock, complex_task_data::notify_cond, SCOPED_MUTEX, complex_task_data::stall_cond, complex_task_data::task_executed, and complex_task_data::task_started.

Referenced by AST_TEST_DEFINE().

◆ complex_task_data_alloc()

static struct complex_task_data * complex_task_data_alloc ( void  )
static

Definition at line 1417 of file test_threadpool.c.

1418{
1419 struct complex_task_data *ctd = ast_calloc(1, sizeof(*ctd));
1420
1421 if (!ctd) {
1422 return NULL;
1423 }
1424 ast_mutex_init(&ctd->lock);
1427 return ctd;
1428}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_cond_init(cond, attr)
Definition: lock.h:208
#define ast_mutex_init(pmutex)
Definition: lock.h:193

References ast_calloc, ast_cond_init, ast_mutex_init, complex_task_data::lock, complex_task_data::notify_cond, NULL, and complex_task_data::stall_cond.

Referenced by AST_TEST_DEFINE().

◆ complex_task_data_free()

static void complex_task_data_free ( struct complex_task_data ctd)
static

Definition at line 1430 of file test_threadpool.c.

1431{
1432 if (!ctd) {
1433 return;
1434 }
1435
1436 ast_mutex_destroy(&ctd->lock);
1439
1440 ast_free(ctd);
1441}
#define ast_cond_destroy(cond)
Definition: lock.h:209
#define ast_mutex_destroy(a)
Definition: lock.h:195

References ast_cond_destroy, ast_free, ast_mutex_destroy, complex_task_data::lock, complex_task_data::notify_cond, and complex_task_data::stall_cond.

Referenced by AST_TEST_DEFINE().

◆ efficiency_task()

static int efficiency_task ( void *  data)
static

Definition at line 358 of file test_threadpool.c.

359{
360 struct efficiency_task_data *etd = data;
361
362 if (etd->shutdown) {
363 return 0;
364 }
365
367
368 if (ast_threadpool_push(etd->pool, efficiency_task, etd)) {
369 return -1;
370 }
371
372 return 0;
373}
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 ast_atomic_fetchadd_int(), ast_threadpool_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_threadpool_push_efficiency().

◆ handle_cli_threadpool_push_efficiency()

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

Definition at line 375 of file test_threadpool.c.

376{
377 struct ast_threadpool *pool = NULL;
379 struct test_listener_data *tld = NULL;
383 .idle_timeout = 0,
384 .auto_increment = 0,
385 .initial_size = 5,
386 .max_size = 5,
387 };
388 struct efficiency_task_data etd = {
389 .pool = NULL,
390 .num_tasks_executed = 0,
391 .shutdown = 0,
392 };
393 struct timeval start;
394 struct timespec end;
395 int i;
396
397 switch (cmd) {
398 case CLI_INIT:
399 e->command = "threadpool push efficiency";
400 e->usage =
401 "Usage: threadpool push efficiency\n"
402 " Pushes 200 tasks to a threadpool and measures\n"
403 " the number of tasks executed within 30 seconds.\n";
404 return NULL;
405 case CLI_GENERATE:
406 return NULL;
407 }
408
409 tld = test_alloc();
410 if (!tld) {
411 return CLI_SUCCESS;
412 }
413
415 if (!listener) {
416 goto end;
417 }
418
419 pool = ast_threadpool_create("threadpool_push_efficiency", listener, &options);
420 if (!pool) {
421 goto end;
422 }
423
424 etd.pool = pool;
425
426 /* Push in 200 tasks, cause why not */
427 for (i = 0; i < 200; i++) {
428 if (ast_threadpool_push(pool, efficiency_task, &etd)) {
429 goto end;
430 }
431 }
432
433 /* Wait for 30 seconds */
434 start = ast_tvnow();
435 end.tv_sec = start.tv_sec + 30;
436 end.tv_nsec = start.tv_usec * 1000;
437
438 ast_mutex_lock(&tld->lock);
439 while (ast_cond_timedwait(&tld->cond, &tld->lock, &end) != ETIMEDOUT) {
440 }
441 ast_mutex_unlock(&tld->lock);
442
443 /* Give the total tasks executed, and tell each task to not requeue */
444 ast_cli(a->fd, "Total tasks executed in 30 seconds: %d\n", etd.num_tasks_executed);
445 etd.shutdown = 1;
446
447 res = wait_for_empty_notice(NULL, tld);
448 if (res == AST_TEST_FAIL) {
449 goto end;
450 }
451
452end:
455 ast_free(tld);
456 return CLI_SUCCESS;
457}
#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_cleanup, ast_cli(), ast_cond_timedwait, ast_free, ast_mutex_lock, ast_mutex_unlock, AST_TEST_FAIL, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_push(), ast_threadpool_shutdown(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, test_listener_data::cond, efficiency_task(), end, listener(), test_listener_data::lock, NULL, efficiency_task_data::num_tasks_executed, options, efficiency_task_data::pool, efficiency_task_data::shutdown, test_alloc(), test_callbacks, ast_cli_entry::usage, and wait_for_empty_notice().

◆ handle_cli_threadpool_push_serializer_efficiency()

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

Definition at line 1889 of file test_threadpool.c.

1891{
1892 struct ast_threadpool *pool = NULL;
1894 struct test_listener_data *tld = NULL;
1898 .idle_timeout = 0,
1899 .auto_increment = 0,
1900 .initial_size = 5,
1901 .max_size = 5,
1902 };
1903 struct serializer_efficiency_task_data etd[200];
1904 struct timeval start;
1905 struct timespec end;
1906 int i;
1907 int num_tasks_executed = 0;
1908 int shutdown = 0;
1909
1910 switch (cmd) {
1911 case CLI_INIT:
1912 e->command = "threadpool push serializer efficiency";
1913 e->usage =
1914 "Usage: threadpool push serializer efficiency\n"
1915 " Pushes 200 tasks to a threadpool in serializers and measures\n"
1916 " the number of tasks executed within 30 seconds.\n";
1917 return NULL;
1918 case CLI_GENERATE:
1919 return NULL;
1920 }
1921
1922 tld = test_alloc();
1923 if (!tld) {
1924 return CLI_SUCCESS;
1925 }
1926
1927 memset(&etd, 0, sizeof(etd));
1928
1930 if (!listener) {
1931 goto end;
1932 }
1933
1934 pool = ast_threadpool_create("threadpool_push_serializer_efficiency", listener, &options);
1935 if (!pool) {
1936 goto end;
1937 }
1938
1939 /* We create 400 (200 pairs) of serializers */
1940 for (i = 0; i < 200; i++) {
1941 char serializer_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1942
1943 ast_taskprocessor_build_name(serializer_name, sizeof(serializer_name), "serializer%d", i);
1944 etd[i].serializer[0] = ast_threadpool_serializer(serializer_name, pool);
1945 if (!etd[i].serializer[0]) {
1946 goto end;
1947 }
1948
1949 ast_taskprocessor_build_name(serializer_name, sizeof(serializer_name), "serializer%d", i);
1950 etd[i].serializer[1] = ast_threadpool_serializer(serializer_name, pool);
1951 if (!etd[i].serializer[1]) {
1952 goto end;
1953 }
1954
1955 etd[i].num_tasks_executed = &num_tasks_executed;
1956 etd[i].shutdown = &shutdown;
1957 }
1958
1959 /* And once created we push in 200 tasks */
1960 for (i = 0; i < 200; i++) {
1962 goto end;
1963 }
1964 }
1965
1966 /* Wait for 30 seconds */
1967 start = ast_tvnow();
1968 end.tv_sec = start.tv_sec + 30;
1969 end.tv_nsec = start.tv_usec * 1000;
1970
1971 ast_mutex_lock(&tld->lock);
1972 while (ast_cond_timedwait(&tld->cond, &tld->lock, &end) != ETIMEDOUT) {
1973 }
1974 ast_mutex_unlock(&tld->lock);
1975
1976 /* Give the total tasks executed, and tell each task to not requeue */
1977 ast_cli(a->fd, "Total tasks executed in 30 seconds: %d\n", num_tasks_executed);
1978 shutdown = 1;
1979
1980 res = wait_for_empty_notice(NULL, tld);
1981 if (res == AST_TEST_FAIL) {
1982 goto end;
1983 }
1984
1985end:
1986 /* We need to unreference each serializer */
1987 for (i = 0; i < 200; i++) {
1990 }
1993 ast_free(tld);
1994 return CLI_SUCCESS;
1995}
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
static int serializer_efficiency_task(void *data)

References a, ao2_cleanup, ast_cli(), ast_cond_timedwait, ast_free, ast_mutex_lock, ast_mutex_unlock, ast_taskprocessor_build_name(), AST_TASKPROCESSOR_MAX_NAME, ast_taskprocessor_push(), ast_taskprocessor_unreference(), AST_TEST_FAIL, ast_threadpool_create(), ast_threadpool_listener_alloc(), AST_THREADPOOL_OPTIONS_VERSION, ast_threadpool_serializer(), ast_threadpool_shutdown(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, test_listener_data::cond, end, listener(), test_listener_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_callbacks, ast_cli_entry::usage, and wait_for_empty_notice().

◆ has_complex_started()

static int has_complex_started ( struct complex_task_data ctd)
static

Definition at line 1484 of file test_threadpool.c.

1485{
1486 struct timeval start = ast_tvnow();
1487 struct timespec end = {
1488 .tv_sec = start.tv_sec + 1,
1489 .tv_nsec = start.tv_usec * 1000
1490 };
1491 SCOPED_MUTEX(lock, &ctd->lock);
1492
1493 while (!ctd->task_started) {
1494 if (ast_cond_timedwait(&ctd->notify_cond, lock, &end) == ETIMEDOUT) {
1495 break;
1496 }
1497 }
1498
1499 return ctd->task_started;
1500}

References ast_cond_timedwait, ast_tvnow(), end, lock, complex_task_data::lock, complex_task_data::notify_cond, SCOPED_MUTEX, and complex_task_data::task_started.

Referenced by AST_TEST_DEFINE().

◆ listener_check()

static enum ast_test_result_state listener_check ( struct ast_test *  test,
struct ast_threadpool_listener listener,
int  task_pushed,
int  was_empty,
int  num_tasks,
int  num_active,
int  num_idle,
int  empty_notice 
)
static

Definition at line 243 of file test_threadpool.c.

252{
255
256 if (tld->task_pushed != task_pushed) {
257 ast_test_status_update(test, "Expected task %sto be pushed, but it was%s\n",
258 task_pushed ? "" : "not ", tld->task_pushed ? "" : " not");
259 res = AST_TEST_FAIL;
260 }
261 if (tld->was_empty != was_empty) {
262 ast_test_status_update(test, "Expected %sto be empty, but it was%s\n",
263 was_empty ? "" : "not ", tld->was_empty ? "" : " not");
264 res = AST_TEST_FAIL;
265 }
266 if (tld->num_tasks!= num_tasks) {
267 ast_test_status_update(test, "Expected %d tasks to be pushed, but got %d\n",
268 num_tasks, tld->num_tasks);
269 res = AST_TEST_FAIL;
270 }
271 if (tld->num_active != num_active) {
272 ast_test_status_update(test, "Expected %d active threads, but got %d\n",
273 num_active, tld->num_active);
274 res = AST_TEST_FAIL;
275 }
276 if (tld->num_idle != num_idle) {
277 ast_test_status_update(test, "Expected %d idle threads, but got %d\n",
278 num_idle, tld->num_idle);
279 res = AST_TEST_FAIL;
280 }
281 if (tld->empty_notice != empty_notice) {
282 ast_test_status_update(test, "Expected %s empty notice, but got %s\n",
283 was_empty ? "an" : "no", tld->task_pushed ? "one" : "none");
284 res = AST_TEST_FAIL;
285 }
286
287 return res;
288}
void * ast_threadpool_listener_get_user_data(const struct ast_threadpool_listener *listener)
Get the threadpool listener's user data.
Definition: threadpool.c:906

References AST_TEST_FAIL, AST_TEST_PASS, ast_test_status_update, ast_threadpool_listener_get_user_data(), test_listener_data::empty_notice, listener(), test_listener_data::num_active, test_listener_data::num_idle, test_listener_data::num_tasks, test_listener_data::task_pushed, and test_listener_data::was_empty.

Referenced by AST_TEST_DEFINE().

◆ load_module()

static int load_module ( void  )
static

Definition at line 2078 of file test_threadpool.c.

2079{
2081 ast_test_register(threadpool_push);
2082 ast_test_register(threadpool_initial_threads);
2083 ast_test_register(threadpool_thread_creation);
2084 ast_test_register(threadpool_thread_destruction);
2085 ast_test_register(threadpool_thread_timeout);
2086 ast_test_register(threadpool_thread_timeout_thrash);
2087 ast_test_register(threadpool_one_task_one_thread);
2088 ast_test_register(threadpool_one_thread_one_task);
2089 ast_test_register(threadpool_one_thread_multiple_tasks);
2090 ast_test_register(threadpool_auto_increment);
2091 ast_test_register(threadpool_max_size);
2092 ast_test_register(threadpool_reactivation);
2093 ast_test_register(threadpool_task_distribution);
2094 ast_test_register(threadpool_more_destruction);
2095 ast_test_register(threadpool_serializer);
2096 ast_test_register(threadpool_serializer_dupe);
2098}
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
static struct ast_cli_entry cli[]
#define ARRAY_LEN(a)
Definition: utils.h:703

References ARRAY_LEN, ast_cli_register_multiple, AST_MODULE_LOAD_SUCCESS, and cli.

◆ poke_worker()

static void poke_worker ( struct complex_task_data ctd)
static

◆ serializer_efficiency_task()

static int serializer_efficiency_task ( void *  data)
static

Definition at line 1862 of file test_threadpool.c.

1863{
1864 struct serializer_efficiency_task_data *etd = data;
1865 struct ast_taskprocessor *taskprocessor = etd->serializer[0];
1866
1867 if (*etd->shutdown) {
1868 return 0;
1869 }
1870
1872
1873 /* We ping pong a task between a pair of taskprocessors to ensure that
1874 * a single taskprocessor does not receive a thread from the threadpool
1875 * exclusively.
1876 */
1877 if (taskprocessor == ast_threadpool_serializer_get_current()) {
1878 taskprocessor = etd->serializer[1];
1879 }
1880
1881 if (ast_taskprocessor_push(taskprocessor,
1883 return -1;
1884 }
1885
1886 return 0;
1887}
struct ast_taskprocessor * serializer[2]
struct ast_taskprocessor * ast_threadpool_serializer_get_current(void)
Get the threadpool serializer currently associated with this thread.
Definition: threadpool.c:1296

References ast_atomic_fetchadd_int(), ast_taskprocessor_push(), ast_threadpool_serializer_get_current(), 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_threadpool_push_serializer_efficiency(), and serializer_efficiency_task().

◆ simple_task()

static int simple_task ( void *  data)
static

Definition at line 142 of file test_threadpool.c.

143{
144 struct simple_task_data *std = data;
145 SCOPED_MUTEX(lock, &std->lock);
146 std->task_executed = 1;
147 ast_cond_signal(&std->cond);
148 return 0;
149}

References ast_cond_signal, simple_task_data::cond, lock, simple_task_data::lock, SCOPED_MUTEX, and simple_task_data::task_executed.

Referenced by AST_TEST_DEFINE().

◆ simple_task_data_alloc()

static struct simple_task_data * simple_task_data_alloc ( void  )
static

Definition at line 118 of file test_threadpool.c.

119{
120 struct simple_task_data *std = ast_calloc(1, sizeof(*std));
121
122 if (!std) {
123 return NULL;
124 }
125 ast_mutex_init(&std->lock);
126 ast_cond_init(&std->cond, NULL);
127 return std;
128}

References ast_calloc, ast_cond_init, ast_mutex_init, simple_task_data::cond, simple_task_data::lock, and NULL.

Referenced by AST_TEST_DEFINE().

◆ simple_task_data_free()

static void simple_task_data_free ( struct simple_task_data std)
static

Definition at line 130 of file test_threadpool.c.

131{
132 if (!std) {
133 return;
134 }
135
136 ast_mutex_destroy(&std->lock);
137 ast_cond_destroy(&std->cond);
138
139 ast_free(std);
140}

References ast_cond_destroy, ast_free, ast_mutex_destroy, simple_task_data::cond, and simple_task_data::lock.

Referenced by AST_TEST_DEFINE().

◆ test_alloc()

static struct test_listener_data * test_alloc ( void  )
static

Definition at line 53 of file test_threadpool.c.

54{
55 struct test_listener_data *tld = ast_calloc(1, sizeof(*tld));
56 if (!tld) {
57 return NULL;
58 }
59 ast_mutex_init(&tld->lock);
60 ast_cond_init(&tld->cond, NULL);
61 return tld;
62}

References ast_calloc, ast_cond_init, ast_mutex_init, test_listener_data::cond, test_listener_data::lock, and NULL.

Referenced by AST_TEST_DEFINE(), handle_cli_threadpool_push_efficiency(), and handle_cli_threadpool_push_serializer_efficiency().

◆ test_emptied()

static void test_emptied ( struct ast_threadpool pool,
struct ast_threadpool_listener listener 
)
static

◆ test_shutdown()

static void test_shutdown ( struct ast_threadpool_listener listener)
static

◆ test_state_changed()

static void test_state_changed ( struct ast_threadpool pool,
struct ast_threadpool_listener listener,
int  active_threads,
int  idle_threads 
)
static

Definition at line 64 of file test_threadpool.c.

68{
70 SCOPED_MUTEX(lock, &tld->lock);
71 tld->num_active = active_threads;
72 tld->num_idle = idle_threads;
73 ast_log(LOG_NOTICE, "Thread state: %d active, %d idle\n", tld->num_active, tld->num_idle);
74 ast_cond_signal(&tld->cond);
75}
#define ast_log
Definition: astobj2.c:42
#define LOG_NOTICE

References ast_cond_signal, ast_log, ast_threadpool_listener_get_user_data(), test_listener_data::cond, listener(), lock, test_listener_data::lock, LOG_NOTICE, test_listener_data::num_active, test_listener_data::num_idle, and SCOPED_MUTEX.

◆ test_task_pushed()

static void test_task_pushed ( struct ast_threadpool pool,
struct ast_threadpool_listener listener,
int  was_empty 
)
static

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 2056 of file test_threadpool.c.

2057{
2058 ast_test_unregister(threadpool_push);
2059 ast_test_unregister(threadpool_initial_threads);
2060 ast_test_unregister(threadpool_thread_creation);
2061 ast_test_unregister(threadpool_thread_destruction);
2062 ast_test_unregister(threadpool_thread_timeout);
2063 ast_test_unregister(threadpool_thread_timeout_thrash);
2064 ast_test_unregister(threadpool_one_task_one_thread);
2065 ast_test_unregister(threadpool_one_thread_one_task);
2066 ast_test_unregister(threadpool_one_thread_multiple_tasks);
2067 ast_test_unregister(threadpool_auto_increment);
2068 ast_test_unregister(threadpool_max_size);
2069 ast_test_unregister(threadpool_reactivation);
2070 ast_test_unregister(threadpool_task_distribution);
2071 ast_test_unregister(threadpool_more_destruction);
2072 ast_test_unregister(threadpool_serializer);
2073 ast_test_unregister(threadpool_serializer_dupe);
2075 return 0;
2076}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30

References ARRAY_LEN, ast_cli_unregister_multiple(), and cli.

◆ wait_for_completion()

static enum ast_test_result_state wait_for_completion ( struct ast_test *  test,
struct simple_task_data std 
)
static

Definition at line 194 of file test_threadpool.c.

195{
196 struct timeval start = ast_tvnow();
197 struct timespec end = {
198 .tv_sec = start.tv_sec + 5,
199 .tv_nsec = start.tv_usec * 1000
200 };
202 SCOPED_MUTEX(lock, &std->lock);
203
204 while (!std->task_executed) {
205 if (ast_cond_timedwait(&std->cond, lock, &end) == ETIMEDOUT) {
206 break;
207 }
208 }
209
210 if (!std->task_executed) {
211 ast_test_status_update(test, "Task execution did not occur\n");
212 res = AST_TEST_FAIL;
213 }
214 return res;
215}

References ast_cond_timedwait, AST_TEST_FAIL, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), simple_task_data::cond, end, lock, simple_task_data::lock, SCOPED_MUTEX, and simple_task_data::task_executed.

Referenced by AST_TEST_DEFINE().

◆ wait_for_complex_completion()

static enum ast_test_result_state wait_for_complex_completion ( struct complex_task_data ctd)
static

Definition at line 1502 of file test_threadpool.c.

1503{
1504 struct timeval start = ast_tvnow();
1505 struct timespec end = {
1506 .tv_sec = start.tv_sec + 5,
1507 .tv_nsec = start.tv_usec * 1000
1508 };
1510 SCOPED_MUTEX(lock, &ctd->lock);
1511
1512 while (!ctd->task_executed) {
1513 if (ast_cond_timedwait(&ctd->notify_cond, lock, &end) == ETIMEDOUT) {
1514 break;
1515 }
1516 }
1517
1518 if (!ctd->task_executed) {
1519 res = AST_TEST_FAIL;
1520 }
1521 return res;
1522}

References ast_cond_timedwait, AST_TEST_FAIL, AST_TEST_PASS, ast_tvnow(), end, lock, complex_task_data::lock, complex_task_data::notify_cond, SCOPED_MUTEX, and complex_task_data::task_executed.

Referenced by AST_TEST_DEFINE().

◆ wait_for_complex_start()

static int wait_for_complex_start ( struct complex_task_data ctd)
static

Definition at line 1466 of file test_threadpool.c.

1467{
1468 struct timeval start = ast_tvnow();
1469 struct timespec end = {
1470 .tv_sec = start.tv_sec + 5,
1471 .tv_nsec = start.tv_usec * 1000
1472 };
1473 SCOPED_MUTEX(lock, &ctd->lock);
1474
1475 while (!ctd->task_started) {
1476 if (ast_cond_timedwait(&ctd->notify_cond, lock, &end) == ETIMEDOUT) {
1477 break;
1478 }
1479 }
1480
1481 return ctd->task_started;
1482}

References ast_cond_timedwait, ast_tvnow(), end, lock, complex_task_data::lock, complex_task_data::notify_cond, SCOPED_MUTEX, and complex_task_data::task_started.

Referenced by AST_TEST_DEFINE().

◆ wait_for_empty_notice()

static enum ast_test_result_state wait_for_empty_notice ( struct ast_test *  test,
struct test_listener_data tld 
)
static

Definition at line 217 of file test_threadpool.c.

218{
219 struct timeval start = ast_tvnow();
220 struct timespec end = {
221 .tv_sec = start.tv_sec + 5,
222 .tv_nsec = start.tv_usec * 1000
223 };
225 SCOPED_MUTEX(lock, &tld->lock);
226
227 while (!tld->empty_notice) {
228 if (ast_cond_timedwait(&tld->cond, lock, &end) == ETIMEDOUT) {
229 break;
230 }
231 }
232
233 if (!tld->empty_notice) {
234 if (test) {
235 ast_test_status_update(test, "Test listener not notified that threadpool is empty\n");
236 }
237 res = AST_TEST_FAIL;
238 }
239
240 return res;
241}

References ast_cond_timedwait, AST_TEST_FAIL, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), test_listener_data::cond, test_listener_data::empty_notice, end, lock, test_listener_data::lock, and SCOPED_MUTEX.

Referenced by AST_TEST_DEFINE(), handle_cli_threadpool_push_efficiency(), and handle_cli_threadpool_push_serializer_efficiency().

◆ wait_for_task_pushed()

static void wait_for_task_pushed ( struct ast_threadpool_listener listener)
static

Definition at line 177 of file test_threadpool.c.

178{
180 struct timeval start = ast_tvnow();
181 struct timespec end = {
182 .tv_sec = start.tv_sec + 5,
183 .tv_nsec = start.tv_usec * 1000
184 };
185 SCOPED_MUTEX(lock, &tld->lock);
186
187 while (!tld->task_pushed) {
188 if (ast_cond_timedwait(&tld->cond, lock, &end) == ETIMEDOUT) {
189 break;
190 }
191 }
192}

References ast_cond_timedwait, ast_threadpool_listener_get_user_data(), ast_tvnow(), test_listener_data::cond, end, listener(), lock, test_listener_data::lock, SCOPED_MUTEX, and test_listener_data::task_pushed.

Referenced by AST_TEST_DEFINE().

◆ wait_until_thread_state()

static enum ast_test_result_state wait_until_thread_state ( struct ast_test *  test,
struct test_listener_data tld,
int  num_active,
int  num_idle 
)
static

Definition at line 151 of file test_threadpool.c.

152{
153 struct timeval start = ast_tvnow();
154 struct timespec end = {
155 .tv_sec = start.tv_sec + 5,
156 .tv_nsec = start.tv_usec * 1000
157 };
159 SCOPED_MUTEX(lock, &tld->lock);
160
161 while (!(tld->num_active == num_active && tld->num_idle == num_idle)) {
162 if (ast_cond_timedwait(&tld->cond, &tld->lock, &end) == ETIMEDOUT) {
163 break;
164 }
165 }
166
167 if (tld->num_active != num_active && tld->num_idle != num_idle) {
168 ast_test_status_update(test, "Number of active threads and idle threads not what was expected.\n");
169 ast_test_status_update(test, "Expected %d active threads but got %d\n", num_active, tld->num_active);
170 ast_test_status_update(test, "Expected %d idle threads but got %d\n", num_idle, tld->num_idle);
171 res = AST_TEST_FAIL;
172 }
173
174 return res;
175}

References ast_cond_timedwait, AST_TEST_FAIL, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), test_listener_data::cond, end, lock, test_listener_data::lock, test_listener_data::num_active, test_listener_data::num_idle, and SCOPED_MUTEX.

Referenced by AST_TEST_DEFINE(), and wait_until_thread_state_task_pushed().

◆ wait_until_thread_state_task_pushed()

static enum ast_test_result_state wait_until_thread_state_task_pushed ( struct ast_test *  test,
struct test_listener_data tld,
int  num_active,
int  num_idle,
int  num_tasks 
)
static

Definition at line 1063 of file test_threadpool.c.

1065{
1067 struct timeval start;
1068 struct timespec end;
1069
1070 res = wait_until_thread_state(test, tld, num_active, num_idle);
1071 if (res == AST_TEST_FAIL) {
1072 return res;
1073 }
1074
1075 start = ast_tvnow();
1076 end.tv_sec = start.tv_sec + 5;
1077 end.tv_nsec = start.tv_usec * 1000;
1078
1079 ast_mutex_lock(&tld->lock);
1080
1081 while (tld->num_tasks != num_tasks) {
1082 if (ast_cond_timedwait(&tld->cond, &tld->lock, &end) == ETIMEDOUT) {
1083 break;
1084 }
1085 }
1086
1087 if (tld->num_tasks != num_tasks) {
1088 ast_test_status_update(test, "Number of tasks pushed %d does not match expected %d\n",
1089 tld->num_tasks, num_tasks);
1090 res = AST_TEST_FAIL;
1091 }
1092
1093 ast_mutex_unlock(&tld->lock);
1094
1095 return res;
1096}

References ast_cond_timedwait, ast_mutex_lock, ast_mutex_unlock, AST_TEST_FAIL, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), test_listener_data::cond, end, test_listener_data::lock, test_listener_data::num_tasks, and wait_until_thread_state().

Referenced by AST_TEST_DEFINE().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "threadpool test module" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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 2100 of file test_threadpool.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 2100 of file test_threadpool.c.

◆ cli

struct ast_cli_entry cli[]
static
Initial value:
= {
AST_CLI_DEFINE(handle_cli_threadpool_push_efficiency, "Push tasks to a threadpool and measure efficiency"),
AST_CLI_DEFINE(handle_cli_threadpool_push_serializer_efficiency, "Push tasks to a threadpool in serializers and measure efficiency"),
}
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
static char * handle_cli_threadpool_push_serializer_efficiency(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_threadpool_push_efficiency(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Definition at line 2051 of file test_threadpool.c.

Referenced by load_module(), and unload_module().

◆ test_callbacks

const struct ast_threadpool_listener_callbacks test_callbacks
static