Skip to content

rtio: Add a context pool #92852

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/zephyr/linker/common-ram.ld
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ ITERABLE_SECTION_RAM(scmi_protocol, Z_LINK_ITERABLE_SUBALIGN)

#if defined(CONFIG_RTIO)
ITERABLE_SECTION_RAM(rtio, Z_LINK_ITERABLE_SUBALIGN)
ITERABLE_SECTION_RAM(rtio_pool, Z_LINK_ITERABLE_SUBALIGN)
ITERABLE_SECTION_RAM(rtio_iodev, Z_LINK_ITERABLE_SUBALIGN)
ITERABLE_SECTION_RAM(rtio_sqe_pool, Z_LINK_ITERABLE_SUBALIGN)
ITERABLE_SECTION_RAM(rtio_cqe_pool, Z_LINK_ITERABLE_SUBALIGN)
Expand Down
125 changes: 125 additions & 0 deletions include/zephyr/rtio/rtio.h
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,9 @@ static inline void z_impl_rtio_release_buffer(struct rtio *r, void *buff, uint32

/**
* Grant access to an RTIO context to a user thread
*
* @param r RTIO context
* @param t Thread to grant permissions to
*/
static inline void rtio_access_grant(struct rtio *r, struct k_thread *t)
{
Expand All @@ -1435,6 +1438,26 @@ static inline void rtio_access_grant(struct rtio *r, struct k_thread *t)
#endif
}


/**
* Revoke access to an RTIO context from a user thread
*
* @param r RTIO context
* @param t Thread to revoke permissions from
*/
static inline void rtio_access_revoke(struct rtio *r, struct k_thread *t)
{
k_object_access_revoke(r, t);

#ifdef CONFIG_RTIO_SUBMIT_SEM
k_object_access_revoke(r->submit_sem, t);
#endif

#ifdef CONFIG_RTIO_CONSUME_SEM
k_object_access_revoke(r->consume_sem, t);
#endif
}

/**
* @brief Attempt to cancel an SQE
*
Expand Down Expand Up @@ -1674,6 +1697,108 @@ static inline int z_impl_rtio_submit(struct rtio *r, uint32_t wait_count)
}
#endif /* CONFIG_RTIO_SUBMIT_SEM */

/**
* @brief Pool of RTIO contexts to use with dynamically created threads
*/
struct rtio_pool {
/** Size of the pool */
size_t pool_size;

/** Array containing contexts of the pool */
struct rtio **contexts;

/** Atomic bitmap to signal a member is used/unused */
atomic_t *used;
};

/**
* @brief Obtain an RTIO context from a pool
*
* @param pool RTIO pool to acquire a context from
*
* @retval NULL no available contexts
* @retval r Valid context with permissions granted to the calling thread
*/
__syscall struct rtio *rtio_pool_acquire(struct rtio_pool *pool);

static inline struct rtio *z_impl_rtio_pool_acquire(struct rtio_pool *pool)
{
struct rtio *r = NULL;

for (size_t i = 0; i < pool->pool_size; i++) {
if (atomic_test_and_set_bit(pool->used, i) == 0) {
r = pool->contexts[i];
break;
}
}

if (r != NULL) {
rtio_access_grant(r, k_current_get());
}

return r;
}

/**
* @brief Return an RTIO context to a pool
*
* @param pool RTIO pool to return a context to
* @param r RTIO context to return to the pool
*/
__syscall void rtio_pool_release(struct rtio_pool *pool, struct rtio *r);

static inline void z_impl_rtio_pool_release(struct rtio_pool *pool, struct rtio *r)
{

if (k_is_user_context()) {
rtio_access_revoke(r, k_current_get());
}

for (size_t i = 0; i < pool->pool_size; i++) {
if (pool->contexts[i] == r) {
atomic_clear_bit(pool->used, i);
break;
}
}
}

/* clang-format off */

/** @cond ignore */

#define Z_RTIO_POOL_NAME_N(n, name) \
name##_##n

#define Z_RTIO_POOL_DEFINE_N(n, name, sq_sz, cq_sz) \
RTIO_DEFINE(Z_RTIO_POOL_NAME_N(n, name), sq_sz, cq_sz)

#define Z_RTIO_POOL_REF_N(n, name) \
&Z_RTIO_POOL_NAME_N(n, name)

/** @endcond */

/**
* @brief Statically define and initialize a pool of RTIO contexts
*
* @param name Name of the RTIO pool
* @param pool_sz Number of RTIO contexts to allocate in the pool
* @param sq_sz Size of the submission queue entry pool per context
* @param cq_sz Size of the completion queue entry pool per context
*/
#define RTIO_POOL_DEFINE(name, pool_sz, sq_sz, cq_sz) \
LISTIFY(pool_sz, Z_RTIO_POOL_DEFINE_N, (;), name, sq_sz, cq_sz); \
static struct rtio *name##_contexts[] = { \
LISTIFY(pool_sz, Z_RTIO_POOL_REF_N, (,), name) \
}; \
ATOMIC_DEFINE(name##_used, pool_sz); \
STRUCT_SECTION_ITERABLE(rtio_pool, name) = { \
.pool_size = pool_sz, \
.contexts = name##_contexts, \
.used = name##_used, \
}

/* clang-format on */

/**
* @}
*/
Expand Down
1 change: 1 addition & 0 deletions scripts/build/gen_kobject_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
("ztest_test_rule", ("CONFIG_ZTEST", True, False)),
("rtio", ("CONFIG_RTIO", False, False)),
("rtio_iodev", ("CONFIG_RTIO", False, False)),
("rtio_pool", ("CONFIG_RTIO", False, False)),
("sensor_decoder_api", ("CONFIG_SENSOR_ASYNC_API", True, False))
])

Expand Down
2 changes: 1 addition & 1 deletion subsys/rtio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ if(CONFIG_RTIO)
zephyr_library_sources(rtio_executor.c)
zephyr_library_sources(rtio_init.c)
zephyr_library_sources(rtio_sched.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE rtio_handlers.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE rtio_syscalls.c)
endif()

zephyr_library_sources_ifdef(CONFIG_RTIO_WORKQ rtio_workq.c)
19 changes: 19 additions & 0 deletions subsys/rtio/rtio_handlers.c → subsys/rtio/rtio_syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,22 @@ static inline int z_vrfy_rtio_submit(struct rtio *r, uint32_t wait_count)
return z_impl_rtio_submit(r, wait_count);
}
#include <zephyr/syscalls/rtio_submit_mrsh.c>


static inline struct rtio *z_vrfy_rtio_pool_acquire(struct rtio_pool *rpool)
{
K_OOPS(K_SYSCALL_OBJ(rpool, K_OBJ_RTIO_POOL));

return z_impl_rtio_pool_acquire(rpool);
}
#include <zephyr/syscalls/rtio_pool_acquire_mrsh.c>


static inline void z_vrfy_rtio_pool_release(struct rtio_pool *rpool, struct rtio *r)
{
K_OOPS(K_SYSCALL_OBJ(rpool, K_OBJ_RTIO_POOL));
K_OOPS(K_SYSCALL_OBJ(r, K_OBJ_RTIO));

z_impl_rtio_pool_release(rpool, r);
}
#include <zephyr/syscalls/rtio_pool_release_mrsh.c>
2 changes: 1 addition & 1 deletion tests/subsys/rtio/rtio_api/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(rtio_api_test)

target_sources(app PRIVATE src/test_rtio_api.c)
target_sources(app PRIVATE src/test_rtio_api.c src/test_rtio_pool.c)

target_include_directories(app PRIVATE
${ZEPHYR_BASE}/include
Expand Down
65 changes: 65 additions & 0 deletions tests/subsys/rtio/rtio_api/src/test_rtio_pool.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2025 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <errno.h>
#include <zephyr/ztest.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/sys/kobject.h>
#include <zephyr/sys/libc-hooks.h>
#include <zephyr/app_memory/mem_domain.h>
#include <zephyr/sys/util_loops.h>
#include <zephyr/sys/time_units.h>
#include <zephyr/timing/timing.h>
#include <zephyr/rtio/rtio.h>

RTIO_POOL_DEFINE(rpool, 2, 8, 8);

#ifdef CONFIG_USERSPACE
struct k_mem_domain pool_domain;
#endif


ZTEST_USER(rtio_pool, test_rtio_pool_acquire_release)
{
struct rtio *r = rtio_pool_acquire(&rpool);

zassert_not_null(r, "expected valid rtio context");

struct rtio_sqe nop_sqe;
struct rtio_cqe nop_cqe;

rtio_sqe_prep_nop(&nop_sqe, NULL, NULL);
rtio_sqe_copy_in(r, &nop_sqe, 1);
rtio_submit(r, 1);
rtio_cqe_copy_out(r, &nop_cqe, 1, K_FOREVER);

rtio_pool_release(&rpool, r);
}

static void *rtio_pool_setup(void)
{
#ifdef CONFIG_USERSPACE
k_mem_domain_init(&pool_domain, 0, NULL);
k_mem_domain_add_partition(&pool_domain, &rtio_partition);
#if Z_LIBC_PARTITION_EXISTS
k_mem_domain_add_partition(&pool_domain, &z_libc_partition);
#endif /* Z_LIBC_PARTITION_EXISTS */
#endif /* CONFIG_USERSPACE */

return NULL;
}

static void rtio_pool_before(void *a)
{
ARG_UNUSED(a);

#ifdef CONFIG_USERSPACE
k_object_access_grant(&rpool, k_current_get());
#endif /* CONFIG_USERSPACE */
}

ZTEST_SUITE(rtio_pool, NULL, rtio_pool_setup, rtio_pool_before, NULL, NULL);
Loading