Add Chrono support to Queue,MemoryPool,Mail

pull/12425/head
Kevin Bracey 2020-02-13 11:07:12 +02:00
parent f6e8ecadec
commit 4575ad3f23
3 changed files with 292 additions and 48 deletions

View File

@ -70,7 +70,7 @@ public:
*
* @note You cannot call this function from ISR context.
*/
Mail() { };
Mail() = default;
/** Check if the mail queue is empty.
*
@ -114,15 +114,47 @@ public:
/** Allocate a memory block of type T, optionally blocking.
*
* @param millisec Timeout value, or osWaitForever.
* @param rel_time Timeout value, or Kernel::wait_for_u32_forever.
*
* @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.
*/
T *alloc_for(Kernel::Clock::duration_u32 rel_time)
{
return _pool.alloc_for(rel_time);
}
/** Allocate a memory block of type T, optionally blocking.
*
* @param millisec Timeout value, or osWaitForever.
*
* @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.
* @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`.")
T *alloc_for(uint32_t millisec)
{
return _pool.alloc_for(millisec);
return alloc_for(std::chrono::duration<uint32_t, std::milli>(millisec));
}
/** Allocate a memory block of type T, blocking.
*
* @param abs_time Absolute timeout time, referenced to Kernel::Clock.
*
* @return Pointer to memory block that you can fill with mail or nullptr in case error.
*
* @note You cannot call this function from ISR context.
* @note the underlying RTOS may have a limit to the maximum wait time
* due to internal 32-bit computations, but this is guaranteed to work if the
* wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
* the wait will time out earlier than specified.
*/
T *alloc_until(Kernel::Clock::time_point abs_time)
{
return _pool.alloc_until(abs_time);
}
/** Allocate a memory block of type T, blocking.
@ -136,10 +168,13 @@ public:
* due to internal 32-bit computations, but this is guaranteed to work if the
* wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
* the wait will time out earlier than specified.
* @deprecated 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)
{
return _pool.alloc_until(millisec);
return 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.
@ -156,6 +191,19 @@ public:
return _pool.calloc();
}
/** Allocate a memory block of type T, optionally blocking, and set memory block to zero.
*
* @param rel_time Timeout value, or Kernel::wait_for_u32_forever.
*
* @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 rel_time parameter is set to 0.
*/
T *calloc_for(Kernel::Clock::duration_u32 rel_time)
{
return _pool.alloc_for(rel_time);
}
/** Allocate a memory block of type T, optionally blocking, and set memory block to zero.
*
* @param millisec Timeout value, or osWaitForever.
@ -163,10 +211,29 @@ public:
* @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.
* @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`.")
T *calloc_for(uint32_t millisec)
{
return _pool.calloc_for(millisec);
return calloc_for(std::chrono::duration<uint32_t, std::milli>(millisec));
}
/** Allocate a memory block of type T, blocking, and set memory block to zero.
*
* @param abs_time Absolute timeout time, referenced to Kernel::Clock.
*
* @return Pointer to memory block that you can fill with mail or nullptr in case error.
*
* @note You cannot call this function from ISR context.
* @note the underlying RTOS may have a limit to the maximum wait time
* due to internal 32-bit computations, but this is guaranteed to work if the
* wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
* the wait will time out earlier than specified.
*/
T *calloc_until(Kernel::Clock::time_point abs_time)
{
return _pool.calloc_until(abs_time);
}
/** Allocate a memory block of type T, blocking, and set memory block to zero.
@ -180,10 +247,13 @@ public:
* due to internal 32-bit computations, but this is guaranteed to work if the
* wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
* the wait will time out earlier than specified.
* @deprecated 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)
{
return _pool.calloc_until(millisec);
return calloc_until(Kernel::Clock::time_point(std::chrono::duration<uint64_t, std::milli>(millisec)));
}
/** Put a mail in the queue.
@ -201,7 +271,26 @@ public:
/** Get a mail from the queue.
*
* @param millisec Timeout value (default: osWaitForever).
* @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.
*
* @param rel_time Timeout value (default: Kernel::wait_for_u32_forever).
*
* @return Event that contains mail information and status code. The status code
* is stored in the status member:
@ -212,9 +301,9 @@ public:
*
* @note You may call this function from ISR context if the millisec parameter is set to 0.
*/
osEvent get(uint32_t millisec = osWaitForever)
osEvent get(Kernel::Clock::duration_u32 rel_time = Kernel::wait_for_u32_forever)
{
osEvent evt = _queue.get(millisec);
osEvent evt = _queue.get(rel_time);
if (evt.status == osEventMessage) {
evt.status = osEventMail;
}

View File

@ -94,15 +94,38 @@ public:
return (T *)osMemoryPoolAlloc(_id, 0);
}
/** Allocate a memory block from a memory pool, without blocking.
@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_alloc(void)
{
return (T *)osMemoryPoolAlloc(_id, 0);
}
/** Allocate a memory block from a memory pool, optionally blocking.
@param millisec timeout value (osWaitForever to wait forever)
@return address of the allocated memory block or nullptr in case of no memory available.
@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`.")
T *alloc_for(uint32_t millisec)
{
return (T *)osMemoryPoolAlloc(_id, millisec);
return alloc_for(std::chrono::duration<uint32_t, std::milli>(millisec));
}
/** Allocate a memory block from a memory pool, optionally blocking.
@param rel_time timeout value (Kernel::wait_for_u32_forever to wait forever)
@return address of the allocated memory block or nullptr in case of no memory available.
@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)
{
return (T *)osMemoryPoolAlloc(_id, rel_time.count());
}
/** Allocate a memory block from a memory pool, blocking.
@ -114,21 +137,38 @@ public:
due to internal 32-bit computations, but this is guaranteed to work if the
wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
the wait will time out earlier than specified.
@deprecated 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)
{
uint64_t now = Kernel::get_ms_count();
uint32_t delay;
if (now >= millisec) {
delay = 0;
} else if (millisec - now >= osWaitForever) {
delay = osWaitForever - 1;
} else {
delay = millisec - now;
}
return alloc_for(delay);
return alloc_until(Kernel::Clock::time_point(std::chrono::duration<uint64_t, std::milli>(millisec)));
}
/** Allocate a memory block from a memory pool, blocking.
@param abs_time absolute timeout time, referenced to Kernel::Clock.
@return address of the allocated memory block or nullptr in case of no memory available.
@note You cannot call this function from ISR context.
@note the underlying RTOS may have a limit to the maximum wait time
due to internal 32-bit computations, but this is guaranteed to work if the
wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
the wait will time out earlier than specified.
*/
T *alloc_until(Kernel::Clock::time_point abs_time)
{
Kernel::Clock::time_point now = Kernel::Clock::now();
Kernel::Clock::duration_u32 rel_time;
if (now >= abs_time) {
rel_time = rel_time.zero();
} else if (abs_time - now > Kernel::wait_for_u32_max) {
rel_time = Kernel::wait_for_u32_max;
} else {
rel_time = abs_time - now;
}
return alloc_for(rel_time);
}
/** 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.
@ -148,10 +188,23 @@ public:
@return address of the allocated memory block or nullptr in case of no memory available.
@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`.")
T *calloc_for(uint32_t millisec)
{
T *item = alloc_for(millisec);
return calloc_for(std::chrono::duration<uint32_t, std::milli>(millisec));
}
/** Allocate a memory block from a memory pool, optionally blocking, and set memory block to zero.
@param rel_time timeout value (Kernel::wait_for_u32_forever to wait forever)
@return address of the allocated memory block or nullptr in case of no memory available.
@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 *item = alloc_for(rel_time);
if (item != nullptr) {
memset(item, 0, sizeof(T));
}
@ -167,10 +220,28 @@ public:
due to internal 32-bit computations, but this is guaranteed to work if the
wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
the wait will time out earlier than specified.
@deprecated 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 *item = alloc_until(millisec);
return alloc_until(Kernel::Clock::time_point(std::chrono::duration<uint64_t, std::milli>(millisec)));
}
/** Allocate a memory block from a memory pool, blocking, and set memory block to zero.
@param abs_time absolute timeout time, referenced to Kernel::Clock.
@return address of the allocated memory block or nullptr in case of no memory available.
@note You cannot call this function from ISR context.
@note the underlying RTOS may have a limit to the maximum wait time
due to internal 32-bit computations, but this is guaranteed to work if the
wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
the wait will time out earlier than specified.
*/
T *calloc_until(Kernel::Clock::time_point abs_time)
{
T *item = alloc_until(abs_time);
if (item != nullptr) {
memset(item, 0, sizeof(T));
}

View File

@ -26,6 +26,7 @@
#include "rtos/mbed_rtos_types.h"
#include "rtos/mbed_rtos1_types.h"
#include "rtos/mbed_rtos_storage.h"
#include "rtos/Kernel.h"
#include "platform/mbed_error.h"
#include "platform/NonCopyable.h"
@ -121,6 +122,47 @@ public:
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 timeout indicated by the parameter `rel_time` specifies how long the
* function blocks waiting for the message to be inserted into the
* queue.
*
* The parameter `rel_time` can have the following values:
* - When the duration is 0 (the default), the function returns instantly.
* - When the duration is Kernel::wait_for_u32_forever, the function waits for an
* infinite time.
* - For all other values, the function waits for the given duration.
*
* @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.
* (default: 0)
*
* @return Status code that indicates the execution status of the function:
* @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
* parameter is set to 0.
*
*/
osStatus put(T *data, Kernel::Clock::duration_u32 rel_time = Kernel::Clock::duration_u32::zero(), uint8_t prio = 0)
{
return osMessageQueuePut(_id, &data, prio, rel_time.count());
}
/** Inserts the given element to the end of the queue.
*
* This function puts the message pointed to by `data` into the queue. The
@ -156,11 +198,74 @@ public:
*
* @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`.")
osStatus put(T *data, uint32_t millisec = 0, uint8_t prio = 0)
{
return osMessageQueuePut(_id, &data, prio, millisec);
return put(data, std::chrono::duration<uint32_t, std::milli>(millisec), prio);
}
/** Get a message or wait for a message from the queue.
*
* This function retrieves a message from the queue. The message is stored
* in the value field of the returned `osEvent` object.
*
* The timeout specified by the parameter `rel_time` specifies how long the
* function waits to retrieve the message from the queue.
*
* The timeout parameter can have the following values:
* - When the timeout is 0, the function returns instantly.
* - When the timeout is Kernel::wait_for_u32_forever (default), the function waits
* infinite time until the message is retrieved.
* - When the timeout is any other value, the function waits for the
* specified time before returning a timeout error.
*
* Messages are retrieved in descending priority order. If two messages
* share the same priority level, they are retrieved in first-in, first-out
* (FIFO) order.
*
* @param rel_time Timeout value.
* (default: Kernel::wait_for_u32_forever).
*
* @return Event information that includes the message in event. Message
* 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
* parameter is set to 0.
*/
osEvent get(Kernel::Clock::duration_u32 rel_time = Kernel::wait_for_u32_forever)
{
osEvent event;
T *data = nullptr;
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.
@ -197,34 +302,13 @@ public:
*
* @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 = osWaitForever)
{
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;
return get(std::chrono::duration<uint32_t, std::milli>(millisec));
}
private:
osMessageQueueId_t _id;
char _queue_mem[queue_sz * (sizeof(T *) + sizeof(mbed_rtos_storage_message_t))];