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

taskpool unit tests More...

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

Go to the source code of this file.

Data Structures

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

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
 AST_TEST_DEFINE (taskpool_push)
 
 AST_TEST_DEFINE (taskpool_push_grow)
 
 AST_TEST_DEFINE (taskpool_push_serializer)
 
 AST_TEST_DEFINE (taskpool_push_serializer_synchronous)
 
 AST_TEST_DEFINE (taskpool_push_serializer_synchronous_requeue)
 
 AST_TEST_DEFINE (taskpool_push_shrink)
 
 AST_TEST_DEFINE (taskpool_push_synchronous)
 
static int efficiency_task (void *data)
 
static char * handle_cli_taskpool_push_efficiency (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_cli_taskpool_push_serializer_efficiency (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int load_module (void)
 
static int requeue_task (void *data)
 
static int serializer_efficiency_task (void *data)
 
static int simple_task (void *data)
 
static struct test_datatest_alloc (void)
 
static void test_destroy (struct test_data *td)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "taskpool test module" , .key = "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 []
 

Detailed Description

taskpool unit tests

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

Definition in file test_taskpool.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 810 of file test_taskpool.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 810 of file test_taskpool.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 810 of file test_taskpool.c.

◆ AST_TEST_DEFINE() [1/7]

AST_TEST_DEFINE ( taskpool_push  )

Definition at line 78 of file test_taskpool.c.

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}
char * end
Definition: eagi_proxy.c:73
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:213
#define ast_mutex_unlock(a)
Definition: lock.h:197
#define ast_mutex_lock(a)
Definition: lock.h:196
def info(msg)
#define NULL
Definition: resample.c:96
An opaque taskpool structure.
Definition: taskpool.c:62
Sorcery object created based on backend data.
#define AST_TASKPOOL_OPTIONS_VERSION
Definition: taskpool.h:69
void ast_taskpool_shutdown(struct ast_taskpool *pool)
Shut down a taskpool and remove the underlying taskprocessors.
Definition: taskpool.c:653
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
struct ast_taskpool * ast_taskpool_create(const char *name, const struct ast_taskpool_options *options)
Create a new taskpool.
Definition: taskpool.c:324
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
ast_test_result_state
Definition: test.h:193
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
static struct test_options options
static struct test_data * test_alloc(void)
Definition: test_taskpool.c:50
static void test_destroy(struct test_data *td)
Definition: test_taskpool.c:61
static int simple_task(void *data)
Definition: test_taskpool.c:68
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

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

◆ AST_TEST_DEFINE() [2/7]

AST_TEST_DEFINE ( taskpool_push_grow  )

Definition at line 393 of file test_taskpool.c.

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}
size_t ast_taskpool_taskprocessors_count(struct ast_taskpool *pool)
Get the current number of taskprocessors in the taskpool.
Definition: taskpool.c:451

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

◆ AST_TEST_DEFINE() [3/7]

AST_TEST_DEFINE ( taskpool_push_serializer  )

Definition at line 190 of file test_taskpool.c.

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}
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
struct ast_taskprocessor * taskprocessor
Definition: test_taskpool.c:47
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_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.

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

◆ AST_TEST_DEFINE() [4/7]

AST_TEST_DEFINE ( taskpool_push_serializer_synchronous  )

Definition at line 264 of file test_taskpool.c.

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}
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

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

◆ AST_TEST_DEFINE() [5/7]

AST_TEST_DEFINE ( taskpool_push_serializer_synchronous_requeue  )

Definition at line 331 of file test_taskpool.c.

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}
static int requeue_task(void *data)

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

◆ AST_TEST_DEFINE() [6/7]

AST_TEST_DEFINE ( taskpool_push_shrink  )

Definition at line 467 of file test_taskpool.c.

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}

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

◆ AST_TEST_DEFINE() [7/7]

AST_TEST_DEFINE ( taskpool_push_synchronous  )

Definition at line 140 of file test_taskpool.c.

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}
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

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

◆ efficiency_task()

static int efficiency_task ( void *  data)
static

Definition at line 559 of file test_taskpool.c.

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}
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:764
struct ast_taskpool * pool
static int efficiency_task(void *data)

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

Referenced by efficiency_task(), and handle_cli_taskpool_push_efficiency().

◆ handle_cli_taskpool_push_efficiency()

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

Definition at line 578 of file test_taskpool.c.

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}
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
#define CLI_SUCCESS
Definition: cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
static struct test_val a

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

◆ handle_cli_taskpool_push_serializer_efficiency()

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

Definition at line 685 of file test_taskpool.c.

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}
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, ast_cli(), ast_cond_timedwait, ast_mutex_lock, ast_mutex_unlock, ast_taskpool_create(), AST_TASKPOOL_OPTIONS_VERSION, ast_taskpool_serializer(), ast_taskpool_shutdown(), ast_taskprocessor_build_name(), AST_TASKPROCESSOR_MAX_NAME, ast_taskprocessor_push(), ast_taskprocessor_unreference(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, test_data::cond, end, test_data::lock, NULL, serializer_efficiency_task_data::num_tasks_executed, options, serializer_efficiency_task_data::serializer, serializer_efficiency_task(), serializer_efficiency_task_data::shutdown, test_alloc(), test_destroy(), and ast_cli_entry::usage.

◆ load_module()

static int load_module ( void  )
static

Definition at line 797 of file test_taskpool.c.

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}
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
static struct ast_cli_entry cli[]
#define ARRAY_LEN(a)
Definition: utils.h:703

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

◆ requeue_task()

static int requeue_task ( void *  data)
static

Definition at line 326 of file test_taskpool.c.

327{
329}
struct ast_taskprocessor * ast_taskpool_serializer_get_current(void)
Get the taskpool serializer currently associated with this thread.
Definition: taskpool.c:784

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

Referenced by AST_TEST_DEFINE().

◆ serializer_efficiency_task()

static int serializer_efficiency_task ( void *  data)
static

Definition at line 658 of file test_taskpool.c.

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}
struct ast_taskprocessor * serializer[2]

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

Referenced by handle_cli_taskpool_push_serializer_efficiency(), and serializer_efficiency_task().

◆ simple_task()

static int simple_task ( void *  data)
static

Definition at line 68 of file test_taskpool.c.

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

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

Referenced by AST_TEST_DEFINE(), and requeue_task().

◆ test_alloc()

static struct test_data * test_alloc ( void  )
static

Definition at line 50 of file test_taskpool.c.

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}
#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, test_data::cond, test_data::lock, and NULL.

Referenced by AST_TEST_DEFINE(), handle_cli_taskpool_push_efficiency(), and handle_cli_taskpool_push_serializer_efficiency().

◆ test_destroy()

static void test_destroy ( struct test_data td)
static

Definition at line 61 of file test_taskpool.c.

62{
65 ast_free(td);
66}
#define ast_free(a)
Definition: astmm.h:180
#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, test_data::cond, and test_data::lock.

Referenced by AST_TEST_DEFINE(), handle_cli_taskpool_push_efficiency(), and handle_cli_taskpool_push_serializer_efficiency().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 784 of file test_taskpool.c.

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}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

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

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "taskpool test module" , .key = "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 810 of file test_taskpool.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 810 of file test_taskpool.c.

◆ cli

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

Definition at line 779 of file test_taskpool.c.

Referenced by load_module(), and unload_module().