zephyr/lib/os/user_work.c
Peter Bigot 4e3b92609b kernel: provide functional equivalent to old userspace work queue API
The new API cannot be used from userspace because it is not merely a
wrapper around existing userspace-capable objects (threads and
queues), but instead requires much more complex and lower-level access
to memory that can't be touched from userspace.  The vast majority of
work queue users are operating from privileged mode, so there's little
motivation to go through the pain and complexity of converting all
functions to system calls.

Copy the necessary pieces of the existing userspace work queue API out
and expose them with new names and types:

* k_work_handler_t becomes k_work_user_handler_t
* k_work becomes k_work_user
* k_work_q becomes k_work_user_q

etc.  Because the replacement API cannot use the same types new API
names are also introduced to make it more clear that the userspace
work queue API is a separate functionality.

Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
2021-03-03 20:06:00 -05:00

60 lines
1.4 KiB
C

/*
* Copyright (c) 2018 Intel Corporation
* Copyright (c) 2016 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
static void z_work_user_q_main(void *work_q_ptr, void *p2, void *p3)
{
struct k_work_user_q *work_q = work_q_ptr;
ARG_UNUSED(p2);
ARG_UNUSED(p3);
while (true) {
struct k_work_user *work;
k_work_user_handler_t handler;
work = k_queue_get(&work_q->queue, K_FOREVER);
if (work == NULL) {
continue;
}
handler = work->handler;
__ASSERT(handler != NULL, "handler must be provided");
/* Reset pending state so it can be resubmitted by handler */
if (atomic_test_and_clear_bit(&work->flags,
K_WORK_USER_STATE_PENDING)) {
handler(work);
}
/* Make sure we don't hog up the CPU if the FIFO never (or
* very rarely) gets empty.
*/
k_yield();
}
}
void k_work_user_queue_start(struct k_work_user_q *work_q, k_thread_stack_t *stack,
size_t stack_size, int prio, const char *name)
{
k_queue_init(&work_q->queue);
/* Created worker thread will inherit object permissions and memory
* domain configuration of the caller
*/
k_thread_create(&work_q->thread, stack, stack_size, z_work_user_q_main,
work_q, NULL, NULL, prio, K_USER | K_INHERIT_PERMS,
K_FOREVER);
k_object_access_grant(&work_q->queue, &work_q->thread);
if (name != NULL) {
k_thread_name_set(&work_q->thread, name);
}
k_thread_start(&work_q->thread);
}