lib: cmsis_rtos_v2: Fix timing and logic for osEventFlagsWait.

Consistently use ticks for timing purposes.
Fix retry logic.
Check flags when osFlagsWaitAll is not set.

Fixes #31103

Signed-off-by: Artur Lipowski <Artur.Lipowski@hidglobal.com>
This commit is contained in:
Artur Lipowski 2021-03-11 16:51:33 +01:00 committed by Anas Nashif
commit 3b269bb033

View file

@ -18,8 +18,7 @@ static const osEventFlagsAttr_t init_event_flags_attrs = {
.cb_size = 0, .cb_size = 0,
}; };
#define DONT_CARE (0) #define DONT_CARE (0)
#define NSEC_PER_MSEC (NSEC_PER_USEC * USEC_PER_MSEC)
/** /**
* @brief Create and Initialize an Event Flags object. * @brief Create and Initialize an Event Flags object.
@ -37,7 +36,7 @@ osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr)
} }
if (k_mem_slab_alloc(&cv2_event_flags_slab, (void **)&events, K_MSEC(100)) if (k_mem_slab_alloc(&cv2_event_flags_slab, (void **)&events, K_MSEC(100))
== 0) { == 0) {
memset(events, 0, sizeof(struct cv2_event_flags)); memset(events, 0, sizeof(struct cv2_event_flags));
} else { } else {
return NULL; return NULL;
@ -66,7 +65,7 @@ uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags)
struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id;
int key; int key;
if ((ef_id == NULL) || (flags & 0x80000000)) { if ((ef_id == NULL) || (flags & osFlagsError)) {
return osFlagsErrorParameter; return osFlagsErrorParameter;
} }
@ -88,7 +87,7 @@ uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags)
int key; int key;
uint32_t sig; uint32_t sig;
if ((ef_id == NULL) || (flags & 0x80000000)) { if ((ef_id == NULL) || (flags & osFlagsError)) {
return osFlagsErrorParameter; return osFlagsErrorParameter;
} }
@ -109,91 +108,98 @@ uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags,
struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id;
int retval, key; int retval, key;
uint32_t sig; uint32_t sig;
uint32_t time_delta_ms, timeout_ms = k_ticks_to_ms_floor64(timeout); k_timeout_t poll_timeout;
uint64_t time_stamp_start, hwclk_cycles_delta, time_delta_ns; uint64_t time_stamp_start, ticks_elapsed;
bool flags_are_set;
/* Can be called from ISRs only if timeout is set to 0 */ /* Can be called from ISRs only if timeout is set to 0 */
if (timeout > 0 && k_is_in_isr()) { if (timeout > 0 && k_is_in_isr()) {
return osFlagsErrorUnknown; return osFlagsErrorUnknown;
} }
if ((ef_id == NULL) || (flags & 0x80000000)) { if ((ef_id == NULL) || (flags & osFlagsError)) {
return osFlagsErrorParameter; return osFlagsErrorParameter;
} }
time_stamp_start = (uint64_t)k_uptime_ticks();
for (;;) { for (;;) {
time_stamp_start = (uint64_t)k_cycle_get_32(); flags_are_set = false;
switch (timeout) { key = irq_lock();
case 0:
retval = k_poll(&events->poll_event, 1, K_NO_WAIT); if (options & osFlagsWaitAll) {
break; /* Check if all events we are waiting on have
case osWaitForever: * been signalled
retval = k_poll(&events->poll_event, 1, K_FOREVER); */
break; if ((events->signal_results & flags) == flags) {
default: flags_are_set = true;
retval = k_poll(&events->poll_event, 1, }
K_MSEC(timeout_ms)); } else {
break; /* Check if any of events we are waiting on have
* been signalled
*/
if (events->signal_results & flags) {
flags_are_set = true;
}
} }
switch (retval) { if (flags_are_set) {
case 0: sig = events->signal_results;
break;
case -EAGAIN:
return osFlagsErrorTimeout;
default:
return osFlagsErrorUnknown;
}
__ASSERT(events->poll_event.state == K_POLL_STATE_SIGNALED, if (!(options & osFlagsNoClear)) {
"event state not signalled!"); /* Clear signal flags as the thread is ready now */
__ASSERT(events->poll_event.signal->signaled == 1U, events->signal_results &= ~(flags);
"event signaled is not 1"); }
irq_unlock(key);
break;
}
/* Reset the states to facilitate the next trigger */ /* Reset the states to facilitate the next trigger */
events->poll_event.signal->signaled = 0U; events->poll_event.signal->signaled = 0U;
events->poll_event.state = K_POLL_STATE_NOT_READY; events->poll_event.state = K_POLL_STATE_NOT_READY;
if (options & osFlagsWaitAll) { irq_unlock(key);
/* Check if all events we are waiting on have
* been signalled
*/
if ((events->signal_results & flags) == flags) {
break;
}
if (timeout == 0) {
return osFlagsErrorTimeout;
} else if (timeout == osWaitForever) {
poll_timeout = Z_FOREVER;
} else {
/* If we need to wait on more signals, we need to /* If we need to wait on more signals, we need to
* adjust the timeout value accordingly based on * adjust the timeout value accordingly based on
* the time that has already elapsed. * the time that has already elapsed.
*/ */
hwclk_cycles_delta = ticks_elapsed =
(uint64_t)k_cycle_get_32() - time_stamp_start; (uint64_t)k_uptime_ticks() - time_stamp_start;
time_delta_ns = if (ticks_elapsed < (uint64_t)timeout) {
(uint32_t)k_cyc_to_ns_floor64(hwclk_cycles_delta); poll_timeout = Z_TIMEOUT_TICKS((k_ticks_t)(
timeout - (uint32_t)ticks_elapsed));
time_delta_ms = (uint32_t)time_delta_ns / NSEC_PER_MSEC;
if (timeout_ms > time_delta_ms) {
timeout_ms -= time_delta_ms;
} else { } else {
timeout_ms = 0U; return osFlagsErrorTimeout;
} }
} else {
break;
} }
}
sig = events->signal_results; retval = k_poll(&events->poll_event, 1, poll_timeout);
if (!(options & osFlagsNoClear)) {
/* Clear signal flags as the thread is ready now */ if (retval == -EAGAIN) {
key = irq_lock(); /* k_poll signaled timeout. */
events->signal_results &= ~(flags); return osFlagsErrorTimeout;
irq_unlock(key); } else if (retval != 0) {
return osFlagsErrorUnknown;
}
/* retval is zero.
* k_poll found some raised signal then loop again and check flags.
*/
__ASSERT(events->poll_event.state == K_POLL_STATE_SIGNALED,
"event state not signalled!");
__ASSERT(events->poll_event.signal->signaled == 1U,
"event signaled is not 1");
} }
return sig; return sig;