Browse Source

kernel: internal APIs for thread resource pools

Some kernel APIs may need to allocate memory in order to function
correctly, especially if they are exposed to userspace where
buffers provided by user code cannot be trusted.

Instead of simply drawing from the system heap, specific pools
may instead be assigned to threads, and any requests made on
behalf of the calling thread will draw heap memory from that pool.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
pull/7396/merge
Andrew Boie 7 years ago committed by Andrew Boie
parent
commit
92e5bd7473
  1. 21
      doc/kernel/memory/pools.rst
  2. 36
      include/kernel.h
  3. 13
      kernel/include/kernel_internal.h
  4. 18
      kernel/mempool.c
  5. 5
      kernel/thread.c

21
doc/kernel/memory/pools.rst

@ -173,6 +173,25 @@ memory block is actually used to satisfy the request.) @@ -173,6 +173,25 @@ memory block is actually used to satisfy the request.)
... /* use memory block */
k_mem_pool_free(&block);
Thread Resource Pools
*********************
Certain kernel APIs may need to make heap allocations on behalf of the
calling thread. For example, some initialization APIs for objects like
pipes and message queues may need to allocate a private kernel-side buffer,
or objects like queues may temporarily allocate kernel data structures
as items are placed in the queue.
Such memory allocations are drawn from memory pools that are assigned to
a thread. By default, a thread in the system has no resource pool and
any allocations made on its behalf will fail. The supervisor-mode only
:cpp:func:`k_thread_resource_pool_assign()` will associate any implicit
kernel-side allocations to the target thread with the provided memory pool,
and any children of that thread will inherit this assignment.
If a system heap exists, threads may alternatively have their resources
drawn from it using the :cpp:func:`k_thread_system_pool_assign()` API.
Suggested Uses
**************
@ -191,3 +210,5 @@ The following memory pool APIs are provided by :file:`kernel.h`: @@ -191,3 +210,5 @@ The following memory pool APIs are provided by :file:`kernel.h`:
* :cpp:func:`k_mem_pool_free()`
* :cpp:func:`k_mem_pool_malloc()`
* :cpp:func:`k_free()`
* :cpp:func:`k_thread_resource_pool_assign()`
* :cpp:func:`k_thread_system_pool_assign()`

36
include/kernel.h

@ -524,6 +524,7 @@ struct k_thread { @@ -524,6 +524,7 @@ struct k_thread {
/* Context handle returned via _arch_switch() */
void *switch_handle;
#endif
struct k_mem_pool *resource_pool;
/* arch-specifics: must always be at the end */
struct _thread_arch arch;
@ -700,6 +701,41 @@ extern FUNC_NORETURN void k_thread_user_mode_enter(k_thread_entry_t entry, @@ -700,6 +701,41 @@ extern FUNC_NORETURN void k_thread_user_mode_enter(k_thread_entry_t entry,
extern void __attribute__((sentinel))
k_thread_access_grant(struct k_thread *thread, ...);
/**
* @brief Assign a resource memory pool to a thread
*
* By default, threads have no resource pool assigned unless their parent
* thread has a resource pool, in which case it is inherited. Multiple
* threads may be assigned to the same memory pool.
*
* Changing a thread's resource pool will not migrate allocations from the
* previous pool.
*
* @param thread Target thread to assign a memory pool for resource requests,
* or NULL if the thread should no longer have a memory pool.
* @param pool Memory pool to use for resources.
*/
static inline void k_thread_resource_pool_assign(struct k_thread *thread,
struct k_mem_pool *pool)
{
thread->resource_pool = pool;
}
#if (CONFIG_HEAP_MEM_POOL_SIZE > 0)
/**
* @brief Assign the system heap as a thread's resource pool
*
* Similar to k_thread_resource_pool_assign(), but the thread will use
* the kernel heap to draw memory.
*
* Use with caution, as a malicious thread could perform DoS attacks on the
* kernel heap.
*
* @param thread Target thread to assign the system heap for resource requests
*/
void k_thread_system_pool_assign(struct k_thread *thread);
#endif /* (CONFIG_HEAP_MEM_POOL_SIZE > 0) */
/**
* @brief Put the current thread to sleep.
*

13
kernel/include/kernel_internal.h

@ -159,6 +159,19 @@ void _arch_user_mode_enter(k_thread_entry_t user_entry, void *p1, void *p2, @@ -159,6 +159,19 @@ void _arch_user_mode_enter(k_thread_entry_t user_entry, void *p1, void *p2,
extern FUNC_NORETURN void _arch_syscall_oops(void *ssf);
#endif /* CONFIG_USERSPACE */
/**
* @brief Allocate some memory from the current thread's resource pool
*
* Threads may be assigned a resource pool, which will be used to allocate
* memory on behalf of certain kernel and driver APIs. Memory reserved
* in this way should be freed with k_free().
*
* @param size Memory allocation size
* @return A pointer to the allocated memory, or NULL if there is insufficient
* RAM in the pool or the thread has no resource pool assigned
*/
void *z_thread_malloc(size_t size);
/* set and clear essential thread flag */
extern void _thread_essential_set(void);

18
kernel/mempool.c

@ -185,4 +185,22 @@ void *k_calloc(size_t nmemb, size_t size) @@ -185,4 +185,22 @@ void *k_calloc(size_t nmemb, size_t size)
}
return ret;
}
void k_thread_system_pool_assign(struct k_thread *thread)
{
thread->resource_pool = _HEAP_MEM_POOL;
}
#endif
void *z_thread_malloc(size_t size)
{
void *ret;
if (_current->resource_pool) {
ret = k_mem_pool_malloc(_current->resource_pool, size);
} else {
ret = NULL;
}
return ret;
}

5
kernel/thread.c

@ -295,13 +295,15 @@ void _setup_new_thread(struct k_thread *new_thread, @@ -295,13 +295,15 @@ void _setup_new_thread(struct k_thread *new_thread,
/* Any given thread has access to itself */
k_object_access_grant(new_thread, new_thread);
#endif
#ifdef CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN
/* _current may be null if the dummy thread is not used */
if (!_current) {
new_thread->resource_pool = NULL;
return;
}
#endif
#ifdef CONFIG_USERSPACE
/* New threads inherit any memory domain membership by the parent */
if (_current->mem_domain_info.mem_domain) {
k_mem_domain_add_thread(_current->mem_domain_info.mem_domain,
@ -312,6 +314,7 @@ void _setup_new_thread(struct k_thread *new_thread, @@ -312,6 +314,7 @@ void _setup_new_thread(struct k_thread *new_thread,
_thread_perms_inherit(_current, new_thread);
}
#endif
new_thread->resource_pool = _current->resource_pool;
}
#ifdef CONFIG_MULTITHREADING

Loading…
Cancel
Save