Skip to content

Commit 2ace615

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 2ace615

File tree

7 files changed

+213
-2
lines changed

7 files changed

+213
-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: 125 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,26 @@ static inline void rtio_access_grant(struct rtio *r, struct k_thread *t)
14351438
#endif
14361439
}
14371440

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

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

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)