Merge pull request #12901 from kjbracey-arm/mailchrono

Rationalise Mail/Queue/MemoryPool timing APIs
pull/12961/head
Martin Kojtal 2020-05-12 17:10:43 +02:00 committed by GitHub
commit 0b4b2afaf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 418 additions and 338 deletions

View File

@ -23,10 +23,24 @@
#error [NOT_SUPPORTED] MemoryPool test cases require a RTOS to run. #error [NOT_SUPPORTED] MemoryPool test cases require a RTOS to run.
#else #else
#define TEST_ASSERT_DURATION_WITHIN(delta, expected, actual) \
do { \
using ct = std::common_type_t<decltype(delta), decltype(expected), decltype(actual)>; \
TEST_ASSERT_INT_WITHIN(ct(delta).count(), ct(expected).count(), ct(actual).count()); \
} while (0)
#define TEST_ASSERT_TIME_POINT_WITHIN(delta, expected, actual) \
do { \
using ct_tp = std::common_type_t<decltype(expected), decltype(actual)>; \
using ct = std::common_type_t<decltype(delta), ct_tp::duration>; \
TEST_ASSERT_INT_WITHIN(ct(delta).count(), ct(expected.time_since_epoch()).count(), ct(actual.time_since_epoch()).count()); \
} while (0)
using namespace utest::v1; using namespace utest::v1;
using namespace std::chrono;
#define THREAD_STACK_SIZE 512 #define THREAD_STACK_SIZE 512
#define TEST_TIMEOUT 50 #define TEST_TIMEOUT 50ms
/* Enum used to select block allocation method. */ /* Enum used to select block allocation method. */
typedef enum { typedef enum {
@ -68,7 +82,7 @@ void comp_set(COMPLEX_TYPE *object, int a, char b, int c)
object->c = c; object->c = c;
} }
/* Template for functional tests for alloc(), calloc() functions /* Template for functional tests for try_alloc(), try_calloc() functions
* of MemoryPool object. * of MemoryPool object.
* *
* Given MemoryPool object of the specified type and queue size has * Given MemoryPool object of the specified type and queue size has
@ -89,9 +103,9 @@ void test_mem_pool_alloc_success(AllocType atype)
for (i = 0; i < numOfEntries; i++) { for (i = 0; i < numOfEntries; i++) {
/* Allocate memory block. */ /* Allocate memory block. */
if (atype == ALLOC) { if (atype == ALLOC) {
p_blocks[i] = mem_pool.alloc(); p_blocks[i] = mem_pool.try_alloc();
} else { } else {
p_blocks[i] = mem_pool.calloc(); p_blocks[i] = mem_pool.try_calloc();
} }
/* Show that memory pool block has been allocated. */ /* Show that memory pool block has been allocated. */
@ -112,7 +126,7 @@ void test_mem_pool_alloc_success(AllocType atype)
} }
} }
/* Template for functional tests for alloc(), calloc() functions /* Template for functional tests for try_alloc(), try_calloc() functions
* of MemoryPool object. * of MemoryPool object.
* *
* Complex memory pool block type is used. * Complex memory pool block type is used.
@ -135,9 +149,9 @@ void test_mem_pool_alloc_success_complex(AllocType atype)
for (i = 0; i < numOfEntries; i++) { for (i = 0; i < numOfEntries; i++) {
/* Allocate memory block. */ /* Allocate memory block. */
if (atype == ALLOC) { if (atype == ALLOC) {
p_blocks[i] = mem_pool.alloc(); p_blocks[i] = mem_pool.try_alloc();
} else { } else {
p_blocks[i] = mem_pool.calloc(); p_blocks[i] = mem_pool.try_calloc();
} }
/* Show that memory pool block has been allocated. */ /* Show that memory pool block has been allocated. */
@ -158,7 +172,7 @@ void test_mem_pool_alloc_success_complex(AllocType atype)
} }
} }
/* Template for functional tests for alloc(), calloc() functions /* Template for functional tests for try_alloc(), try_calloc() functions
* of MemoryPool object. * of MemoryPool object.
* *
* Given MemoryPool has already max number of blocks allocated from the pool. * Given MemoryPool has already max number of blocks allocated from the pool.
@ -177,9 +191,9 @@ void test_mem_pool_alloc_fail(AllocType atype)
/* Allocate all available blocks. */ /* Allocate all available blocks. */
for (i = 0; i < numOfEntries; i++) { for (i = 0; i < numOfEntries; i++) {
if (atype == ALLOC) { if (atype == ALLOC) {
p_blocks[i] = mem_pool.alloc(); p_blocks[i] = mem_pool.try_alloc();
} else { } else {
p_blocks[i] = mem_pool.calloc(); p_blocks[i] = mem_pool.try_calloc();
} }
/* Show that memory pool block has been allocated. */ /* Show that memory pool block has been allocated. */
@ -188,9 +202,9 @@ void test_mem_pool_alloc_fail(AllocType atype)
/* There are no more blocks available. Try to allocate another block. */ /* There are no more blocks available. Try to allocate another block. */
if (atype == ALLOC) { if (atype == ALLOC) {
p_extra_block = mem_pool.alloc(); p_extra_block = mem_pool.try_alloc();
} else { } else {
p_extra_block = mem_pool.calloc(); p_extra_block = mem_pool.try_calloc();
} }
/* Show that memory pool block has NOT been allocated. */ /* Show that memory pool block has NOT been allocated. */
@ -216,9 +230,9 @@ void test_mem_pool_free_success(AllocType atype)
/* Allocate all available blocks. */ /* Allocate all available blocks. */
for (i = 0; i < numOfEntries; i++) { for (i = 0; i < numOfEntries; i++) {
if (atype == ALLOC) { if (atype == ALLOC) {
p_blocks[i] = mem_pool.alloc(); p_blocks[i] = mem_pool.try_alloc();
} else { } else {
p_blocks[i] = mem_pool.calloc(); p_blocks[i] = mem_pool.try_calloc();
} }
/* Show that memory pool block has been allocated. */ /* Show that memory pool block has been allocated. */
@ -234,7 +248,7 @@ void test_mem_pool_free_success(AllocType atype)
} }
} }
/* Template for functional tests for alloc(), calloc() functions /* Template for functional tests for try_alloc(), try_calloc() functions
* of MemoryPool object. * of MemoryPool object.
* *
* Basic memory pool block type is used. * Basic memory pool block type is used.
@ -256,9 +270,9 @@ void test_mem_pool_free_realloc_last(AllocType atype)
/* Allocate all available blocks. */ /* Allocate all available blocks. */
for (i = 0; i < numOfEntries; i++) { for (i = 0; i < numOfEntries; i++) {
if (atype == ALLOC) { if (atype == ALLOC) {
p_blocks[i] = mem_pool.alloc(); p_blocks[i] = mem_pool.try_alloc();
} else { } else {
p_blocks[i] = mem_pool.calloc(); p_blocks[i] = mem_pool.try_calloc();
} }
/* Init block. */ /* Init block. */
@ -276,9 +290,9 @@ void test_mem_pool_free_realloc_last(AllocType atype)
/* Try to allocate another block (one block is now available). */ /* Try to allocate another block (one block is now available). */
if (atype == ALLOC) { if (atype == ALLOC) {
p_blocks[numOfEntries - 1] = mem_pool.alloc(); p_blocks[numOfEntries - 1] = mem_pool.try_alloc();
} else { } else {
p_blocks[numOfEntries - 1] = mem_pool.calloc(); p_blocks[numOfEntries - 1] = mem_pool.try_calloc();
} }
/* Show that memory pool block has been now allocated. */ /* Show that memory pool block has been now allocated. */
@ -290,7 +304,7 @@ void test_mem_pool_free_realloc_last(AllocType atype)
} }
} }
/* Template for functional tests for alloc(), calloc() functions /* Template for functional tests for try_alloc(), try_calloc() functions
* of MemoryPool object. * of MemoryPool object.
* *
* Complex memory pool block type is used. * Complex memory pool block type is used.
@ -312,9 +326,9 @@ void test_mem_pool_free_realloc_last_complex(AllocType atype)
/* Allocate all available blocks. */ /* Allocate all available blocks. */
for (i = 0; i < numOfEntries; i++) { for (i = 0; i < numOfEntries; i++) {
if (atype == ALLOC) { if (atype == ALLOC) {
p_blocks[i] = mem_pool.alloc(); p_blocks[i] = mem_pool.try_alloc();
} else { } else {
p_blocks[i] = mem_pool.calloc(); p_blocks[i] = mem_pool.try_calloc();
} }
/* Init block. */ /* Init block. */
@ -332,9 +346,9 @@ void test_mem_pool_free_realloc_last_complex(AllocType atype)
/* Try to allocate another block (one block is now available). */ /* Try to allocate another block (one block is now available). */
if (atype == ALLOC) { if (atype == ALLOC) {
p_blocks[numOfEntries - 1] = mem_pool.alloc(); p_blocks[numOfEntries - 1] = mem_pool.try_alloc();
} else { } else {
p_blocks[numOfEntries - 1] = mem_pool.calloc(); p_blocks[numOfEntries - 1] = mem_pool.try_calloc();
} }
/* Show that memory pool block has been now allocated. */ /* Show that memory pool block has been now allocated. */
@ -346,7 +360,7 @@ void test_mem_pool_free_realloc_last_complex(AllocType atype)
} }
} }
/* Template for functional tests for alloc(), calloc() functions /* Template for functional tests for try_alloc(), try_calloc() functions
* of MemoryPool object. * of MemoryPool object.
* *
* Basic memory pool block type is used. * Basic memory pool block type is used.
@ -368,9 +382,9 @@ void test_mem_pool_free_realloc_first(AllocType atype)
/* Allocate all available blocks. */ /* Allocate all available blocks. */
for (i = 0; i < numOfEntries; i++) { for (i = 0; i < numOfEntries; i++) {
if (atype == ALLOC) { if (atype == ALLOC) {
p_blocks[i] = mem_pool.alloc(); p_blocks[i] = mem_pool.try_alloc();
} else { } else {
p_blocks[i] = mem_pool.calloc(); p_blocks[i] = mem_pool.try_calloc();
} }
/* Init block. */ /* Init block. */
@ -388,9 +402,9 @@ void test_mem_pool_free_realloc_first(AllocType atype)
/* Try to allocate another block (one block is now available). */ /* Try to allocate another block (one block is now available). */
if (atype == ALLOC) { if (atype == ALLOC) {
p_blocks[0] = mem_pool.alloc(); p_blocks[0] = mem_pool.try_alloc();
} else { } else {
p_blocks[0] = mem_pool.calloc(); p_blocks[0] = mem_pool.try_calloc();
} }
/* Show that memory pool block has been now allocated. */ /* Show that memory pool block has been now allocated. */
@ -402,7 +416,7 @@ void test_mem_pool_free_realloc_first(AllocType atype)
} }
} }
/* Template for functional tests for alloc(), calloc() functions /* Template for functional tests for try_alloc(), try_calloc() functions
* of MemoryPool object. * of MemoryPool object.
* *
* Complex memory pool block type is used. * Complex memory pool block type is used.
@ -424,9 +438,9 @@ void test_mem_pool_free_realloc_first_complex(AllocType atype)
/* Allocate all available blocks. */ /* Allocate all available blocks. */
for (i = 0; i < numOfEntries; i++) { for (i = 0; i < numOfEntries; i++) {
if (atype == ALLOC) { if (atype == ALLOC) {
p_blocks[i] = mem_pool.alloc(); p_blocks[i] = mem_pool.try_alloc();
} else { } else {
p_blocks[i] = mem_pool.calloc(); p_blocks[i] = mem_pool.try_calloc();
} }
/* Init block. */ /* Init block. */
@ -444,9 +458,9 @@ void test_mem_pool_free_realloc_first_complex(AllocType atype)
/* Try to allocate another block (one block is now available). */ /* Try to allocate another block (one block is now available). */
if (atype == ALLOC) { if (atype == ALLOC) {
p_blocks[0] = mem_pool.alloc(); p_blocks[0] = mem_pool.try_alloc();
} else { } else {
p_blocks[0] = mem_pool.calloc(); p_blocks[0] = mem_pool.try_calloc();
} }
/* Show that memory pool block has been now allocated. */ /* Show that memory pool block has been now allocated. */
@ -458,7 +472,7 @@ void test_mem_pool_free_realloc_first_complex(AllocType atype)
} }
} }
/* Test alloc timeout /* Test try_alloc_for/try_alloc_until timeout
* *
* Given a pool with one slot for int data * Given a pool with one slot for int data
* When a thread tries to allocate two blocks with @ TEST_TIMEOUT timeout * When a thread tries to allocate two blocks with @ TEST_TIMEOUT timeout
@ -471,18 +485,18 @@ void test_mem_pool_timeout()
Timer timer; Timer timer;
timer.start(); timer.start();
int *item = mem_pool.alloc_for(TEST_TIMEOUT); int *item = mem_pool.try_alloc_for(TEST_TIMEOUT);
TEST_ASSERT_NOT_NULL(item); TEST_ASSERT_NOT_NULL(item);
TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, 0, timer.read_us()); TEST_ASSERT_DURATION_WITHIN(TEST_TIMEOUT / 10, 0ms, timer.elapsed_time());
item = mem_pool.alloc_for(TEST_TIMEOUT); item = mem_pool.try_alloc_for(TEST_TIMEOUT);
TEST_ASSERT_NULL(item); TEST_ASSERT_NULL(item);
TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, TEST_TIMEOUT * 1000, timer.read_us()); TEST_ASSERT_DURATION_WITHIN(TEST_TIMEOUT / 10, TEST_TIMEOUT, timer.elapsed_time());
uint64_t end_time = Kernel::get_ms_count() + TEST_TIMEOUT; auto end_time = Kernel::Clock::now() + TEST_TIMEOUT;
item = mem_pool.alloc_until(end_time); item = mem_pool.try_alloc_until(end_time);
TEST_ASSERT_NULL(item); TEST_ASSERT_NULL(item);
TEST_ASSERT_UINT64_WITHIN(TEST_TIMEOUT * 100, end_time, Kernel::get_ms_count()); TEST_ASSERT_TIME_POINT_WITHIN(TEST_TIMEOUT / 10, end_time, Kernel::Clock::now());
} }
namespace { namespace {
@ -516,18 +530,18 @@ void test_mem_pool_waitforever()
Timer timer; Timer timer;
timer.start(); timer.start();
int *item = pool.alloc_for(osWaitForever); int *item = pool.try_alloc_for(Kernel::wait_for_u32_forever);
TEST_ASSERT_NOT_NULL(item); TEST_ASSERT_NOT_NULL(item);
TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, 0, timer.read_us()); TEST_ASSERT_DURATION_WITHIN(TEST_TIMEOUT / 10, 0ms, timer.elapsed_time());
struct free_capture to_free; struct free_capture to_free;
to_free.pool = &pool; to_free.pool = &pool;
to_free.item = item; to_free.item = item;
t.start(callback(free_int_item, &to_free)); t.start(callback(free_int_item, &to_free));
item = pool.alloc_for(osWaitForever); item = pool.try_alloc_for(Kernel::wait_for_u32_forever);
TEST_ASSERT_EQUAL(item, to_free.item); TEST_ASSERT_EQUAL(item, to_free.item);
TEST_ASSERT_UINT32_WITHIN(TEST_TIMEOUT * 100, TEST_TIMEOUT * 1000, timer.read_us()); TEST_ASSERT_DURATION_WITHIN(TEST_TIMEOUT / 10, TEST_TIMEOUT, timer.elapsed_time());
t.join(); t.join();
} }
@ -632,12 +646,12 @@ void test_mem_pool_alloc_fail_wrapper()
} }
Case cases[] = { Case cases[] = {
Case("Test: alloc()/calloc() - success, 4 bytes b_type, q_size equal to 1.", test_mem_pool_alloc_success_wrapper<int, 1>), Case("Test: try_alloc()/try_calloc() - success, 4 bytes b_type, q_size equal to 1.", test_mem_pool_alloc_success_wrapper<int, 1>),
Case("Test: alloc()/calloc() - success, 4 bytes b_type, q_size equal to 3.", test_mem_pool_alloc_success_wrapper<int, 3>), Case("Test: try_alloc()/try_calloc() - success, 4 bytes b_type, q_size equal to 3.", test_mem_pool_alloc_success_wrapper<int, 3>),
Case("Test: alloc()/calloc() - success, 1 bytes b_type, q_size equal to 1.", test_mem_pool_alloc_success_wrapper<char, 1>), Case("Test: try_alloc()/try_calloc() - success, 1 bytes b_type, q_size equal to 1.", test_mem_pool_alloc_success_wrapper<char, 1>),
Case("Test: alloc()/calloc() - success, 1 bytes b_type, q_size equal to 3.", test_mem_pool_alloc_success_wrapper<char, 3>), Case("Test: try_alloc()/try_calloc() - success, 1 bytes b_type, q_size equal to 3.", test_mem_pool_alloc_success_wrapper<char, 3>),
Case("Test: alloc()/calloc() - success, complex b_type, q_size equal to 1.", test_mem_pool_alloc_success_complex_wrapper<COMPLEX_TYPE, 1>), Case("Test: try_alloc()/try_calloc() - success, complex b_type, q_size equal to 1.", test_mem_pool_alloc_success_complex_wrapper<COMPLEX_TYPE, 1>),
Case("Test: alloc()/calloc() - success, complex b_type, q_size equal to 3.", test_mem_pool_alloc_success_complex_wrapper<COMPLEX_TYPE, 3>), Case("Test: try_alloc()/try_calloc() - success, complex b_type, q_size equal to 3.", test_mem_pool_alloc_success_complex_wrapper<COMPLEX_TYPE, 3>),
Case("Test: free() - success, 4 bytes b_type, q_size equal to 1.", test_mem_pool_free_success_wrapper<int, 1>), Case("Test: free() - success, 4 bytes b_type, q_size equal to 1.", test_mem_pool_free_success_wrapper<int, 1>),
Case("Test: free() - success, 4 bytes b_type, q_size equal to 3.", test_mem_pool_free_success_wrapper<int, 3>), Case("Test: free() - success, 4 bytes b_type, q_size equal to 3.", test_mem_pool_free_success_wrapper<int, 3>),

View File

@ -29,6 +29,13 @@
#include "rtos.h" #include "rtos.h"
using namespace utest::v1; using namespace utest::v1;
using namespace std::chrono;
#define TEST_ASSERT_DURATION_WITHIN(delta, expected, actual) \
do { \
using ct = std::common_type_t<decltype(delta), decltype(expected), decltype(actual)>; \
TEST_ASSERT_INT_WITHIN(ct(delta).count(), ct(expected).count(), ct(actual).count()); \
} while (0)
#if defined(__CORTEX_M23) || defined(__CORTEX_M33) #if defined(__CORTEX_M23) || defined(__CORTEX_M33)
#define THREAD_STACK_SIZE 512 #define THREAD_STACK_SIZE 512
@ -43,9 +50,9 @@ using namespace utest::v1;
#define THREAD_1_ID 1 #define THREAD_1_ID 1
#define THREAD_2_ID 2 #define THREAD_2_ID 2
#define THREAD_3_ID 3 #define THREAD_3_ID 3
#define QUEUE_PUT_DELAY_1 5 #define QUEUE_PUT_DELAY_1 5ms
#define QUEUE_PUT_DELAY_2 50 #define QUEUE_PUT_DELAY_2 50ms
#define QUEUE_PUT_DELAY_3 100 #define QUEUE_PUT_DELAY_3 100ms
#define DATA_BASE 100 #define DATA_BASE 100
@ -55,31 +62,29 @@ typedef struct {
} mail_t; } mail_t;
template<uint8_t thread_id, uint32_t wait_ms, uint32_t send_count> void send_thread(Mail<mail_t, QUEUE_SIZE> *m, uint8_t thread_id, milliseconds wait, uint32_t send_count)
void send_thread(Mail<mail_t, QUEUE_SIZE> *m)
{ {
uint32_t data = thread_id * DATA_BASE; uint32_t data = thread_id * DATA_BASE;
for (uint32_t i = 0; i < send_count; i++) { for (uint32_t i = 0; i < send_count; i++) {
mail_t *mail = m->alloc(); mail_t *mail = m->try_alloc();
mail->thread_id = thread_id; mail->thread_id = thread_id;
mail->data = data++; mail->data = data++;
m->put(mail); m->put(mail);
ThisThread::sleep_for(wait_ms); ThisThread::sleep_for(wait);
} }
} }
template<uint8_t thread_id, uint32_t queue_size, uint32_t wait_ms> template<uint32_t queue_size>
void receive_thread(Mail<mail_t, queue_size> *m) void receive_thread(Mail<mail_t, queue_size> *m, uint8_t thread_id, milliseconds wait)
{ {
int result_counter = 0; int result_counter = 0;
uint32_t data = thread_id * DATA_BASE; uint32_t data = thread_id * DATA_BASE;
ThisThread::sleep_for(wait_ms); ThisThread::sleep_for(wait);
for (uint32_t i = 0; i < queue_size; i++) { for (uint32_t i = 0; i < queue_size; i++) {
osEvent evt = m->get(); mail_t *mail = m->try_get_for(Kernel::wait_for_u32_forever);
if (evt.status == osEventMail) { if (mail) {
mail_t *mail = (mail_t *)evt.value.p;
const uint8_t id = mail->thread_id; const uint8_t id = mail->thread_id;
// verify thread id // verify thread id
@ -108,16 +113,15 @@ void test_single_thread_order(void)
// mail send thread creation // mail send thread creation
Thread thread(osPriorityNormal, THREAD_STACK_SIZE); Thread thread(osPriorityNormal, THREAD_STACK_SIZE);
thread.start(callback(send_thread<THREAD_1_ID, QUEUE_PUT_DELAY_1, QUEUE_SIZE>, &mail_box)); thread.start([&] { send_thread(&mail_box, THREAD_1_ID, QUEUE_PUT_DELAY_1, QUEUE_SIZE); });
// wait for some mail to be collected // wait for some mail to be collected
ThisThread::sleep_for(10); ThisThread::sleep_for(10ms);
for (uint32_t i = 0; i < QUEUE_SIZE; i++) { for (uint32_t i = 0; i < QUEUE_SIZE; i++) {
// mail receive (main thread) // mail receive (main thread)
osEvent evt = mail_box.get(); mail_t *mail = mail_box.try_get_for(Kernel::wait_for_u32_forever);
if (evt.status == osEventMail) { if (mail) {
mail_t *mail = (mail_t *)evt.value.p;
const uint8_t id = mail->thread_id; const uint8_t id = mail->thread_id;
// verify thread id // verify thread id
@ -148,18 +152,17 @@ void test_multi_thread_order(void)
Thread thread1(osPriorityNormal, THREAD_STACK_SIZE); Thread thread1(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread2(osPriorityNormal, THREAD_STACK_SIZE); Thread thread2(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread3(osPriorityNormal, THREAD_STACK_SIZE); Thread thread3(osPriorityNormal, THREAD_STACK_SIZE);
thread1.start(callback(send_thread<THREAD_1_ID, QUEUE_PUT_DELAY_1, 7>, &mail_box)); thread1.start([&] { send_thread(&mail_box, THREAD_1_ID, QUEUE_PUT_DELAY_1, 7); });
thread2.start(callback(send_thread<THREAD_2_ID, QUEUE_PUT_DELAY_2, 5>, &mail_box)); thread2.start([&] { send_thread(&mail_box, THREAD_2_ID, QUEUE_PUT_DELAY_2, 5); });
thread3.start(callback(send_thread<THREAD_3_ID, QUEUE_PUT_DELAY_3, 4>, &mail_box)); thread3.start([&] { send_thread(&mail_box, THREAD_3_ID, QUEUE_PUT_DELAY_3, 4); });
// wait for some mail to be collected // wait for some mail to be collected
ThisThread::sleep_for(10); ThisThread::sleep_for(10ms);
for (uint32_t i = 0; i < QUEUE_SIZE; i++) { for (uint32_t i = 0; i < QUEUE_SIZE; i++) {
// mail receive (main thread) // mail receive (main thread)
osEvent evt = mail_box.get(); mail_t *mail = mail_box.try_get_for(Kernel::wait_for_u32_forever);
if (evt.status == osEventMail) { if (mail) {
mail_t *mail = (mail_t *)evt.value.p;
const uint8_t id = mail->thread_id; const uint8_t id = mail->thread_id;
// verify thread id // verify thread id
@ -191,30 +194,30 @@ void test_multi_thread_multi_mail_order(void)
Thread thread1(osPriorityNormal, THREAD_STACK_SIZE); Thread thread1(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread2(osPriorityNormal, THREAD_STACK_SIZE); Thread thread2(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread3(osPriorityNormal, THREAD_STACK_SIZE); Thread thread3(osPriorityNormal, THREAD_STACK_SIZE);
thread1.start(callback(receive_thread<THREAD_1_ID, 4, 0>, mail_box + 1)); thread1.start([&] { receive_thread<4>(mail_box + 1, THREAD_1_ID, 0ms); });
thread2.start(callback(receive_thread<THREAD_2_ID, 4, 10>, mail_box + 2)); thread2.start([&] { receive_thread<4>(mail_box + 2, THREAD_2_ID, 10ms); });
thread3.start(callback(receive_thread<THREAD_3_ID, 4, 100>, mail_box + 3)); thread3.start([&] { receive_thread<4>(mail_box + 3, THREAD_3_ID, 100ms); });
for (uint32_t i = 0; i < 4; i++) { for (uint32_t i = 0; i < 4; i++) {
id = THREAD_1_ID; id = THREAD_1_ID;
mail = mail_box[id].alloc(); mail = mail_box[id].try_alloc();
mail->thread_id = id; mail->thread_id = id;
mail->data = data[id]++; mail->data = data[id]++;
mail_box[id].put(mail); mail_box[id].put(mail);
id = THREAD_2_ID; id = THREAD_2_ID;
mail = mail_box[id].alloc(); mail = mail_box[id].try_alloc();
mail->thread_id = id; mail->thread_id = id;
mail->data = data[id]++; mail->data = data[id]++;
mail_box[id].put(mail); mail_box[id].put(mail);
id = THREAD_3_ID; id = THREAD_3_ID;
mail = mail_box[id].alloc(); mail = mail_box[id].try_alloc();
mail->thread_id = id; mail->thread_id = id;
mail->data = data[id]++; mail->data = data[id]++;
mail_box[id].put(mail); mail_box[id].put(mail);
ThisThread::sleep_for(i * 10); ThisThread::sleep_for(i * 10ms);
} }
thread1.join(); thread1.join();
@ -238,7 +241,7 @@ void test_free_wrong()
status = mail_box.free(mail); status = mail_box.free(mail);
TEST_ASSERT_EQUAL(osErrorParameter, status); TEST_ASSERT_EQUAL(osErrorParameter, status);
mail = mail_box.alloc(); mail = mail_box.try_alloc();
TEST_ASSERT_NOT_EQUAL(NULL, mail); TEST_ASSERT_NOT_EQUAL(NULL, mail);
mail = &data; mail = &data;
@ -262,7 +265,7 @@ void test_free_null()
status = mail_box.free(mail); status = mail_box.free(mail);
TEST_ASSERT_EQUAL(osErrorParameter, status); TEST_ASSERT_EQUAL(osErrorParameter, status);
mail = mail_box.alloc(); mail = mail_box.try_alloc();
TEST_ASSERT_NOT_EQUAL(NULL, mail); TEST_ASSERT_NOT_EQUAL(NULL, mail);
mail = NULL; mail = NULL;
@ -273,8 +276,8 @@ void test_free_null()
/** Test get from empty mailbox with timeout set /** Test get from empty mailbox with timeout set
Given an empty mailbox Given an empty mailbox
When @a get is called on the mailbox with timeout of 50 When @a try_get_for is called on the mailbox with timeout of 50ms
Then mailbox returns status of osOK, but no data after specified amount of time Then mailbox returns no data
*/ */
void test_get_empty_timeout() void test_get_empty_timeout()
{ {
@ -282,23 +285,23 @@ void test_get_empty_timeout()
Timer timer; Timer timer;
timer.start(); timer.start();
osEvent evt = mail_box.get(50); uint32_t *mail = mail_box.try_get_for(50ms);
TEST_ASSERT_UINT32_WITHIN(5000, 50000, timer.read_us()); TEST_ASSERT_DURATION_WITHIN(5ms, 50ms, timer.elapsed_time());
TEST_ASSERT_EQUAL(osEventTimeout, evt.status); TEST_ASSERT_NULL(mail);
} }
/** Test get from empty mailbox with 0 timeout /** Test get from empty mailbox with 0 timeout
Given an empty mailbox Given an empty mailbox
When @a get is called on the mailbox with timeout of 0 When @a try_get is called on the mailbox
Then mailbox returns status of osOK, but no data Then mailbox returns no data
*/ */
void test_get_empty_no_timeout() void test_get_empty_no_timeout()
{ {
Mail<uint32_t, 4> mail_box; Mail<uint32_t, 4> mail_box;
osEvent evt = mail_box.get(0); uint32_t *mail = mail_box.try_get();
TEST_ASSERT_EQUAL(osOK, evt.status); TEST_ASSERT_NULL(mail);
} }
/** Test mail order /** Test mail order
@ -311,36 +314,29 @@ void test_get_empty_no_timeout()
void test_order(void) void test_order(void)
{ {
osStatus status; osStatus status;
osEvent evt;
Mail<int32_t, 4> mail_box; Mail<int32_t, 4> mail_box;
const int32_t TEST_VAL1 = 123; const int32_t TEST_VAL1 = 123;
const int32_t TEST_VAL2 = 456; const int32_t TEST_VAL2 = 456;
int32_t *mail1 = mail_box.alloc(); int32_t *mail1 = mail_box.try_alloc();
TEST_ASSERT_NOT_EQUAL(NULL, mail1); TEST_ASSERT_NOT_EQUAL(NULL, mail1);
*mail1 = TEST_VAL1; *mail1 = TEST_VAL1;
status = mail_box.put(mail1); mail_box.put(mail1);
TEST_ASSERT_EQUAL(osOK, status);
int32_t *mail2 = mail_box.alloc(); int32_t *mail2 = mail_box.try_alloc();
TEST_ASSERT_NOT_EQUAL(NULL, mail2); TEST_ASSERT_NOT_EQUAL(NULL, mail2);
*mail2 = TEST_VAL2; *mail2 = TEST_VAL2;
status = mail_box.put(mail2); mail_box.put(mail2);
TEST_ASSERT_EQUAL(osOK, status);
evt = mail_box.get(); mail1 = mail_box.try_get_for(Kernel::wait_for_u32_forever);
TEST_ASSERT_EQUAL(evt.status, osEventMail); TEST_ASSERT_NOT_NULL(mail1);
mail1 = (int32_t *)evt.value.p;
TEST_ASSERT_EQUAL(TEST_VAL1, *mail1); TEST_ASSERT_EQUAL(TEST_VAL1, *mail1);
evt = mail_box.get(); mail2 = mail_box.try_get_for(Kernel::wait_for_u32_forever);
TEST_ASSERT_EQUAL(evt.status, osEventMail); TEST_ASSERT_NOT_NULL(mail2);
mail2 = (int32_t *)evt.value.p;
TEST_ASSERT_EQUAL(TEST_VAL2, *mail2); TEST_ASSERT_EQUAL(TEST_VAL2, *mail2);
@ -354,35 +350,34 @@ void test_order(void)
/** Test Mail box max size limit /** Test Mail box max size limit
Given an Mail box with max size of 4 elements Given an Mail box with max size of 4 elements
When call @a alloc four times it returns memory blocks When call @a try_alloc four times it returns memory blocks
Then the memory blocks should be valid Then the memory blocks should be valid
When call @a alloc one more time it returns memory blocks When call @a try_alloc one more time it returns memory blocks
Then the memory blocks should be not valid (NULL - no memory available) Then the memory blocks should be not valid (NULL - no memory available)
*/ */
void test_max_size() void test_max_size()
{ {
osStatus status; osStatus status;
Mail<uint32_t, 4> mail_box; Mail<uint32_t, 4> mail_box;
const uint32_t TEST_VAL = 123;
// 1 OK // 1 OK
uint32_t *mail1 = mail_box.alloc(); uint32_t *mail1 = mail_box.try_alloc();
TEST_ASSERT_NOT_EQUAL(NULL, mail1); TEST_ASSERT_NOT_EQUAL(NULL, mail1);
// 2 OK // 2 OK
uint32_t *mail2 = mail_box.alloc(); uint32_t *mail2 = mail_box.try_alloc();
TEST_ASSERT_NOT_EQUAL(NULL, mail2); TEST_ASSERT_NOT_EQUAL(NULL, mail2);
// 3 OK // 3 OK
uint32_t *mail3 = mail_box.alloc(); uint32_t *mail3 = mail_box.try_alloc();
TEST_ASSERT_NOT_EQUAL(NULL, mail3); TEST_ASSERT_NOT_EQUAL(NULL, mail3);
// 4 OK // 4 OK
uint32_t *mail4 = mail_box.alloc(); uint32_t *mail4 = mail_box.try_alloc();
TEST_ASSERT_NOT_EQUAL(NULL, mail4); TEST_ASSERT_NOT_EQUAL(NULL, mail4);
// 5 KO // 5 KO
uint32_t *mail5 = mail_box.alloc(); uint32_t *mail5 = mail_box.try_alloc();
TEST_ASSERT_EQUAL(NULL, mail5); TEST_ASSERT_EQUAL(NULL, mail5);
@ -412,17 +407,14 @@ void test_data_type(void)
Mail<T, 4> mail_box; Mail<T, 4> mail_box;
const T TEST_VAL = 123; const T TEST_VAL = 123;
T *mail = mail_box.alloc(); T *mail = mail_box.try_alloc();
TEST_ASSERT_NOT_EQUAL(NULL, mail); TEST_ASSERT_NOT_EQUAL(NULL, mail);
*mail = TEST_VAL; *mail = TEST_VAL;
status = mail_box.put(mail); mail_box.put(mail);
TEST_ASSERT_EQUAL(osOK, status);
osEvent evt = mail_box.get(); mail = mail_box.try_get_for(Kernel::wait_for_u32_forever);
TEST_ASSERT_EQUAL(evt.status, osEventMail); TEST_ASSERT_NOT_NULL(mail);
mail = (T *)evt.value.p;
TEST_ASSERT_EQUAL(TEST_VAL, *mail); TEST_ASSERT_EQUAL(TEST_VAL, *mail);
@ -430,17 +422,17 @@ void test_data_type(void)
TEST_ASSERT_EQUAL(osOK, status); TEST_ASSERT_EQUAL(osOK, status);
} }
/** Test calloc - memory block allocation with resetting /** Test try_calloc - memory block allocation with resetting
Given an empty Mail box Given an empty Mail box
When call @a calloc it returns allocated memory block When call @a try_calloc it returns allocated memory block
Then the memory block should be valid and filled with zeros Then the memory block should be valid and filled with zeros
*/ */
void test_calloc() void test_calloc()
{ {
Mail<uint32_t, 1> mail_box; Mail<uint32_t, 1> mail_box;
uint32_t *mail = mail_box.calloc(); uint32_t *mail = mail_box.try_calloc();
TEST_ASSERT_NOT_EQUAL(NULL, mail); TEST_ASSERT_NOT_EQUAL(NULL, mail);
TEST_ASSERT_EQUAL(0, *mail); TEST_ASSERT_EQUAL(0, *mail);
} }
@ -455,7 +447,7 @@ void test_mail_empty()
{ {
Mail<mail_t, 1> m; Mail<mail_t, 1> m;
mail_t *mail = m.alloc(); mail_t *mail = m.try_alloc();
TEST_ASSERT_EQUAL(true, m.empty()); TEST_ASSERT_EQUAL(true, m.empty());
@ -474,7 +466,7 @@ void test_mail_full()
{ {
Mail<mail_t, 1> m; Mail<mail_t, 1> m;
mail_t *mail = m.alloc(); mail_t *mail = m.try_alloc();
TEST_ASSERT_EQUAL(false, m.full()); TEST_ASSERT_EQUAL(false, m.full());
@ -490,7 +482,7 @@ utest::v1::status_t test_setup(const size_t number_of_cases)
} }
Case cases[] = { Case cases[] = {
Case("Test calloc", test_calloc), Case("Test try_calloc", test_calloc),
Case("Test message type uint8", test_data_type<uint8_t>), Case("Test message type uint8", test_data_type<uint8_t>),
Case("Test message type uint16", test_data_type<uint16_t>), Case("Test message type uint16", test_data_type<uint16_t>),
Case("Test message type uint32", test_data_type<uint32_t>), Case("Test message type uint32", test_data_type<uint32_t>),

View File

@ -38,44 +38,47 @@ using namespace std::chrono;
} while (0) } while (0)
#define THREAD_STACK_SIZE 512 #define THREAD_STACK_SIZE 512
#define TEST_UINT_MSG 0xDEADBEEF
#define TEST_UINT_MSG2 0xE1EE7
#define TEST_TIMEOUT 50ms #define TEST_TIMEOUT 50ms
static uint32_t msg;
static uint32_t msg2;
void thread_put_uint_msg(Queue<uint32_t, 1> *q) void thread_put_uint_msg(Queue<uint32_t, 1> *q)
{ {
ThisThread::sleep_for(TEST_TIMEOUT); ThisThread::sleep_for(TEST_TIMEOUT);
osStatus stat = q->put((uint32_t *) TEST_UINT_MSG); bool stat = q->try_put(&msg);
TEST_ASSERT_EQUAL(osOK, stat); TEST_ASSERT_TRUE(stat);
} }
void thread_get_uint_msg(Queue<uint32_t, 1> *q) void thread_get_uint_msg(Queue<uint32_t, 1> *q)
{ {
ThisThread::sleep_for(TEST_TIMEOUT); ThisThread::sleep_for(TEST_TIMEOUT);
osEvent evt = q->get(); uint32_t *v;
TEST_ASSERT_EQUAL(osEventMessage, evt.status); bool stat = q->try_get_for(Kernel::wait_for_u32_forever, &v);
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v); TEST_ASSERT_TRUE(stat)
TEST_ASSERT_EQUAL(&msg, v);
} }
/** Test pass uint msg /** Test pass msg
Given a queue for uint32_t messages with one slot Given a queue for uint32_t messages with one slot
When a uin32_t value is inserted into the queue When a uin32_t value is inserted into the queue
and a message is extracted from the queue and a message is extracted from the queue
Then the extracted message is the same as previously inserted message Then the extracted message is the same as previously inserted message
*/ */
void test_pass_uint() void test_pass()
{ {
Queue<uint32_t, 1> q; Queue<uint32_t, 1> q;
osStatus stat = q.put((uint32_t *)TEST_UINT_MSG); bool stat = q.try_put(&msg);
TEST_ASSERT_EQUAL(osOK, stat); TEST_ASSERT_TRUE(stat)
osEvent evt = q.get(); uint32_t *v;
TEST_ASSERT_EQUAL(osEventMessage, evt.status); stat = q.try_get_for(Kernel::wait_for_u32_forever, &v);
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v); TEST_ASSERT_TRUE(stat)
TEST_ASSERT_EQUAL(&msg, v);
} }
/** Test pass uint msg twice /** Test pass msg twice
Given a queue for uint32_t messages with one slot Given a queue for uint32_t messages with one slot
When a uin32_t value is inserted into the queue When a uin32_t value is inserted into the queue
@ -84,56 +87,38 @@ void test_pass_uint()
Then the extracted message is the same as previously inserted message for both iterations Then the extracted message is the same as previously inserted message for both iterations
*/ */
void test_pass_uint_twice() void test_pass_twice()
{ {
Queue<uint32_t, 1> q; Queue<uint32_t, 1> q;
osStatus stat = q.put((uint32_t *)TEST_UINT_MSG); bool stat = q.try_put(&msg);
TEST_ASSERT_EQUAL(osOK, stat); TEST_ASSERT_TRUE(stat);
osEvent evt = q.get(); uint32_t *v;
TEST_ASSERT_EQUAL(osEventMessage, evt.status); stat = q.try_get_for(Kernel::wait_for_u32_forever, &v);
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v); TEST_ASSERT_TRUE(stat);
TEST_ASSERT_EQUAL(&msg, v);
stat = q.put((uint32_t *)TEST_UINT_MSG2); stat = q.try_put(&msg2);
TEST_ASSERT_EQUAL(osOK, stat); TEST_ASSERT_TRUE(stat);
evt = q.get(); stat = q.try_get_for(Kernel::wait_for_u32_forever, &v);
TEST_ASSERT_EQUAL(osEventMessage, evt.status); TEST_ASSERT_TRUE(stat);
TEST_ASSERT_EQUAL(TEST_UINT_MSG2, evt.value.v); TEST_ASSERT_EQUAL(&msg2, v);
}
/** Test pass ptr msg
Given a queue for pointers to uint32_t messages with one slot
When a pointer to an uint32_t is inserted into the queue
and a message is extracted from the queue
Then the extracted message is the same as previously inserted message
*/
void test_pass_ptr()
{
Queue<uint32_t, 1> q;
uint32_t msg = TEST_UINT_MSG;
osStatus stat = q.put(&msg);
TEST_ASSERT_EQUAL(osOK, stat);
osEvent evt = q.get();
TEST_ASSERT_EQUAL(osEventMessage, evt.status);
TEST_ASSERT_EQUAL(&msg, evt.value.p);
} }
/** Test get from empty queue /** Test get from empty queue
Given an empty queue for uint32_t values Given an empty queue for uint32_t values
When @a get is called on the queue with timeout of 0 When @a get is called on the queue with timeout of 0
Then queue returns status of osOK, but no data Then queue returns status of false
*/ */
void test_get_empty_no_timeout() void test_get_empty_no_timeout()
{ {
Queue<uint32_t, 1> q; Queue<uint32_t, 1> q;
osEvent evt = q.get(0ms); uint32_t *v;
TEST_ASSERT_EQUAL(osOK, evt.status); bool stat = q.try_get(&v);
TEST_ASSERT_FALSE(stat);
} }
/** Test get from empty queue with timeout /** Test get from empty queue with timeout
@ -148,8 +133,9 @@ void test_get_empty_timeout()
Timer timer; Timer timer;
timer.start(); timer.start();
osEvent evt = q.get(50ms); uint32_t *v;
TEST_ASSERT_EQUAL(osEventTimeout, evt.status); bool stat = q.try_get_for(50ms, &v);
TEST_ASSERT_FALSE(stat);
TEST_ASSERT_DURATION_WITHIN(5ms, 50ms, timer.elapsed_time()); TEST_ASSERT_DURATION_WITHIN(5ms, 50ms, timer.elapsed_time());
} }
@ -171,9 +157,10 @@ void test_get_empty_wait_forever()
Timer timer; Timer timer;
timer.start(); timer.start();
osEvent evt = q.get(); uint32_t *v;
TEST_ASSERT_EQUAL(osEventMessage, evt.status); bool stat = q.try_get_for(Kernel::wait_for_u32_forever, &v);
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v); TEST_ASSERT_TRUE(stat);
TEST_ASSERT_EQUAL(&msg, v);
TEST_ASSERT_DURATION_WITHIN(TEST_TIMEOUT / 10, TEST_TIMEOUT, timer.elapsed_time()); TEST_ASSERT_DURATION_WITHIN(TEST_TIMEOUT / 10, TEST_TIMEOUT, timer.elapsed_time());
} }
@ -181,37 +168,37 @@ void test_get_empty_wait_forever()
* *
* Given a queue with one slot for uint32_t data * Given a queue with one slot for uint32_t data
* When a thread tries to insert two messages * When a thread tries to insert two messages
* Then first operation succeeds and second fails with @a osErrorResource * Then first operation succeeds and second fails
*/ */
void test_put_full_no_timeout() void test_put_full_no_timeout()
{ {
Queue<uint32_t, 1> q; Queue<uint32_t, 1> q;
osStatus stat = q.put((uint32_t *) TEST_UINT_MSG); bool stat = q.try_put(&msg);
TEST_ASSERT_EQUAL(osOK, stat); TEST_ASSERT_TRUE(stat);
stat = q.put((uint32_t *) TEST_UINT_MSG); stat = q.try_put(&msg);
TEST_ASSERT_EQUAL(osErrorResource, stat); TEST_ASSERT_FALSE(stat);
} }
/** Test put full timeout /** Test put full timeout
* *
* Given a queue with one slot for uint32_t data * Given a queue with one slot for uint32_t data
* When a thread tries to insert two messages with @ TEST_TIMEOUT timeout * When a thread tries to insert two messages with @ TEST_TIMEOUT timeout
* Then first operation succeeds and second fails with @a osErrorTimeout * Then first operation succeeds and second fails
*/ */
void test_put_full_timeout() void test_put_full_timeout()
{ {
Queue<uint32_t, 1> q; Queue<uint32_t, 1> q;
osStatus stat = q.put((uint32_t *) TEST_UINT_MSG, TEST_TIMEOUT); bool stat = q.try_put_for(TEST_TIMEOUT, &msg);
TEST_ASSERT_EQUAL(osOK, stat); TEST_ASSERT_TRUE(stat);
Timer timer; Timer timer;
timer.start(); timer.start();
stat = q.put((uint32_t *) TEST_UINT_MSG, TEST_TIMEOUT); stat = q.try_put_for(TEST_TIMEOUT, &msg);
TEST_ASSERT_EQUAL(osErrorTimeout, stat); TEST_ASSERT_FALSE(stat);
TEST_ASSERT_DURATION_WITHIN(TEST_TIMEOUT / 10, TEST_TIMEOUT, timer.elapsed_time()); TEST_ASSERT_DURATION_WITHIN(TEST_TIMEOUT / 10, TEST_TIMEOUT, timer.elapsed_time());
} }
@ -230,13 +217,13 @@ void test_put_full_waitforever()
t.start(callback(thread_get_uint_msg, &q)); t.start(callback(thread_get_uint_msg, &q));
osStatus stat = q.put((uint32_t *) TEST_UINT_MSG); bool stat = q.try_put(&msg);
TEST_ASSERT_EQUAL(osOK, stat); TEST_ASSERT_TRUE(stat);
Timer timer; Timer timer;
timer.start(); timer.start();
stat = q.put((uint32_t *) TEST_UINT_MSG, Kernel::wait_for_u32_forever); stat = q.try_put_for(Kernel::wait_for_u32_forever, &msg);
TEST_ASSERT_EQUAL(osOK, stat); TEST_ASSERT_TRUE(stat);
TEST_ASSERT_DURATION_WITHIN(TEST_TIMEOUT / 10, TEST_TIMEOUT, timer.elapsed_time()); TEST_ASSERT_DURATION_WITHIN(TEST_TIMEOUT / 10, TEST_TIMEOUT, timer.elapsed_time());
t.join(); t.join();
@ -252,19 +239,20 @@ void test_msg_order()
{ {
Queue<uint32_t, 2> q; Queue<uint32_t, 2> q;
osStatus stat = q.put((uint32_t *) TEST_UINT_MSG, TEST_TIMEOUT); bool stat = q.try_put_for(TEST_TIMEOUT, &msg);
TEST_ASSERT_EQUAL(osOK, stat); TEST_ASSERT_TRUE(stat);
stat = q.put((uint32_t *) TEST_UINT_MSG2, TEST_TIMEOUT); stat = q.try_put_for(TEST_TIMEOUT, &msg2);
TEST_ASSERT_EQUAL(osOK, stat); TEST_ASSERT_TRUE(stat);
osEvent evt = q.get(); uint32_t *v;
TEST_ASSERT_EQUAL(osEventMessage, evt.status); stat = q.try_get(&v);
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v); TEST_ASSERT_TRUE(stat);
TEST_ASSERT_EQUAL(&msg, v);
evt = q.get(); stat = q.try_get(&v);
TEST_ASSERT_EQUAL(osEventMessage, evt.status); TEST_ASSERT_TRUE(stat);
TEST_ASSERT_EQUAL(TEST_UINT_MSG2, evt.value.v); TEST_ASSERT_EQUAL(&msg2, v);
} }
/** Test message priority /** Test message priority
@ -277,19 +265,20 @@ void test_msg_prio()
{ {
Queue<uint32_t, 2> q; Queue<uint32_t, 2> q;
osStatus stat = q.put((uint32_t *) TEST_UINT_MSG, TEST_TIMEOUT, 0); bool stat = q.try_put_for(TEST_TIMEOUT, &msg, 0);
TEST_ASSERT_EQUAL(osOK, stat); TEST_ASSERT_TRUE(stat);
stat = q.put((uint32_t *) TEST_UINT_MSG2, TEST_TIMEOUT, 1); stat = q.try_put_for(TEST_TIMEOUT, &msg2, 1);
TEST_ASSERT_EQUAL(osOK, stat); TEST_ASSERT_TRUE(stat);
osEvent evt = q.get(); uint32_t *v;
TEST_ASSERT_EQUAL(osEventMessage, evt.status); stat = q.try_get(&v);
TEST_ASSERT_EQUAL(TEST_UINT_MSG2, evt.value.v); TEST_ASSERT_TRUE(stat);
TEST_ASSERT_EQUAL(&msg2, v);
evt = q.get(); stat = q.try_get(&v);
TEST_ASSERT_EQUAL(osEventMessage, evt.status); TEST_ASSERT_TRUE(stat);
TEST_ASSERT_EQUAL(TEST_UINT_MSG, evt.value.v); TEST_ASSERT_EQUAL(&msg, v);
} }
/** Test queue empty /** Test queue empty
@ -302,11 +291,11 @@ void test_queue_empty()
{ {
Queue<uint32_t, 1> q; Queue<uint32_t, 1> q;
TEST_ASSERT_EQUAL(true, q.empty()); TEST_ASSERT_TRUE(q.empty());
q.put((uint32_t *) TEST_UINT_MSG, TEST_TIMEOUT, 1); q.try_put_for(TEST_TIMEOUT, &msg, 1);
TEST_ASSERT_EQUAL(false, q.empty()); TEST_ASSERT_FALSE(q.empty());
} }
/** Test queue empty /** Test queue empty
@ -319,11 +308,11 @@ void test_queue_full()
{ {
Queue<uint32_t, 1> q; Queue<uint32_t, 1> q;
TEST_ASSERT_EQUAL(false, q.full()); TEST_ASSERT_FALSE(q.full());
q.put((uint32_t *) TEST_UINT_MSG, TEST_TIMEOUT, 1); q.try_put_for(TEST_TIMEOUT, &msg, 1);
TEST_ASSERT_EQUAL(true, q.full()); TEST_ASSERT_TRUE(q.full());
} }
utest::v1::status_t test_setup(const size_t number_of_cases) utest::v1::status_t test_setup(const size_t number_of_cases)
@ -333,9 +322,8 @@ utest::v1::status_t test_setup(const size_t number_of_cases)
} }
Case cases[] = { Case cases[] = {
Case("Test pass uint msg", test_pass_uint), Case("Test pass msg", test_pass),
Case("Test pass uint msg twice", test_pass_uint_twice), Case("Test pass msg twice", test_pass_twice),
Case("Test pass ptr msg", test_pass_ptr),
Case("Test get from empty queue no timeout", test_get_empty_no_timeout), Case("Test get from empty queue no timeout", test_get_empty_no_timeout),
Case("Test get from empty queue timeout", test_get_empty_timeout), Case("Test get from empty queue timeout", test_get_empty_timeout),
Case("Test get empty wait forever", test_get_empty_wait_forever), Case("Test get empty wait forever", test_get_empty_wait_forever),

View File

@ -705,12 +705,12 @@ void test_msg_get()
TEST_ASSERT_EQUAL(Thread::WaitingMessageGet, t.get_state()); TEST_ASSERT_EQUAL(Thread::WaitingMessageGet, t.get_state());
queue.put((int32_t *)0xE1EE7); queue.try_put((int32_t *)0xE1EE7);
} }
void test_msg_put_thread(Queue<int32_t, 1> *queue) void test_msg_put_thread(Queue<int32_t, 1> *queue)
{ {
queue->put((int32_t *)0xDEADBEEF, Kernel::wait_for_u32_forever); queue->try_put_for(Kernel::wait_for_u32_forever, (int32_t *)0xDEADBEEF);
} }
@ -729,7 +729,7 @@ void test_msg_put()
Thread t(osPriorityNormal, THREAD_STACK_SIZE); Thread t(osPriorityNormal, THREAD_STACK_SIZE);
Queue<int32_t, 1> queue; Queue<int32_t, 1> queue;
queue.put((int32_t *)0xE1EE7); queue.try_put((int32_t *)0xE1EE7);
t.start(callback(test_msg_put_thread, &queue)); t.start(callback(test_msg_put_thread, &queue));

View File

@ -33,6 +33,7 @@
#include "rtos/mbed_rtos1_types.h" #include "rtos/mbed_rtos1_types.h"
#include "platform/mbed_toolchain.h" #include "platform/mbed_toolchain.h"
#include "platform/mbed_assert.h"
#include "platform/NonCopyable.h" #include "platform/NonCopyable.h"
#ifndef MBED_NO_GLOBAL_USING_DIRECTIVE #ifndef MBED_NO_GLOBAL_USING_DIRECTIVE
@ -105,11 +106,25 @@ public:
* @return Pointer to memory block that you can fill with mail or nullptr in case error. * @return Pointer to memory block that you can fill with mail or nullptr in case error.
* *
* @note You may call this function from ISR context. * @note You may call this function from ISR context.
* @note If blocking is required, use Mail::alloc_for or Mail::alloc_until * @note If blocking is required, use Mail::try_alloc_for or Mail::try_alloc_until
* @deprecated Replaced with try_alloc. In future alloc() will be an untimed blocking call.
*/ */
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_alloc. In future alloc() will be an untimed blocking call.")
T *alloc(MBED_UNUSED uint32_t millisec = 0) T *alloc(MBED_UNUSED uint32_t millisec = 0)
{ {
return _pool.alloc(); return try_alloc();
}
/** Allocate a memory block of type T, without blocking.
*
* @return Pointer to memory block that you can fill with mail or nullptr in case error.
*
* @note You may call this function from ISR context.
* @note If blocking is required, use Mail::try_alloc_for or Mail::try_alloc_until
*/
T *try_alloc()
{
return _pool.try_alloc();
} }
/** Allocate a memory block of type T, optionally blocking. /** Allocate a memory block of type T, optionally blocking.
@ -120,9 +135,9 @@ public:
* *
* @note You may call this function from ISR context if the millisec parameter is set to 0. * @note You may call this function from ISR context if the millisec parameter is set to 0.
*/ */
T *alloc_for(Kernel::Clock::duration_u32 rel_time) T *try_alloc_for(Kernel::Clock::duration_u32 rel_time)
{ {
return _pool.alloc_for(rel_time); return _pool.try_alloc_for(rel_time);
} }
/** Allocate a memory block of type T, optionally blocking. /** Allocate a memory block of type T, optionally blocking.
@ -137,7 +152,7 @@ public:
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.") MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.")
T *alloc_for(uint32_t millisec) T *alloc_for(uint32_t millisec)
{ {
return alloc_for(std::chrono::duration<uint32_t, std::milli>(millisec)); return try_alloc_for(std::chrono::duration<uint32_t, std::milli>(millisec));
} }
/** Allocate a memory block of type T, blocking. /** Allocate a memory block of type T, blocking.
@ -152,9 +167,9 @@ public:
* wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded, * wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
* the wait will time out earlier than specified. * the wait will time out earlier than specified.
*/ */
T *alloc_until(Kernel::Clock::time_point abs_time) T *try_alloc_until(Kernel::Clock::time_point abs_time)
{ {
return _pool.alloc_until(abs_time); return _pool.try_alloc_until(abs_time);
} }
/** Allocate a memory block of type T, blocking. /** Allocate a memory block of type T, blocking.
@ -174,7 +189,7 @@ public:
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.") MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.")
T *alloc_until(uint64_t millisec) T *alloc_until(uint64_t millisec)
{ {
return alloc_until(Kernel::Clock::time_point(std::chrono::duration<uint64_t, std::milli>(millisec))); return try_alloc_until(Kernel::Clock::time_point(std::chrono::duration<uint64_t, std::milli>(millisec)));
} }
/** Allocate a memory block of type T, and set memory block to zero. /** Allocate a memory block of type T, and set memory block to zero.
@ -183,12 +198,26 @@ public:
* *
* @return Pointer to memory block that you can fill with mail or nullptr in case error. * @return Pointer to memory block that you can fill with mail or nullptr in case error.
* *
* @note You may call this function from ISR context if the millisec parameter is set to 0. * @note You may call this function from ISR context.
* @note If blocking is required, use Mail::calloc_for or Mail::calloc_until * @note If blocking is required, use Mail::try_calloc_for or Mail::try_calloc_until
* @deprecated Replaced with try_calloc. In future calloc() will be an untimed blocking call.
*/ */
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_calloc. In future calloc() will be an untimed blocking call.")
T *calloc(MBED_UNUSED uint32_t millisec = 0) T *calloc(MBED_UNUSED uint32_t millisec = 0)
{ {
return _pool.calloc(); return try_calloc();
}
/** Allocate a memory block of type T, and set memory block to zero.
*
* @return Pointer to memory block that you can fill with mail or nullptr in case error.
*
* @note You may call this function from ISR context.
* @note If blocking is required, use Mail::try_calloc_for or Mail::try_calloc_until
*/
T *try_calloc()
{
return _pool.try_calloc();
} }
/** Allocate a memory block of type T, optionally blocking, and set memory block to zero. /** Allocate a memory block of type T, optionally blocking, and set memory block to zero.
@ -199,9 +228,9 @@ public:
* *
* @note You may call this function from ISR context if the rel_time parameter is set to 0. * @note You may call this function from ISR context if the rel_time parameter is set to 0.
*/ */
T *calloc_for(Kernel::Clock::duration_u32 rel_time) T *try_calloc_for(Kernel::Clock::duration_u32 rel_time)
{ {
return _pool.alloc_for(rel_time); return _pool.try_calloc_for(rel_time);
} }
/** Allocate a memory block of type T, optionally blocking, and set memory block to zero. /** Allocate a memory block of type T, optionally blocking, and set memory block to zero.
@ -216,7 +245,7 @@ public:
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.") MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.")
T *calloc_for(uint32_t millisec) T *calloc_for(uint32_t millisec)
{ {
return calloc_for(std::chrono::duration<uint32_t, std::milli>(millisec)); return try_calloc_for(std::chrono::duration<uint32_t, std::milli>(millisec));
} }
/** Allocate a memory block of type T, blocking, and set memory block to zero. /** Allocate a memory block of type T, blocking, and set memory block to zero.
@ -231,9 +260,9 @@ public:
* wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded, * wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
* the wait will time out earlier than specified. * the wait will time out earlier than specified.
*/ */
T *calloc_until(Kernel::Clock::time_point abs_time) T *try_calloc_until(Kernel::Clock::time_point abs_time)
{ {
return _pool.calloc_until(abs_time); return _pool.try_calloc_until(abs_time);
} }
/** Allocate a memory block of type T, blocking, and set memory block to zero. /** Allocate a memory block of type T, blocking, and set memory block to zero.
@ -253,7 +282,7 @@ public:
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.") MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.")
T *calloc_until(uint64_t millisec) T *calloc_until(uint64_t millisec)
{ {
return calloc_until(Kernel::Clock::time_point(std::chrono::duration<uint64_t, std::milli>(millisec))); return try_calloc_until(Kernel::Clock::time_point(std::chrono::duration<uint64_t, std::milli>(millisec)));
} }
/** Put a mail in the queue. /** Put a mail in the queue.
@ -261,31 +290,19 @@ public:
* @param mptr Memory block previously allocated with Mail::alloc or Mail::calloc. * @param mptr Memory block previously allocated with Mail::alloc or Mail::calloc.
* *
* @return Status code that indicates the execution status of the function (osOK on success). * @return Status code that indicates the execution status of the function (osOK on success).
* See note.
* *
* @note You may call this function from ISR context. * @note You may call this function from ISR context.
* @note As the mail should have already been allocated, and the memory pool is the same size
* as the queue, the put operation should always succeed, despite being implemented with
* Queue::try_put - there is room in the queue for every mail from the pool. Therefore
* use of the return value is deprecated, and the function will return void in future.
*/ */
osStatus put(T *mptr) osStatus put(T *mptr)
{ {
return _queue.put(mptr); bool ok = _queue.try_put(mptr);
} MBED_ASSERT(ok);
return ok ? osOK : osErrorResource;
/** Get a mail from the queue.
*
* @param millisec Timeout value.
*
* @return Event that contains mail information or error code.
* @retval osEventMessage Message received.
* @retval osOK No mail is available (and no timeout was specified).
* @retval osEventTimeout No mail has arrived during the given timeout period.
* @retval osErrorParameter A parameter is invalid or outside of a permitted range.
*
* @note You may call this function from ISR context if the millisec parameter is set to 0.
* @deprecated Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.
*/
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.")
osEvent get(uint32_t millisec)
{
return get(std::chrono::duration<uint32_t, std::milli>(millisec));
} }
/** Get a mail from the queue. /** Get a mail from the queue.
@ -300,16 +317,46 @@ public:
* @a osErrorParameter A parameter is invalid or outside of a permitted range. * @a osErrorParameter A parameter is invalid or outside of a permitted range.
* *
* @note You may call this function from ISR context if the millisec parameter is set to 0. * @note You may call this function from ISR context if the millisec parameter is set to 0.
* @deprecated Replaced with try_get and try_get_for. In future get will be an untimed blocking call.
*/ */
osEvent get(Kernel::Clock::duration_u32 rel_time = Kernel::wait_for_u32_forever) MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_get and try_get_for. In future get will be an untimed blocking call.")
osEvent get(uint32_t millisec = osWaitForever)
{ {
osEvent evt = _queue.get(rel_time); osEvent evt = _queue.get(millisec);
if (evt.status == osEventMessage) { if (evt.status == osEventMessage) {
evt.status = osEventMail; evt.status = osEventMail;
} }
return evt; return evt;
} }
/** Get a mail from the queue.
*
* @return Pointer to received mail, or nullptr if none was received.
*
* @note You may call this function from ISR context.
*/
T *try_get()
{
T *mptr = nullptr;
_queue.try_get(&mptr);
return mptr;
}
/** Get a mail from the queue.
*
* @param rel_time Timeout value or Kernel::wait_for_u32_forever.
*
* @return Pointer to received mail, or nullptr if none was received.
*
* @note You may call this function from ISR context if the millisec parameter is set to 0.
*/
T *try_get_for(Kernel::Clock::duration_u32 rel_time)
{
T *mptr = nullptr;
_queue.try_get_for(rel_time, &mptr);
return mptr;
}
/** Free a memory block from a mail. /** Free a memory block from a mail.
* *
* @param mptr Pointer to the memory block that was obtained with Mail::get. * @param mptr Pointer to the memory block that was obtained with Mail::get.

View File

@ -88,10 +88,12 @@ public:
@return address of the allocated memory block or nullptr in case of no memory available. @return address of the allocated memory block or nullptr in case of no memory available.
@note You may call this function from ISR context. @note You may call this function from ISR context.
@deprecated Replaced with try_alloc. In future alloc() will be an untimed blocking call.
*/ */
T *alloc(void) MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_alloc. In future alloc() will be an untimed blocking call.")
T *alloc()
{ {
return (T *)osMemoryPoolAlloc(_id, 0); return try_alloc();
} }
/** Allocate a memory block from a memory pool, without blocking. /** Allocate a memory block from a memory pool, without blocking.
@ -99,7 +101,7 @@ public:
@note You may call this function from ISR context. @note You may call this function from ISR context.
*/ */
T *try_alloc(void) T *try_alloc()
{ {
return (T *)osMemoryPoolAlloc(_id, 0); return (T *)osMemoryPoolAlloc(_id, 0);
} }
@ -123,7 +125,7 @@ public:
@note You may call this function from ISR context if the rel_time parameter is set to 0. @note You may call this function from ISR context if the rel_time parameter is set to 0.
*/ */
T *alloc_for(Kernel::Clock::duration_u32 rel_time) T *try_alloc_for(Kernel::Clock::duration_u32 rel_time)
{ {
return (T *)osMemoryPoolAlloc(_id, rel_time.count()); return (T *)osMemoryPoolAlloc(_id, rel_time.count());
} }
@ -156,7 +158,7 @@ public:
wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded, wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
the wait will time out earlier than specified. the wait will time out earlier than specified.
*/ */
T *alloc_until(Kernel::Clock::time_point abs_time) T *try_alloc_until(Kernel::Clock::time_point abs_time)
{ {
Kernel::Clock::time_point now = Kernel::Clock::now(); Kernel::Clock::time_point now = Kernel::Clock::now();
Kernel::Clock::duration_u32 rel_time; Kernel::Clock::duration_u32 rel_time;
@ -167,16 +169,28 @@ public:
} else { } else {
rel_time = abs_time - now; rel_time = abs_time - now;
} }
return alloc_for(rel_time); return try_alloc_for(rel_time);
} }
/** Allocate a memory block from a memory pool, without blocking, and set memory block to zero. /** Allocate a memory block from a memory pool, without blocking, and set memory block to zero.
@return address of the allocated memory block or nullptr in case of no memory available. @return address of the allocated memory block or nullptr in case of no memory available.
@note You may call this function from ISR context. @note You may call this function from ISR context.
@deprecated Replaced with try_calloc. In future calloc() will be an untimed blocking call.
*/ */
T *calloc(void) MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_calloc. In future calloc() will be an untimed blocking call.")
T *calloc()
{ {
T *item = alloc(); return try_calloc();
}
/** Allocate a memory block from a memory pool, without blocking, and set memory block to zero.
@return address of the allocated memory block or nullptr in case of no memory available.
@note You may call this function from ISR context.
*/
T *try_calloc()
{
T *item = try_alloc();
if (item != nullptr) { if (item != nullptr) {
memset(item, 0, sizeof(T)); memset(item, 0, sizeof(T));
} }
@ -202,7 +216,7 @@ public:
@note You may call this function from ISR context if the rel_time parameter is set to 0. @note You may call this function from ISR context if the rel_time parameter is set to 0.
*/ */
T *calloc_for(Kernel::Clock::duration_u32 rel_time) T *try_calloc_for(Kernel::Clock::duration_u32 rel_time)
{ {
T *item = alloc_for(rel_time); T *item = alloc_for(rel_time);
if (item != nullptr) { if (item != nullptr) {
@ -239,7 +253,7 @@ public:
wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded, wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
the wait will time out earlier than specified. the wait will time out earlier than specified.
*/ */
T *calloc_until(Kernel::Clock::time_point abs_time) T *try_calloc_until(Kernel::Clock::time_point abs_time)
{ {
T *item = alloc_until(abs_time); T *item = alloc_until(abs_time);
if (item != nullptr) { if (item != nullptr) {

View File

@ -122,6 +122,27 @@ public:
return osMessageQueueGetCount(_id); return osMessageQueueGetCount(_id);
} }
/** Inserts the given element to the end of the queue.
*
* This function puts the message pointed to by `data` into the queue. The
* parameter `prio` is used to sort the message according to their priority
* (higher numbers indicate higher priority) on insertion.
*
* The function does not block, and returns immediately if the queue is full.
*
* @param data Pointer to the element to insert into the queue.
* @param prio Priority of the operation or 0 in case of default.
* (default: 0)
*
* @return true if the element was inserted, false otherwise.
*
* @note You may call this function from ISR context.
*/
bool try_put(T *data, uint8_t prio = 0)
{
return try_put_for(Kernel::Clock::duration_u32::zero(), data, prio);
}
/** Inserts the given element to the end of the queue. /** Inserts the given element to the end of the queue.
* *
* This function puts the message pointed to by `data` into the queue. The * This function puts the message pointed to by `data` into the queue. The
@ -133,34 +154,27 @@ public:
* queue. * queue.
* *
* The parameter `rel_time` can have the following values: * The parameter `rel_time` can have the following values:
* - When the duration is 0 (the default), the function returns instantly. * - When the duration is 0, the function returns instantly. You could use
* `try_put` instead.
* - When the duration is Kernel::wait_for_u32_forever, the function waits for an * - When the duration is Kernel::wait_for_u32_forever, the function waits for an
* infinite time. * infinite time.
* - For all other values, the function waits for the given duration. * - For all other values, the function waits for the given duration.
* *
* @param rel_time Timeout for the operation to be executed.
* @param data Pointer to the element to insert into the queue. * @param data Pointer to the element to insert into the queue.
* @param rel_time Timeout for the operation to be executed, or 0 in case
* of no timeout. (default: 0)
* @param prio Priority of the operation or 0 in case of default. * @param prio Priority of the operation or 0 in case of default.
* (default: 0) * (default: 0)
* *
* @return Status code that indicates the execution status of the function: * @return true if the element was inserted, false otherwise.
* @a osOK The message has been successfully inserted
* into the queue.
* @a osErrorTimeout The message could not be inserted into the
* queue in the given time.
* @a osErrorResource The message could not be inserted because
* the queue is full.
* @a osErrorParameter Internal error or nonzero timeout specified
* in an ISR.
* *
* @note You may call this function from ISR context if the rel_time * @note You may call this function from ISR context if the rel_time
* parameter is set to 0. * parameter is set to 0.
* *
*/ */
osStatus put(T *data, Kernel::Clock::duration_u32 rel_time = Kernel::Clock::duration_u32::zero(), uint8_t prio = 0) bool try_put_for(Kernel::Clock::duration_u32 rel_time, T *data, uint8_t prio = 0)
{ {
return osMessageQueuePut(_id, &data, prio, rel_time.count()); osStatus status = osMessageQueuePut(_id, &data, prio, rel_time.count());
return status == osOK;
} }
/** Inserts the given element to the end of the queue. /** Inserts the given element to the end of the queue.
@ -198,25 +212,43 @@ public:
* *
* @note You may call this function from ISR context if the millisec * @note You may call this function from ISR context if the millisec
* parameter is set to 0. * parameter is set to 0.
* @deprecated Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`. * @deprecated Replaced with try_put and try_put_for. In future put will be an untimed blocking call.
*/ */
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.") MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_put and try_put_for. In future put will be an untimed blocking call.")
osStatus put(T *data, uint32_t millisec, uint8_t prio = 0) osStatus put(T *data, uint32_t millisec = 0, uint8_t prio = 0)
{ {
return put(data, std::chrono::duration<uint32_t, std::milli>(millisec), prio); return osMessageQueuePut(_id, &data, prio, millisec);
}
/** Get a message from the queue.
*
* This function retrieves a message from the queue. The message is stored
* in the location pointed to be the parameter `data_out`.
*
* The function does not block, and returns immediately if the queue is empty.
*
* @param[out] data_out Pointer to location to write the element retrieved from the queue.
*
* @return true if an element was received and written to data_out.
*
* @note You may call this function from ISR context.
*/
bool try_get(T **data_out)
{
return try_get_for(Kernel::Clock::duration_u32::zero(), data_out);
} }
/** Get a message or wait for a message from the queue. /** Get a message or wait for a message from the queue.
* *
* This function retrieves a message from the queue. The message is stored * This function retrieves a message from the queue. The message is stored
* in the value field of the returned `osEvent` object. * in the location pointed to be the parameter `data_out`.
* *
* The timeout specified by the parameter `rel_time` specifies how long the * The timeout specified by the parameter `rel_time` specifies how long the
* function waits to retrieve the message from the queue. * function waits to retrieve the message from the queue.
* *
* The timeout parameter can have the following values: * The timeout parameter can have the following values:
* - When the timeout is 0, the function returns instantly. * - When the timeout is 0, the function returns instantly.
* - When the timeout is Kernel::wait_for_u32_forever (default), the function waits * - When the timeout is Kernel::wait_for_u32_forever, the function waits
* infinite time until the message is retrieved. * infinite time until the message is retrieved.
* - When the timeout is any other value, the function waits for the * - When the timeout is any other value, the function waits for the
* specified time before returning a timeout error. * specified time before returning a timeout error.
@ -226,46 +258,17 @@ public:
* (FIFO) order. * (FIFO) order.
* *
* @param rel_time Timeout value. * @param rel_time Timeout value.
* (default: Kernel::wait_for_u32_forever). * @param[out] data_out Pointer to location to write the element retrieved from the queue.
* *
* @return Event information that includes the message in event. Message * @return true if an element was received and written to data_out.
* value and the status code in event.status:
* @a osEventMessage Message successfully received.
* @a osOK No message is available in the queue, and no
* timeout was specified.
* @a osEventTimeout No message was received before a timeout
* event occurred.
* @a osErrorParameter A parameter is invalid or outside of a
* permitted range.
* *
* @note You may call this function from ISR context if the rel_time * @note You may call this function from ISR context if the rel_time
* parameter is set to 0. * parameter is set to 0.
*/ */
osEvent get(Kernel::Clock::duration_u32 rel_time = Kernel::wait_for_u32_forever) bool try_get_for(Kernel::Clock::duration_u32 rel_time, T **data_out)
{ {
osEvent event; osStatus status = osMessageQueueGet(_id, data_out, nullptr, rel_time.count());
T *data = nullptr; return status == osOK;
osStatus_t res = osMessageQueueGet(_id, &data, nullptr, rel_time.count());
switch (res) {
case osOK:
event.status = (osStatus)osEventMessage;
event.value.p = data;
break;
case osErrorResource:
event.status = osOK;
break;
case osErrorTimeout:
event.status = (osStatus)osEventTimeout;
break;
case osErrorParameter:
default:
event.status = osErrorParameter;
break;
}
event.def.message_id = _id;
return event;
} }
/** Get a message or wait for a message from the queue. /** Get a message or wait for a message from the queue.
@ -301,12 +304,34 @@ public:
* *
* @note You may call this function from ISR context if the millisec * @note You may call this function from ISR context if the millisec
* parameter is set to 0. * parameter is set to 0.
* @deprecated Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`. * @deprecated Replaced with try_get and try_get_for. In future get will be an untimed blocking call.
*/ */
MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.") MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_get and try_get_for. In future get will be an untimed blocking call.")
osEvent get(uint32_t millisec) osEvent get(uint32_t millisec = osWaitForever)
{ {
return get(std::chrono::duration<uint32_t, std::milli>(millisec)); osEvent event;
T *data = nullptr;
osStatus_t res = osMessageQueueGet(_id, &data, nullptr, millisec);
switch (res) {
case osOK:
event.status = (osStatus)osEventMessage;
event.value.p = data;
break;
case osErrorResource:
event.status = osOK;
break;
case osErrorTimeout:
event.status = (osStatus)osEventTimeout;
break;
case osErrorParameter:
default:
event.status = osErrorParameter;
break;
}
event.def.message_id = _id;
return event;
} }
private: private:
osMessageQueueId_t _id; osMessageQueueId_t _id;