|
20 | 20 |
|
21 | 21 | using namespace utest::v1;
|
22 | 22 |
|
| 23 | +#define THREAD_STACK_SIZE 512 |
| 24 | +#define TEST_TIMEOUT 50 |
| 25 | + |
23 | 26 | /* Enum used to select block allocation method. */
|
24 | 27 | typedef enum {
|
25 | 28 | ALLOC, CALLOC
|
@@ -450,6 +453,80 @@ void test_mem_pool_free_realloc_first_complex(AllocType atype)
|
450 | 453 | }
|
451 | 454 | }
|
452 | 455 |
|
| 456 | +/* Test alloc timeout |
| 457 | + * |
| 458 | + * Given a pool with one slot for int data |
| 459 | + * When a thread tries to allocate two blocks with @ TEST_TIMEOUT timeout |
| 460 | + * Then first operation succeeds immediately and second fails at the correct time. |
| 461 | + */ |
| 462 | +void test_mem_pool_timeout() |
| 463 | +{ |
| 464 | + MemoryPool<int, 1> mem_pool; |
| 465 | + |
| 466 | + Timer timer; |
| 467 | + timer.start(); |
| 468 | + |
| 469 | + int *item = mem_pool.alloc_for(TEST_TIMEOUT); |
| 470 | + TEST_ASSERT_NOT_NULL(item); |
| 471 | + TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, 0, timer.read_us()); |
| 472 | + |
| 473 | + item = mem_pool.alloc_for(TEST_TIMEOUT); |
| 474 | + TEST_ASSERT_NULL(item); |
| 475 | + TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, TEST_TIMEOUT * 1000, timer.read_us()); |
| 476 | + |
| 477 | + uint64_t end_time = Kernel::get_ms_count() + TEST_TIMEOUT; |
| 478 | + item = mem_pool.alloc_until(end_time); |
| 479 | + TEST_ASSERT_NULL(item); |
| 480 | + TEST_ASSERT_UINT64_WITHIN(TEST_TIMEOUT * 100, end_time, Kernel::get_ms_count()); |
| 481 | +} |
| 482 | + |
| 483 | +namespace { |
| 484 | +struct free_capture { |
| 485 | + MemoryPool<int, 1> *pool; |
| 486 | + int *item; |
| 487 | +}; |
| 488 | +} |
| 489 | + |
| 490 | +static void free_int_item(free_capture *to_free) |
| 491 | +{ |
| 492 | + ThisThread::sleep_for(TEST_TIMEOUT); |
| 493 | + |
| 494 | + osStatus status = to_free->pool->free(to_free->item); |
| 495 | + TEST_ASSERT_EQUAL(osOK, status); |
| 496 | +} |
| 497 | + |
| 498 | +/** Test alloc wait forever |
| 499 | + * |
| 500 | + * Given two threads A & B and a pool with one slot for int data |
| 501 | + * When thread A allocs a block from the pool and tries to alloc a second one with @a osWaitForever timeout |
| 502 | + * Then thread waits for a block to become free in the pool |
| 503 | + * When thread B frees the first block from the pool |
| 504 | + * Then thread A successfully allocs a block from the pool |
| 505 | + */ |
| 506 | +void test_mem_pool_waitforever() |
| 507 | +{ |
| 508 | + Thread t(osPriorityNormal, THREAD_STACK_SIZE); |
| 509 | + MemoryPool<int, 1> pool; |
| 510 | + |
| 511 | + Timer timer; |
| 512 | + timer.start(); |
| 513 | + |
| 514 | + int *item = pool.alloc_for(osWaitForever); |
| 515 | + TEST_ASSERT_NOT_NULL(item); |
| 516 | + TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, 0, timer.read_us()); |
| 517 | + |
| 518 | + struct free_capture to_free; |
| 519 | + to_free.pool = &pool; |
| 520 | + to_free.item = item; |
| 521 | + t.start(callback(free_int_item, &to_free)); |
| 522 | + |
| 523 | + item = pool.alloc_for(osWaitForever); |
| 524 | + TEST_ASSERT_EQUAL(item, to_free.item); |
| 525 | + TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, TEST_TIMEOUT * 1000, timer.read_us()); |
| 526 | + |
| 527 | + t.join(); |
| 528 | +} |
| 529 | + |
453 | 530 | /* Robustness checks for free() function.
|
454 | 531 | * Function under test is called with invalid parameters.
|
455 | 532 | *
|
@@ -569,6 +646,9 @@ Case cases[] = {
|
569 | 646 |
|
570 | 647 | Case("Test: fail (out of free blocks).", test_mem_pool_alloc_fail_wrapper<int, 3>),
|
571 | 648 |
|
| 649 | + Case("Test: timeout", test_mem_pool_timeout), |
| 650 | + Case("Test: wait forever", test_mem_pool_waitforever), |
| 651 | + |
572 | 652 | Case("Test: free() - robust (free called with invalid param - NULL).", free_block_invalid_parameter_null),
|
573 | 653 | Case("Test: free() - robust (free called with invalid param).", free_block_invalid_parameter)
|
574 | 654 | };
|
|
0 commit comments