kernel: Allow k_poll on message queues

This commit adds the ability to use a message queue as a
k_poll object. It follows the same pattern as polling on
FIFOs.

This change has been proven in practice at Samsara.

Fixes: #26728

Signed-off-by: Nick Graves <nicholas.graves@samsara.com>
This commit is contained in:
Nick Graves 2021-04-12 12:35:18 -07:00 committed by Anas Nashif
commit b445f13462
3 changed files with 42 additions and 1 deletions

View file

@ -4126,6 +4126,8 @@ struct k_msgq {
/** Number of used messages */
uint32_t used_msgs;
_POLL_EVENT;
_OBJECT_TRACING_NEXT_PTR(k_msgq)
_OBJECT_TRACING_LINKED_FLAG
@ -4147,6 +4149,7 @@ struct k_msgq {
.read_ptr = q_buffer, \
.write_ptr = q_buffer, \
.used_msgs = 0, \
_POLL_EVENT_OBJ_INIT(obj) \
_OBJECT_TRACING_INIT \
}
@ -5098,6 +5101,9 @@ enum _poll_types_bits {
/* queue/FIFO/LIFO data availability */
_POLL_TYPE_DATA_AVAILABLE,
/* msgq data availability */
_POLL_TYPE_MSGQ_DATA_AVAILABLE,
_POLL_NUM_TYPES
};
@ -5120,6 +5126,9 @@ enum _poll_states_bits {
/* queue/FIFO/LIFO wait was cancelled */
_POLL_STATE_CANCELLED,
/* data is available to read on a message queue */
_POLL_STATE_MSGQ_DATA_AVAILABLE,
_POLL_NUM_STATES
};
@ -5150,6 +5159,7 @@ enum _poll_states_bits {
#define K_POLL_TYPE_SEM_AVAILABLE Z_POLL_TYPE_BIT(_POLL_TYPE_SEM_AVAILABLE)
#define K_POLL_TYPE_DATA_AVAILABLE Z_POLL_TYPE_BIT(_POLL_TYPE_DATA_AVAILABLE)
#define K_POLL_TYPE_FIFO_DATA_AVAILABLE K_POLL_TYPE_DATA_AVAILABLE
#define K_POLL_TYPE_MSGQ_DATA_AVAILABLE Z_POLL_TYPE_BIT(_POLL_TYPE_MSGQ_DATA_AVAILABLE)
/* public - polling modes */
enum k_poll_modes {
@ -5165,6 +5175,7 @@ enum k_poll_modes {
#define K_POLL_STATE_SEM_AVAILABLE Z_POLL_STATE_BIT(_POLL_STATE_SEM_AVAILABLE)
#define K_POLL_STATE_DATA_AVAILABLE Z_POLL_STATE_BIT(_POLL_STATE_DATA_AVAILABLE)
#define K_POLL_STATE_FIFO_DATA_AVAILABLE K_POLL_STATE_DATA_AVAILABLE
#define K_POLL_STATE_MSGQ_DATA_AVAILABLE Z_POLL_STATE_BIT(_POLL_STATE_MSGQ_DATA_AVAILABLE)
#define K_POLL_STATE_CANCELLED Z_POLL_STATE_BIT(_POLL_STATE_CANCELLED)
/* public - poll signal object */
@ -5221,6 +5232,7 @@ struct k_poll_event {
struct k_sem *sem;
struct k_fifo *fifo;
struct k_queue *queue;
struct k_msgq *msgq;
};
};

View file

@ -46,6 +46,13 @@ SYS_INIT(init_msgq_module, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
#endif /* CONFIG_OBJECT_TRACING */
#ifdef CONFIG_POLL
static inline void handle_poll_events(struct k_msgq *msgq, uint32_t state)
{
z_handle_obj_poll_events(&msgq->poll_events, state);
}
#endif /* CONFIG_POLL */
void k_msgq_init(struct k_msgq *msgq, char *buffer, size_t msg_size,
uint32_t max_msgs)
{
@ -59,7 +66,9 @@ void k_msgq_init(struct k_msgq *msgq, char *buffer, size_t msg_size,
msgq->flags = 0;
z_waitq_init(&msgq->wait_q);
msgq->lock = (struct k_spinlock) {};
#ifdef CONFIG_POLL
sys_dlist_init(&msgq->poll_events);
#endif /* CONFIG_POLL */
SYS_TRACING_OBJ_INIT(k_msgq, msgq);
z_object_init(msgq);
@ -143,6 +152,9 @@ int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout
msgq->write_ptr = msgq->buffer_start;
}
msgq->used_msgs++;
#ifdef CONFIG_POLL
handle_poll_events(msgq, K_POLL_STATE_MSGQ_DATA_AVAILABLE);
#endif /* CONFIG_POLL */
}
result = 0;
} else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {

View file

@ -78,6 +78,12 @@ static inline bool is_condition_met(struct k_poll_event *event, uint32_t *state)
return true;
}
break;
case K_POLL_TYPE_MSGQ_DATA_AVAILABLE:
if (event->msgq->used_msgs > 0) {
*state = K_POLL_STATE_MSGQ_DATA_AVAILABLE;
return true;
}
break;
case K_POLL_TYPE_IGNORE:
break;
default:
@ -134,6 +140,10 @@ static inline void register_event(struct k_poll_event *event,
__ASSERT(event->signal != NULL, "invalid poll signal\n");
add_event(&event->signal->poll_events, event, poller);
break;
case K_POLL_TYPE_MSGQ_DATA_AVAILABLE:
__ASSERT(event->msgq != NULL, "invalid message queue\n");
add_event(&event->msgq->poll_events, event, poller);
break;
case K_POLL_TYPE_IGNORE:
/* nothing to do */
break;
@ -165,6 +175,10 @@ static inline void clear_event_registration(struct k_poll_event *event)
__ASSERT(event->signal != NULL, "invalid poll signal\n");
remove_event = true;
break;
case K_POLL_TYPE_MSGQ_DATA_AVAILABLE:
__ASSERT(event->msgq != NULL, "invalid message queue\n");
remove_event = true;
break;
case K_POLL_TYPE_IGNORE:
/* nothing to do */
break;
@ -362,6 +376,9 @@ static inline int z_vrfy_k_poll(struct k_poll_event *events,
case K_POLL_TYPE_DATA_AVAILABLE:
Z_OOPS(Z_SYSCALL_OBJ(e->queue, K_OBJ_QUEUE));
break;
case K_POLL_TYPE_MSGQ_DATA_AVAILABLE:
Z_OOPS(Z_SYSCALL_OBJ(e->msgq, K_OBJ_MSGQ));
break;
default:
ret = -EINVAL;
goto out_free;