kernel: Add k_event_set_masked primitive

There is no easy way to clear event bits without
the potential for a race to exist between producer(s)
and consumer(s). The result of this race is that events
can be lost through the various resetting mechanisms
available (flag to k_event_wait(), or k_event_set()).

Add k_event_set_masked() which permits bits to be set or cleared.
This allows consumers to clear just the bits that they have read
without (accidentally) discarding any new bits.

Update unit tests to verify the functionality.

Partly Fixes #46117.

Signed-off-by: Andrew Jackson <andrew.jackson@amd.com>
This commit is contained in:
Andrew Jackson 2022-07-07 06:06:59 +01:00 committed by Anas Nashif
commit e183671808
3 changed files with 59 additions and 0 deletions

View file

@ -2129,6 +2129,21 @@ __syscall void k_event_post(struct k_event *event, uint32_t events);
*/
__syscall void k_event_set(struct k_event *event, uint32_t events);
/**
* @brief Set or clear the events in an event object
*
* This routine sets the events stored in event object to the specified value.
* All tasks waiting on the event object @a event whose waiting conditions
* become met by this immediately unpend. Unlike @ref k_event_set, this routine
* allows specific event bits to be set and cleared as determined by the mask.
*
* @param event Address of the event object
* @param events Set of events to post to @a event
* @param events_mask Mask to be applied to @a events
*/
__syscall void k_event_set_masked(struct k_event *event, uint32_t events,
uint32_t events_mask);
/**
* @brief Wait for any of the specified events
*

View file

@ -174,6 +174,22 @@ void z_vrfy_k_event_set(struct k_event *event, uint32_t events)
#include <syscalls/k_event_set_mrsh.c>
#endif
void z_impl_k_event_set_masked(struct k_event *event, uint32_t events,
uint32_t events_mask)
{
k_event_post_internal(event, events, events_mask);
}
#ifdef CONFIG_USERSPACE
void z_vrfy_k_event_set_masked(struct k_event *event, uint32_t events,
uint32_t events_mask)
{
Z_OOPS(Z_SYSCALL_OBJ(event, K_OBJ_EVENT));
z_impl_k_event_set_masked(event, events, events_mask);
}
#include <syscalls/k_event_set_masked_mrsh.c>
#endif
static uint32_t k_event_wait_internal(struct k_event *event, uint32_t events,
unsigned int options, k_timeout_t timeout)
{

View file

@ -340,6 +340,7 @@ ZTEST(events_api, test_event_deliver)
{
static struct k_event event;
uint32_t events;
uint32_t events_mask;
k_event_init(&event);
@ -361,6 +362,33 @@ ZTEST(events_api, test_event_deliver)
events = 0xAAAA0000;
k_event_set(&event, events);
zassert_true(event.events == events, NULL);
/*
* Verify k_event_set_masked() update the events
* stored in the event object as expected
*/
events = 0x33333333;
k_event_set(&event, events);
zassert_true(event.events == events, NULL);
events_mask = 0x11111111;
k_event_set_masked(&event, 0, events_mask);
zassert_true(event.events == 0x22222222, NULL);
events_mask = 0x22222222;
k_event_set_masked(&event, 0, events_mask);
zassert_true(event.events == 0, NULL);
events = 0x22222222;
events_mask = 0x22222222;
k_event_set_masked(&event, events, events_mask);
zassert_true(event.events == events, NULL);
events = 0x11111111;
events_mask = 0x33333333;
k_event_set_masked(&event, events, events_mask);
zassert_true(event.events == events, NULL);
}
/**