Skip to content

Commit f03ba9c

Browse files
committed
rtio: Add a context pool
Adds a context pool that can be used when a number of threads may be dynamically created to use with RTIO. While the pool has a small cost to it, the cost of verifying a statically declared kobject likely makes it worth avoiding dynamically allocating these with the typical kobject_alloc method. Instead this arena style pool of objects can be used where the kobject validation uses the gperf hash created at build time. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
1 parent 8add921 commit f03ba9c

File tree

7 files changed

+214
-2
lines changed

7 files changed

+214
-2
lines changed

include/zephyr/linker/common-ram.ld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ ITERABLE_SECTION_RAM(scmi_protocol, Z_LINK_ITERABLE_SUBALIGN)
126126

127127
#if defined(CONFIG_RTIO)
128128
ITERABLE_SECTION_RAM(rtio, Z_LINK_ITERABLE_SUBALIGN)
129+
ITERABLE_SECTION_RAM(rtio_pool, Z_LINK_ITERABLE_SUBALIGN)
129130
ITERABLE_SECTION_RAM(rtio_iodev, Z_LINK_ITERABLE_SUBALIGN)
130131
ITERABLE_SECTION_RAM(rtio_sqe_pool, Z_LINK_ITERABLE_SUBALIGN)
131132
ITERABLE_SECTION_RAM(rtio_cqe_pool, Z_LINK_ITERABLE_SUBALIGN)

include/zephyr/rtio/rtio.h

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,9 @@ static inline void z_impl_rtio_release_buffer(struct rtio *r, void *buff, uint32
14211421

14221422
/**
14231423
* Grant access to an RTIO context to a user thread
1424+
*
1425+
* @param r RTIO context
1426+
* @param t Thread to grant permissions to
14241427
*/
14251428
static inline void rtio_access_grant(struct rtio *r, struct k_thread *t)
14261429
{
@@ -1435,6 +1438,27 @@ static inline void rtio_access_grant(struct rtio *r, struct k_thread *t)
14351438
#endif
14361439
}
14371440

1441+
1442+
1443+
/**
1444+
* Revoke access to an RTIO context to a user thread
1445+
*
1446+
* @param r RTIO context
1447+
* @param t Thread to revoke permissions from
1448+
*/
1449+
static inline void rtio_access_revoke(struct rtio *r, struct k_thread *t)
1450+
{
1451+
k_object_access_revoke(r, t);
1452+
1453+
#ifdef CONFIG_RTIO_SUBMIT_SEM
1454+
k_object_access_revoke(r->submit_sem, t);
1455+
#endif
1456+
1457+
#ifdef CONFIG_RTIO_CONSUME_SEM
1458+
k_object_access_revoke(r->consume_sem, t);
1459+
#endif
1460+
}
1461+
14381462
/**
14391463
* @brief Attempt to cancel an SQE
14401464
*
@@ -1674,6 +1698,108 @@ static inline int z_impl_rtio_submit(struct rtio *r, uint32_t wait_count)
16741698
}
16751699
#endif /* CONFIG_RTIO_SUBMIT_SEM */
16761700

1701+
/**
1702+
* @brief Pool of RTIO contexts to use with dynamically created threads
1703+
*/
1704+
struct rtio_pool {
1705+
/** Size of the pool */
1706+
size_t pool_size;
1707+
1708+
/** Array containing contexts of the pool */
1709+
struct rtio **contexts;
1710+
1711+
/** Atomic bitmap to signal a member is used/unused */
1712+
atomic_t *used;
1713+
};
1714+
1715+
/**
1716+
* @brief Obtain an RTIO context from a pool
1717+
*
1718+
* @param pool RTIO pool to acquire a context from
1719+
*
1720+
* @retval NULL no available contexts
1721+
* @retval r Valid context with permissions granted to the calling thread
1722+
*/
1723+
__syscall struct rtio *rtio_pool_acquire(struct rtio_pool *pool);
1724+
1725+
static inline struct rtio *z_impl_rtio_pool_acquire(struct rtio_pool *pool)
1726+
{
1727+
struct rtio *r = NULL;
1728+
1729+
for (size_t i = 0; i < pool->pool_size; i++) {
1730+
if (atomic_test_and_set_bit(pool->used, i) == 0) {
1731+
r = pool->contexts[i];
1732+
break;
1733+
}
1734+
}
1735+
1736+
if (r != NULL) {
1737+
rtio_access_grant(r, k_current_get());
1738+
}
1739+
1740+
return r;
1741+
}
1742+
1743+
/**
1744+
* @brief Return an RTIO context to a pool
1745+
*
1746+
* @param pool RTIO pool to return a context to
1747+
* @paam r RTIO context to return
1748+
*/
1749+
__syscall void rtio_pool_release(struct rtio_pool *pool, struct rtio *r);
1750+
1751+
static inline void z_impl_rtio_pool_release(struct rtio_pool *pool, struct rtio *r)
1752+
{
1753+
1754+
if (k_is_user_context()) {
1755+
rtio_access_revoke(r, k_current_get());
1756+
}
1757+
1758+
for (size_t i = 0; i < pool->pool_size; i++) {
1759+
if (pool->contexts[i] == r) {
1760+
atomic_clear_bit(pool->used, i);
1761+
break;
1762+
}
1763+
}
1764+
}
1765+
1766+
/* clang-format off */
1767+
1768+
/** @cond ignore */
1769+
1770+
#define Z_RTIO_POOL_NAME_N(n, name) \
1771+
name##_##n
1772+
1773+
#define Z_RTIO_POOL_DEFINE_N(n, name, sq_sz, cq_sz) \
1774+
RTIO_DEFINE(Z_RTIO_POOL_NAME_N(n, name), sq_sz, cq_sz)
1775+
1776+
#define Z_RTIO_POOL_REF_N(n, name) \
1777+
&Z_RTIO_POOL_NAME_N(n, name)
1778+
1779+
/** @endcond */
1780+
1781+
/**
1782+
* @brief Statically define and initialize a pool of RTIO contexts
1783+
*
1784+
* @param name Name of the RTIO pool
1785+
* @param pool_sz Number of RTIO contexts to allocate in the pool
1786+
* @param sq_sz Size of the submission queue entry pool per context
1787+
* @param cq_sz Size of the completion queue entry pool per context
1788+
*/
1789+
#define RTIO_POOL_DEFINE(name, pool_sz, sq_sz, cq_sz) \
1790+
LISTIFY(pool_sz, Z_RTIO_POOL_DEFINE_N, (;), name, sq_sz, cq_sz); \
1791+
static struct rtio *name##_contexts[] = { \
1792+
LISTIFY(pool_sz, Z_RTIO_POOL_REF_N, (,), name) \
1793+
}; \
1794+
ATOMIC_DEFINE(name##_used, pool_sz); \
1795+
STRUCT_SECTION_ITERABLE(rtio_pool, name) = { \
1796+
.pool_size = pool_sz, \
1797+
.contexts = name##_contexts, \
1798+
.used = name##_used, \
1799+
}
1800+
1801+
/* clang-format on */
1802+
16771803
/**
16781804
* @}
16791805
*/

scripts/build/gen_kobject_list.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
("ztest_test_rule", ("CONFIG_ZTEST", True, False)),
115115
("rtio", ("CONFIG_RTIO", False, False)),
116116
("rtio_iodev", ("CONFIG_RTIO", False, False)),
117+
("rtio_pool", ("CONFIG_RTIO", False, False)),
117118
("sensor_decoder_api", ("CONFIG_SENSOR_ASYNC_API", True, False))
118119
])
119120

subsys/rtio/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ if(CONFIG_RTIO)
1111
zephyr_library_sources(rtio_executor.c)
1212
zephyr_library_sources(rtio_init.c)
1313
zephyr_library_sources(rtio_sched.c)
14-
zephyr_library_sources_ifdef(CONFIG_USERSPACE rtio_handlers.c)
14+
zephyr_library_sources_ifdef(CONFIG_USERSPACE rtio_syscalls.c)
1515
endif()
1616

1717
zephyr_library_sources_ifdef(CONFIG_RTIO_WORKQ rtio_workq.c)

subsys/rtio/rtio_handlers.c renamed to subsys/rtio/rtio_syscalls.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,22 @@ static inline int z_vrfy_rtio_submit(struct rtio *r, uint32_t wait_count)
133133
return z_impl_rtio_submit(r, wait_count);
134134
}
135135
#include <zephyr/syscalls/rtio_submit_mrsh.c>
136+
137+
138+
static inline struct rtio * z_vrfy_rtio_pool_acquire(struct rtio_pool *rpool)
139+
{
140+
K_OOPS(K_SYSCALL_OBJ(rpool, K_OBJ_RTIO_POOL));
141+
142+
return z_impl_rtio_pool_acquire(rpool);
143+
}
144+
#include <zephyr/syscalls/rtio_pool_acquire_mrsh.c>
145+
146+
147+
static inline void z_vrfy_rtio_pool_release(struct rtio_pool *rpool, struct rtio *r)
148+
{
149+
K_OOPS(K_SYSCALL_OBJ(rpool, K_OBJ_RTIO_POOL));
150+
K_OOPS(K_SYSCALL_OBJ(r, K_OBJ_RTIO));
151+
152+
z_impl_rtio_pool_release(rpool, r);
153+
}
154+
#include <zephyr/syscalls/rtio_pool_release_mrsh.c>

tests/subsys/rtio/rtio_api/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.20.0)
55
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
66
project(rtio_api_test)
77

8-
target_sources(app PRIVATE src/test_rtio_api.c)
8+
target_sources(app PRIVATE src/test_rtio_api.c src/test_rtio_pool.c)
99

1010
target_include_directories(app PRIVATE
1111
${ZEPHYR_BASE}/include
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright (c) 2025 Intel Corporation.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <errno.h>
8+
#include <zephyr/ztest.h>
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/sys/atomic.h>
11+
#include <zephyr/sys/kobject.h>
12+
#include <zephyr/sys/libc-hooks.h>
13+
#include <zephyr/app_memory/mem_domain.h>
14+
#include <zephyr/sys/util_loops.h>
15+
#include <zephyr/sys/time_units.h>
16+
#include <zephyr/timing/timing.h>
17+
#include <zephyr/rtio/rtio.h>
18+
19+
RTIO_POOL_DEFINE(rpool, 2, 8, 8);
20+
21+
#ifdef CONFIG_USERSPACE
22+
struct k_mem_domain pool_domain;
23+
#endif
24+
25+
26+
ZTEST_USER(rtio_pool, test_rtio_pool_acquire_release)
27+
{
28+
struct rtio *r = rtio_pool_acquire(&rpool);
29+
30+
zassert_not_null(r, "expected valid rtio context");
31+
32+
struct rtio_sqe nop_sqe;
33+
struct rtio_cqe nop_cqe;
34+
35+
rtio_sqe_prep_nop(&nop_sqe, NULL, NULL);
36+
rtio_sqe_copy_in(r, &nop_sqe, 1);
37+
rtio_submit(r, 1);
38+
rtio_cqe_copy_out(r, &nop_cqe, 1, K_FOREVER);
39+
40+
rtio_pool_release(&rpool, r);
41+
}
42+
43+
static void *rtio_pool_setup(void)
44+
{
45+
#ifdef CONFIG_USERSPACE
46+
k_mem_domain_init(&pool_domain, 0, NULL);
47+
k_mem_domain_add_partition(&pool_domain, &rtio_partition);
48+
#if Z_LIBC_PARTITION_EXISTS
49+
k_mem_domain_add_partition(&pool_domain, &z_libc_partition);
50+
#endif /* Z_LIBC_PARTITION_EXISTS */
51+
#endif /* CONFIG_USERSPACE */
52+
53+
return NULL;
54+
}
55+
56+
static void rtio_pool_before(void *a)
57+
{
58+
ARG_UNUSED(a);
59+
60+
#ifdef CONFIG_USERSPACE
61+
k_object_access_grant(&rpool, k_current_get());
62+
#endif /* CONFIG_USERSPACE */
63+
}
64+
65+
ZTEST_SUITE(rtio_pool, NULL, rtio_pool_setup, rtio_pool_before, NULL, NULL);

0 commit comments

Comments
 (0)