kernel: add k_thread_create() API
Unline k_thread_spawn(), the struct k_thread can live anywhere and not in the thread's stack region. This will be useful for memory protection scenarios where private kernel structures for a thread are not accessible by that thread, or we want to allow the thread to use all the stack space we gave it. This requires a change to the internal _new_thread() API as we need to provide a separate pointer for the k_thread. By default, we still create internal threads with the k_thread in stack memory. Forthcoming patches will change this, but we first need to make it easier to define k_thread memory of variable size depending on whether we need to store coprocessor state or not. Change-Id: I533bbcf317833ba67a771b356b6bbc6596bf60f5 Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
2a0d16593a
commit
d26cf2dc33
16 changed files with 147 additions and 100 deletions
|
@ -54,7 +54,7 @@ struct init_stack_frame {
|
||||||
*
|
*
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
void _new_thread(char *pStackMem, size_t stackSize,
|
void _new_thread(struct k_thread *thread, char *pStackMem, size_t stackSize,
|
||||||
_thread_entry_t pEntry,
|
_thread_entry_t pEntry,
|
||||||
void *parameter1, void *parameter2, void *parameter3,
|
void *parameter1, void *parameter2, void *parameter3,
|
||||||
int priority, unsigned int options)
|
int priority, unsigned int options)
|
||||||
|
@ -64,12 +64,9 @@ void _new_thread(char *pStackMem, size_t stackSize,
|
||||||
char *stackEnd = pStackMem + stackSize;
|
char *stackEnd = pStackMem + stackSize;
|
||||||
struct init_stack_frame *pInitCtx;
|
struct init_stack_frame *pInitCtx;
|
||||||
|
|
||||||
struct k_thread *thread;
|
_new_thread_init(thread, pStackMem, stackSize, priority, options);
|
||||||
|
|
||||||
thread = _new_thread_init(pStackMem, stackSize, priority, options);
|
|
||||||
|
|
||||||
/* carve the thread entry struct from the "base" of the stack */
|
/* carve the thread entry struct from the "base" of the stack */
|
||||||
|
|
||||||
pInitCtx = (struct init_stack_frame *)(STACK_ROUND_DOWN(stackEnd) -
|
pInitCtx = (struct init_stack_frame *)(STACK_ROUND_DOWN(stackEnd) -
|
||||||
sizeof(struct init_stack_frame));
|
sizeof(struct init_stack_frame));
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void _new_thread(char *pStackMem, size_t stackSize,
|
void _new_thread(struct k_thread *thread, char *pStackMem, size_t stackSize,
|
||||||
_thread_entry_t pEntry,
|
_thread_entry_t pEntry,
|
||||||
void *parameter1, void *parameter2, void *parameter3,
|
void *parameter1, void *parameter2, void *parameter3,
|
||||||
int priority, unsigned int options)
|
int priority, unsigned int options)
|
||||||
|
@ -62,9 +62,8 @@ void _new_thread(char *pStackMem, size_t stackSize,
|
||||||
|
|
||||||
char *stackEnd = pStackMem + stackSize;
|
char *stackEnd = pStackMem + stackSize;
|
||||||
struct __esf *pInitCtx;
|
struct __esf *pInitCtx;
|
||||||
struct k_thread *thread = (struct k_thread *) pStackMem;
|
|
||||||
|
|
||||||
thread = _new_thread_init(pStackMem, stackSize, priority, options);
|
_new_thread_init(thread, pStackMem, stackSize, priority, options);
|
||||||
|
|
||||||
/* carve the thread entry struct from the "base" of the stack */
|
/* carve the thread entry struct from the "base" of the stack */
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,8 @@ static ALWAYS_INLINE void kernel_arch_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static ALWAYS_INLINE void
|
static ALWAYS_INLINE void
|
||||||
_arch_switch_to_main_thread(char *main_stack, size_t main_stack_size,
|
_arch_switch_to_main_thread(struct k_thread *main_thread, char *main_stack,
|
||||||
_thread_entry_t _main)
|
size_t main_stack_size, _thread_entry_t _main)
|
||||||
{
|
{
|
||||||
/* get high address of the stack, i.e. its start (stack grows down) */
|
/* get high address of the stack, i.e. its start (stack grows down) */
|
||||||
char *start_of_main_stack;
|
char *start_of_main_stack;
|
||||||
|
@ -47,7 +47,7 @@ _arch_switch_to_main_thread(char *main_stack, size_t main_stack_size,
|
||||||
start_of_main_stack = main_stack + main_stack_size;
|
start_of_main_stack = main_stack + main_stack_size;
|
||||||
start_of_main_stack = (void *)STACK_ROUND_DOWN(start_of_main_stack);
|
start_of_main_stack = (void *)STACK_ROUND_DOWN(start_of_main_stack);
|
||||||
|
|
||||||
_current = (void *)main_stack;
|
_current = main_thread;
|
||||||
|
|
||||||
/* the ready queue cache already contains the main thread */
|
/* the ready queue cache already contains the main thread */
|
||||||
|
|
||||||
|
|
|
@ -31,17 +31,16 @@ struct init_stack_frame {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void _new_thread(char *stack_memory, size_t stack_size,
|
void _new_thread(struct k_thread *thread, char *stack_memory, size_t stack_size,
|
||||||
_thread_entry_t thread_func,
|
_thread_entry_t thread_func,
|
||||||
void *arg1, void *arg2, void *arg3,
|
void *arg1, void *arg2, void *arg3,
|
||||||
int priority, unsigned int options)
|
int priority, unsigned int options)
|
||||||
{
|
{
|
||||||
_ASSERT_VALID_PRIO(priority, thread_func);
|
_ASSERT_VALID_PRIO(priority, thread_func);
|
||||||
|
|
||||||
struct k_thread *thread;
|
|
||||||
struct init_stack_frame *iframe;
|
struct init_stack_frame *iframe;
|
||||||
|
|
||||||
thread = _new_thread_init(stack_memory, stack_size, priority, options);
|
_new_thread_init(thread, stack_memory, stack_size, priority, options);
|
||||||
|
|
||||||
/* Initial stack frame data, stored at the base of the stack */
|
/* Initial stack frame data, stored at the base of the stack */
|
||||||
iframe = (struct init_stack_frame *)
|
iframe = (struct init_stack_frame *)
|
||||||
|
|
|
@ -15,17 +15,16 @@ void _thread_entry_wrapper(_thread_entry_t thread,
|
||||||
void *arg2,
|
void *arg2,
|
||||||
void *arg3);
|
void *arg3);
|
||||||
|
|
||||||
void _new_thread(char *stack_memory, size_t stack_size,
|
void _new_thread(struct k_thread *thread, char *stack_memory,
|
||||||
_thread_entry_t thread_func,
|
size_t stack_size, _thread_entry_t thread_func,
|
||||||
void *arg1, void *arg2, void *arg3,
|
void *arg1, void *arg2, void *arg3,
|
||||||
int priority, unsigned int options)
|
int priority, unsigned int options)
|
||||||
{
|
{
|
||||||
_ASSERT_VALID_PRIO(priority, thread_func);
|
_ASSERT_VALID_PRIO(priority, thread_func);
|
||||||
|
|
||||||
struct k_thread *thread;
|
|
||||||
struct __esf *stack_init;
|
struct __esf *stack_init;
|
||||||
|
|
||||||
thread = _new_thread_init(stack_memory, stack_size, priority, options);
|
_new_thread_init(thread, stack_memory, stack_size, priority, options);
|
||||||
|
|
||||||
/* Initial stack frame for thread */
|
/* Initial stack frame for thread */
|
||||||
stack_init = (struct __esf *)
|
stack_init = (struct __esf *)
|
||||||
|
|
|
@ -39,6 +39,7 @@ void _thread_entry_wrapper(_thread_entry_t, void *,
|
||||||
*
|
*
|
||||||
* This function is called by _new_thread() to initialize tasks.
|
* This function is called by _new_thread() to initialize tasks.
|
||||||
*
|
*
|
||||||
|
* @param thread pointer to thread struct memory
|
||||||
* @param pStackMem pointer to thread stack memory
|
* @param pStackMem pointer to thread stack memory
|
||||||
* @param stackSize size of a stack in bytes
|
* @param stackSize size of a stack in bytes
|
||||||
* @param priority thread priority
|
* @param priority thread priority
|
||||||
|
@ -180,9 +181,8 @@ __asm__("\t.globl _thread_entry\n"
|
||||||
* This function is utilized to create execution threads for both fiber
|
* This function is utilized to create execution threads for both fiber
|
||||||
* threads and kernel tasks.
|
* threads and kernel tasks.
|
||||||
*
|
*
|
||||||
* The k_thread structure is carved from the "end" of the specified
|
* @param thread pointer to thread struct memory, including any space needed
|
||||||
* thread stack memory.
|
* for extra coprocessor context
|
||||||
*
|
|
||||||
* @param pStackmem the pointer to aligned stack memory
|
* @param pStackmem the pointer to aligned stack memory
|
||||||
* @param stackSize the stack size in bytes
|
* @param stackSize the stack size in bytes
|
||||||
* @param pEntry thread entry point routine
|
* @param pEntry thread entry point routine
|
||||||
|
@ -195,7 +195,7 @@ __asm__("\t.globl _thread_entry\n"
|
||||||
*
|
*
|
||||||
* @return opaque pointer to initialized k_thread structure
|
* @return opaque pointer to initialized k_thread structure
|
||||||
*/
|
*/
|
||||||
void _new_thread(char *pStackMem, size_t stackSize,
|
void _new_thread(struct k_thread *thread, char *pStackMem, size_t stackSize,
|
||||||
_thread_entry_t pEntry,
|
_thread_entry_t pEntry,
|
||||||
void *parameter1, void *parameter2, void *parameter3,
|
void *parameter1, void *parameter2, void *parameter3,
|
||||||
int priority, unsigned int options)
|
int priority, unsigned int options)
|
||||||
|
@ -203,9 +203,8 @@ void _new_thread(char *pStackMem, size_t stackSize,
|
||||||
_ASSERT_VALID_PRIO(priority, pEntry);
|
_ASSERT_VALID_PRIO(priority, pEntry);
|
||||||
|
|
||||||
unsigned long *pInitialThread;
|
unsigned long *pInitialThread;
|
||||||
struct k_thread *thread;
|
|
||||||
|
|
||||||
thread = _new_thread_init(pStackMem, stackSize, priority, options);
|
_new_thread_init(thread, pStackMem, stackSize, priority, options);
|
||||||
|
|
||||||
/* carve the thread entry struct from the "base" of the stack */
|
/* carve the thread entry struct from the "base" of the stack */
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
extern void _xt_user_exit(void);
|
extern void _xt_user_exit(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief Initialize a new thread from its stack space
|
* @brief Initialize a new thread
|
||||||
*
|
*
|
||||||
* The struct k_thread is put at the lower address of the stack. An
|
* Any coprocessor context data is put at the lower address of the stack. An
|
||||||
* initial context, to be "restored" by __return_from_coop(), is put at
|
* initial context, to be "restored" by __return_from_coop(), is put at
|
||||||
* the other end of the stack, and thus reusable by the stack when not
|
* the other end of the stack, and thus reusable by the stack when not
|
||||||
* needed anymore.
|
* needed anymore.
|
||||||
|
@ -29,6 +29,7 @@ extern void _xt_user_exit(void);
|
||||||
*
|
*
|
||||||
* <options> is currently unused.
|
* <options> is currently unused.
|
||||||
*
|
*
|
||||||
|
* @param thread pointer to k_thread memory
|
||||||
* @param pStackmem the pointer to aligned stack memory
|
* @param pStackmem the pointer to aligned stack memory
|
||||||
* @param stackSize the stack size in bytes
|
* @param stackSize the stack size in bytes
|
||||||
* @param pEntry thread entry point routine
|
* @param pEntry thread entry point routine
|
||||||
|
@ -41,23 +42,19 @@ extern void _xt_user_exit(void);
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void _new_thread(char *pStack, size_t stackSize,
|
void _new_thread(struct k_thread *thread, char *pStack, size_t stackSize,
|
||||||
void (*pEntry)(void *, void *, void *),
|
void (*pEntry)(void *, void *, void *),
|
||||||
void *p1, void *p2, void *p3,
|
void *p1, void *p2, void *p3,
|
||||||
int priority, unsigned int options)
|
int priority, unsigned int options)
|
||||||
{
|
{
|
||||||
/* Align stack end to maximum alignment requirement. */
|
/* Align stack end to maximum alignment requirement. */
|
||||||
char *stackEnd = (char *)ROUND_DOWN(pStack + stackSize, 16);
|
char *stackEnd = (char *)ROUND_DOWN(pStack + stackSize, 16);
|
||||||
/* k_thread is located at top of stack while frames are located at end
|
|
||||||
* of it
|
|
||||||
*/
|
|
||||||
struct k_thread *thread;
|
|
||||||
#if XCHAL_CP_NUM > 0
|
#if XCHAL_CP_NUM > 0
|
||||||
u32_t *cpSA;
|
u32_t *cpSA;
|
||||||
char *cpStack;
|
char *cpStack;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
thread = _new_thread_init(pStack, stackSize, priority, options);
|
_new_thread_init(thread, pStack, stackSize, priority, options);
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG
|
#ifdef CONFIG_DEBUG
|
||||||
printk("\nstackPtr = %p, stackSize = %d\n", pStack, stackSize);
|
printk("\nstackPtr = %p, stackSize = %d\n", pStack, stackSize);
|
||||||
|
|
|
@ -100,15 +100,15 @@ tagged as an SSE user, or if the application wants to avoid the exception
|
||||||
handling overhead involved in auto-tagging threads, it is possible to
|
handling overhead involved in auto-tagging threads, it is possible to
|
||||||
pre-tag a thread using one of the techniques listed below.
|
pre-tag a thread using one of the techniques listed below.
|
||||||
|
|
||||||
* A statically-spawned x86 thread can be pre-tagged by passing the
|
* A statically-created x86 thread can be pre-tagged by passing the
|
||||||
:c:macro:`K_FP_REGS` or :c:macro:`K_SSE_REGS` option to
|
:c:macro:`K_FP_REGS` or :c:macro:`K_SSE_REGS` option to
|
||||||
:c:macro:`K_THREAD_DEFINE`.
|
:c:macro:`K_THREAD_DEFINE`.
|
||||||
|
|
||||||
* A dynamically-spawned x86 thread can be pre-tagged by passing the
|
* A dynamically-created x86 thread can be pre-tagged by passing the
|
||||||
:c:macro:`K_FP_REGS` or :c:macro:`K_SSE_REGS` option to
|
:c:macro:`K_FP_REGS` or :c:macro:`K_SSE_REGS` option to
|
||||||
:cpp:func:`k_thread_spawn()`.
|
:cpp:func:`k_thread_create()`.
|
||||||
|
|
||||||
* An already-spawned x86 thread can pre-tag itself once it has started
|
* An already-created x86 thread can pre-tag itself once it has started
|
||||||
by passing the :c:macro:`K_FP_REGS` or :c:macro:`K_SSE_REGS` option to
|
by passing the :c:macro:`K_FP_REGS` or :c:macro:`K_SSE_REGS` option to
|
||||||
:cpp:func:`k_float_enable()`.
|
:cpp:func:`k_float_enable()`.
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,13 @@ referenced by a :dfn:`thread id` that is assigned when the thread is spawned.
|
||||||
|
|
||||||
A thread has the following key properties:
|
A thread has the following key properties:
|
||||||
|
|
||||||
* A **stack area**, which is a region of memory used for the thread's
|
* A **stack area**, which is a region of memory used for the thread's stack.
|
||||||
control block (of type :c:type:`struct k_thread`) and for its stack.
|
|
||||||
The **size** of the stack area can be tailored to conform to the actual needs
|
The **size** of the stack area can be tailored to conform to the actual needs
|
||||||
of the thread's processing.
|
of the thread's processing.
|
||||||
|
|
||||||
|
* A **thread control block** for private kernel bookkeeping of the thread's
|
||||||
|
metadata. This is an instance of type :c:type:`struct k_thread`.
|
||||||
|
|
||||||
* An **entry point function**, which is invoked when the thread is started.
|
* An **entry point function**, which is invoked when the thread is started.
|
||||||
Up to 3 **argument values** can be passed to this function.
|
Up to 3 **argument values** can be passed to this function.
|
||||||
|
|
||||||
|
@ -38,13 +40,12 @@ A thread has the following key properties:
|
||||||
|
|
||||||
.. _spawning_thread:
|
.. _spawning_thread:
|
||||||
|
|
||||||
Thread Spawning
|
Thread Creation
|
||||||
===============
|
===============
|
||||||
|
|
||||||
A thread must be spawned before it can be used. The kernel initializes
|
A thread must be created before it can be used. The kernel initializes
|
||||||
the control block portion of the thread's stack area, as well as one
|
the thread control block as well as one end of the stack portion. The remainder
|
||||||
end of the stack portion. The remainder of the thread's stack is typically
|
of the thread's stack is typically left uninitialized.
|
||||||
left uninitialized.
|
|
||||||
|
|
||||||
Specifying a start delay of :c:macro:`K_NO_WAIT` instructs the kernel
|
Specifying a start delay of :c:macro:`K_NO_WAIT` instructs the kernel
|
||||||
to start thread execution immediately. Alternatively, the kernel can be
|
to start thread execution immediately. Alternatively, the kernel can be
|
||||||
|
@ -146,11 +147,9 @@ Implementation
|
||||||
Spawning a Thread
|
Spawning a Thread
|
||||||
=================
|
=================
|
||||||
|
|
||||||
A thread is spawned by defining its stack area and then calling
|
A thread is spawned by defining its stack area and its thread control block,
|
||||||
:cpp:func:`k_thread_spawn()`. The stack area is an array of bytes
|
and then calling :cpp:func:`k_thread_create()`. The stack area must be defined
|
||||||
whose size must equal :c:macro:`K_THREAD_SIZEOF` plus the size
|
using the :c:macro:`__stack` attribute to ensure it is properly aligned.
|
||||||
of the thread's stack. The stack area must be defined using the
|
|
||||||
:c:macro:`__stack` attribute to ensure it is properly aligned.
|
|
||||||
|
|
||||||
The thread spawning function returns its thread id, which can be used
|
The thread spawning function returns its thread id, which can be used
|
||||||
to reference the thread.
|
to reference the thread.
|
||||||
|
@ -165,14 +164,16 @@ The following code spawns a thread that starts immediately.
|
||||||
extern void my_entry_point(void *, void *, void *);
|
extern void my_entry_point(void *, void *, void *);
|
||||||
|
|
||||||
char __noinit __stack my_stack_area[MY_STACK_SIZE];
|
char __noinit __stack my_stack_area[MY_STACK_SIZE];
|
||||||
|
struct k_thread my_thread_data;
|
||||||
|
|
||||||
k_tid_t my_tid = k_thread_spawn(my_stack_area, MY_STACK_SIZE,
|
k_tid_t my_tid = k_thread_create(&my_thread_data, my_stack_area,
|
||||||
my_entry_point, NULL, NULL, NULL,
|
MY_STACK_SIZE, my_entry_point,
|
||||||
MY_PRIORITY, 0, K_NO_WAIT);
|
NULL, NULL, NULL,
|
||||||
|
MY_PRIORITY, 0, K_NO_WAIT);
|
||||||
|
|
||||||
Alternatively, a thread can be spawned at compile time by calling
|
Alternatively, a thread can be spawned at compile time by calling
|
||||||
:c:macro:`K_THREAD_DEFINE`. Observe that the macro defines
|
:c:macro:`K_THREAD_DEFINE`. Observe that the macro defines
|
||||||
the stack area and thread id variables automatically.
|
the stack area, control block, and thread id variables automatically.
|
||||||
|
|
||||||
The following code has the same effect as the code segment above.
|
The following code has the same effect as the code segment above.
|
||||||
|
|
||||||
|
@ -231,7 +232,7 @@ APIs
|
||||||
The following thread APIs are provided by :file:`kernel.h`:
|
The following thread APIs are provided by :file:`kernel.h`:
|
||||||
|
|
||||||
* :c:macro:`K_THREAD_DEFINE`
|
* :c:macro:`K_THREAD_DEFINE`
|
||||||
* :cpp:func:`k_thread_spawn()`
|
* :cpp:func:`k_thread_create()`
|
||||||
* :cpp:func:`k_thread_cancel()`
|
* :cpp:func:`k_thread_cancel()`
|
||||||
* :cpp:func:`k_thread_abort()`
|
* :cpp:func:`k_thread_abort()`
|
||||||
* :cpp:func:`k_thread_suspend()`
|
* :cpp:func:`k_thread_suspend()`
|
||||||
|
|
|
@ -149,16 +149,14 @@ Defining a Workqueue
|
||||||
|
|
||||||
A workqueue is defined using a variable of type :c:type:`struct k_work_q`.
|
A workqueue is defined using a variable of type :c:type:`struct k_work_q`.
|
||||||
The workqueue is initialized by defining the stack area used by its thread
|
The workqueue is initialized by defining the stack area used by its thread
|
||||||
and then calling :cpp:func:`k_work_q_start()`. The stack area is an array
|
and then calling :cpp:func:`k_work_q_start()`. The stack area must be defined
|
||||||
of bytes whose size must equal :c:macro:`K_THREAD_SIZEOF` plus the size
|
using the :c:macro:`__stack` attribute to ensure it is properly aligned.
|
||||||
of the thread's stack. The stack area must be defined using the
|
|
||||||
:c:macro:`__stack` attribute to ensure it is properly aligned.
|
|
||||||
|
|
||||||
The following code defines and initializes a workqueue.
|
The following code defines and initializes a workqueue.
|
||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
#define MY_STACK_SIZE (K_THREAD_SIZEOF + 500)
|
#define MY_STACK_SIZE 512
|
||||||
#define MY_PRIORITY 5
|
#define MY_PRIORITY 5
|
||||||
|
|
||||||
char __noinit __stack my_stack_area[MY_STACK_SIZE];
|
char __noinit __stack my_stack_area[MY_STACK_SIZE];
|
||||||
|
|
|
@ -355,6 +355,12 @@ typedef void (*k_thread_entry_t)(void *p1, void *p2, void *p3);
|
||||||
* scheduler may preempt the current thread to allow the new thread to
|
* scheduler may preempt the current thread to allow the new thread to
|
||||||
* execute.
|
* execute.
|
||||||
*
|
*
|
||||||
|
* Kernel data structures for bookkeeping and context storage for this thread
|
||||||
|
* will be placed at the beginning of the thread's stack memory region and may
|
||||||
|
* become corrupted if too much of the stack is used. This function has been
|
||||||
|
* deprecated in favor of k_thread_create() to give the user more control on
|
||||||
|
* where these data structures reside.
|
||||||
|
*
|
||||||
* Thread options are architecture-specific, and can include K_ESSENTIAL,
|
* Thread options are architecture-specific, and can include K_ESSENTIAL,
|
||||||
* K_FP_REGS, and K_SSE_REGS. Multiple options may be specified by separating
|
* K_FP_REGS, and K_SSE_REGS. Multiple options may be specified by separating
|
||||||
* them using "|" (the logical OR operator).
|
* them using "|" (the logical OR operator).
|
||||||
|
@ -371,11 +377,49 @@ typedef void (*k_thread_entry_t)(void *p1, void *p2, void *p3);
|
||||||
*
|
*
|
||||||
* @return ID of new thread.
|
* @return ID of new thread.
|
||||||
*/
|
*/
|
||||||
extern k_tid_t k_thread_spawn(char *stack, size_t stack_size,
|
extern __deprecated k_tid_t k_thread_spawn(char *stack, size_t stack_size,
|
||||||
k_thread_entry_t entry,
|
k_thread_entry_t entry,
|
||||||
void *p1, void *p2, void *p3,
|
void *p1, void *p2, void *p3,
|
||||||
int prio, u32_t options, s32_t delay);
|
int prio, u32_t options, s32_t delay);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a thread.
|
||||||
|
*
|
||||||
|
* This routine initializes a thread, then schedules it for execution.
|
||||||
|
*
|
||||||
|
* The new thread may be scheduled for immediate execution or a delayed start.
|
||||||
|
* If the newly spawned thread does not have a delayed start the kernel
|
||||||
|
* scheduler may preempt the current thread to allow the new thread to
|
||||||
|
* execute.
|
||||||
|
*
|
||||||
|
* Thread options are architecture-specific, and can include K_ESSENTIAL,
|
||||||
|
* K_FP_REGS, and K_SSE_REGS. Multiple options may be specified by separating
|
||||||
|
* them using "|" (the logical OR operator).
|
||||||
|
*
|
||||||
|
* Historically, users often would use the beginning of the stack memory region
|
||||||
|
* to store the struct k_thread data, although corruption will occur if the
|
||||||
|
* stack overflows this region and stack protection features may not detect this
|
||||||
|
* situation.
|
||||||
|
*
|
||||||
|
* @param new_thread Pointer to uninitialized struct k_thread
|
||||||
|
* @param stack Pointer to the stack space.
|
||||||
|
* @param stack_size Stack size in bytes.
|
||||||
|
* @param entry Thread entry function.
|
||||||
|
* @param p1 1st entry point parameter.
|
||||||
|
* @param p2 2nd entry point parameter.
|
||||||
|
* @param p3 3rd entry point parameter.
|
||||||
|
* @param prio Thread priority.
|
||||||
|
* @param options Thread options.
|
||||||
|
* @param delay Scheduling delay (in milliseconds), or K_NO_WAIT (for no delay).
|
||||||
|
*
|
||||||
|
* @return ID of new thread.
|
||||||
|
*/
|
||||||
|
extern k_tid_t k_thread_create(struct k_thread *new_thread, char *stack,
|
||||||
|
size_t stack_size,
|
||||||
|
void (*entry)(void *, void *, void*),
|
||||||
|
void *p1, void *p2, void *p3,
|
||||||
|
int prio, u32_t options, s32_t delay);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Put the current thread to sleep.
|
* @brief Put the current thread to sleep.
|
||||||
*
|
*
|
||||||
|
@ -469,10 +513,8 @@ extern void k_thread_abort(k_tid_t thread);
|
||||||
#define _INACTIVE (-1)
|
#define _INACTIVE (-1)
|
||||||
|
|
||||||
struct _static_thread_data {
|
struct _static_thread_data {
|
||||||
union {
|
struct k_thread *init_thread;
|
||||||
char *init_stack;
|
char *init_stack;
|
||||||
struct k_thread *thread;
|
|
||||||
};
|
|
||||||
unsigned int init_stack_size;
|
unsigned int init_stack_size;
|
||||||
void (*init_entry)(void *, void *, void *);
|
void (*init_entry)(void *, void *, void *);
|
||||||
void *init_p1;
|
void *init_p1;
|
||||||
|
@ -485,11 +527,12 @@ struct _static_thread_data {
|
||||||
u32_t init_groups;
|
u32_t init_groups;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define _THREAD_INITIALIZER(stack, stack_size, \
|
#define _THREAD_INITIALIZER(thread, stack, stack_size, \
|
||||||
entry, p1, p2, p3, \
|
entry, p1, p2, p3, \
|
||||||
prio, options, delay, abort, groups) \
|
prio, options, delay, abort, groups) \
|
||||||
{ \
|
{ \
|
||||||
{.init_stack = (stack)}, \
|
.init_thread = (thread), \
|
||||||
|
.init_stack = (stack), \
|
||||||
.init_stack_size = (stack_size), \
|
.init_stack_size = (stack_size), \
|
||||||
.init_entry = (void (*)(void *, void *, void *))entry, \
|
.init_entry = (void (*)(void *, void *, void *))entry, \
|
||||||
.init_p1 = (void *)p1, \
|
.init_p1 = (void *)p1, \
|
||||||
|
@ -536,13 +579,15 @@ struct _static_thread_data {
|
||||||
#define K_THREAD_DEFINE(name, stack_size, \
|
#define K_THREAD_DEFINE(name, stack_size, \
|
||||||
entry, p1, p2, p3, \
|
entry, p1, p2, p3, \
|
||||||
prio, options, delay) \
|
prio, options, delay) \
|
||||||
char __noinit __stack _k_thread_obj_##name[stack_size]; \
|
char __noinit __stack _k_thread_stack_##name[stack_size]; \
|
||||||
|
struct k_thread _k_thread_obj_##name; \
|
||||||
struct _static_thread_data _k_thread_data_##name __aligned(4) \
|
struct _static_thread_data _k_thread_data_##name __aligned(4) \
|
||||||
__in_section(_static_thread_data, static, name) = \
|
__in_section(_static_thread_data, static, name) = \
|
||||||
_THREAD_INITIALIZER(_k_thread_obj_##name, stack_size, \
|
_THREAD_INITIALIZER(&_k_thread_obj_##name, \
|
||||||
|
_k_thread_stack_##name, stack_size, \
|
||||||
entry, p1, p2, p3, prio, options, delay, \
|
entry, p1, p2, p3, prio, options, delay, \
|
||||||
NULL, 0); \
|
NULL, 0); \
|
||||||
const k_tid_t name = (k_tid_t)_k_thread_obj_##name
|
const k_tid_t name = (k_tid_t)&_k_thread_obj_##name
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get a thread's priority.
|
* @brief Get a thread's priority.
|
||||||
|
@ -1795,6 +1840,7 @@ typedef void (*k_work_handler_t)(struct k_work *work);
|
||||||
|
|
||||||
struct k_work_q {
|
struct k_work_q {
|
||||||
struct k_fifo fifo;
|
struct k_fifo fifo;
|
||||||
|
struct k_thread thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -142,20 +142,19 @@ extern void _init_thread_base(struct _thread_base *thread_base,
|
||||||
int priority, u32_t initial_state,
|
int priority, u32_t initial_state,
|
||||||
unsigned int options);
|
unsigned int options);
|
||||||
|
|
||||||
static ALWAYS_INLINE struct k_thread *_new_thread_init(char *pStack,
|
static ALWAYS_INLINE void _new_thread_init(struct k_thread *thread,
|
||||||
size_t stackSize,
|
char *pStack, size_t stackSize,
|
||||||
int prio,
|
int prio, unsigned int options)
|
||||||
unsigned int options)
|
|
||||||
{
|
{
|
||||||
struct k_thread *thread;
|
#if !defined(CONFIG_INIT_STACKS) && !defined(CONFIG_THREAD_STACK_INFO)
|
||||||
|
ARG_UNUSED(pStack);
|
||||||
|
ARG_UNUSED(stackSize);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_INIT_STACKS
|
#ifdef CONFIG_INIT_STACKS
|
||||||
memset(pStack, 0xaa, stackSize);
|
memset(pStack, 0xaa, stackSize);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Initialize various struct k_thread members */
|
/* Initialize various struct k_thread members */
|
||||||
thread = (struct k_thread *)pStack;
|
|
||||||
|
|
||||||
_init_thread_base(&thread->base, prio, _THREAD_PRESTART, options);
|
_init_thread_base(&thread->base, prio, _THREAD_PRESTART, options);
|
||||||
|
|
||||||
/* static threads overwrite it afterwards with real value */
|
/* static threads overwrite it afterwards with real value */
|
||||||
|
@ -171,8 +170,6 @@ static ALWAYS_INLINE struct k_thread *_new_thread_init(char *pStack,
|
||||||
thread->stack_info.start = (u32_t)pStack;
|
thread->stack_info.start = (u32_t)pStack;
|
||||||
thread->stack_info.size = (u32_t)stackSize;
|
thread->stack_info.size = (u32_t)stackSize;
|
||||||
#endif /* CONFIG_THREAD_STACK_INFO */
|
#endif /* CONFIG_THREAD_STACK_INFO */
|
||||||
|
|
||||||
return thread;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_THREAD_MONITOR)
|
#if defined(CONFIG_THREAD_MONITOR)
|
||||||
|
|
|
@ -43,7 +43,7 @@ FUNC_NORETURN void _Cstart(void);
|
||||||
extern void _thread_entry(void (*)(void *, void *, void *),
|
extern void _thread_entry(void (*)(void *, void *, void *),
|
||||||
void *, void *, void *);
|
void *, void *, void *);
|
||||||
|
|
||||||
extern void _new_thread(char *pStack, size_t stackSize,
|
extern void _new_thread(struct k_thread *thread, char *pStack, size_t stackSize,
|
||||||
void (*pEntry)(void *, void *, void *),
|
void (*pEntry)(void *, void *, void *),
|
||||||
void *p1, void *p2, void *p3,
|
void *p1, void *p2, void *p3,
|
||||||
int prio, unsigned int options);
|
int prio, unsigned int options);
|
||||||
|
|
|
@ -81,8 +81,11 @@ u64_t __noinit __end_tick_tsc;
|
||||||
char __noinit __stack _main_stack[MAIN_STACK_SIZE];
|
char __noinit __stack _main_stack[MAIN_STACK_SIZE];
|
||||||
char __noinit __stack _idle_stack[IDLE_STACK_SIZE];
|
char __noinit __stack _idle_stack[IDLE_STACK_SIZE];
|
||||||
|
|
||||||
k_tid_t const _main_thread = (k_tid_t)_main_stack;
|
static struct k_thread _main_thread_s;
|
||||||
k_tid_t const _idle_thread = (k_tid_t)_idle_stack;
|
static struct k_thread _idle_thread_s;
|
||||||
|
|
||||||
|
k_tid_t const _main_thread = (k_tid_t)&_main_thread_s;
|
||||||
|
k_tid_t const _idle_thread = (k_tid_t)&_idle_thread_s;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* storage space for the interrupt stack
|
* storage space for the interrupt stack
|
||||||
|
@ -271,15 +274,15 @@ static void prepare_multithreading(struct k_thread *dummy_thread)
|
||||||
*/
|
*/
|
||||||
_ready_q.cache = _main_thread;
|
_ready_q.cache = _main_thread;
|
||||||
|
|
||||||
_new_thread(_main_stack, MAIN_STACK_SIZE,
|
_new_thread(_main_thread, _main_stack,
|
||||||
_main, NULL, NULL, NULL,
|
MAIN_STACK_SIZE, _main, NULL, NULL, NULL,
|
||||||
CONFIG_MAIN_THREAD_PRIORITY, K_ESSENTIAL);
|
CONFIG_MAIN_THREAD_PRIORITY, K_ESSENTIAL);
|
||||||
_mark_thread_as_started(_main_thread);
|
_mark_thread_as_started(_main_thread);
|
||||||
_add_thread_to_ready_q(_main_thread);
|
_add_thread_to_ready_q(_main_thread);
|
||||||
|
|
||||||
#ifdef CONFIG_MULTITHREADING
|
#ifdef CONFIG_MULTITHREADING
|
||||||
_new_thread(_idle_stack, IDLE_STACK_SIZE,
|
_new_thread(_idle_thread, _idle_stack,
|
||||||
idle, NULL, NULL, NULL,
|
IDLE_STACK_SIZE, idle, NULL, NULL, NULL,
|
||||||
K_LOWEST_THREAD_PRIO, K_ESSENTIAL);
|
K_LOWEST_THREAD_PRIO, K_ESSENTIAL);
|
||||||
_mark_thread_as_started(_idle_thread);
|
_mark_thread_as_started(_idle_thread);
|
||||||
_add_thread_to_ready_q(_idle_thread);
|
_add_thread_to_ready_q(_idle_thread);
|
||||||
|
@ -295,7 +298,8 @@ static void prepare_multithreading(struct k_thread *dummy_thread)
|
||||||
static void switch_to_main_thread(void)
|
static void switch_to_main_thread(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN
|
#ifdef CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN
|
||||||
_arch_switch_to_main_thread(_main_stack, MAIN_STACK_SIZE, _main);
|
_arch_switch_to_main_thread(_main_thread, _main_stack, MAIN_STACK_SIZE,
|
||||||
|
_main);
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
* Context switch to main task (entry function is _main()): the
|
* Context switch to main task (entry function is _main()): the
|
||||||
|
|
|
@ -208,21 +208,32 @@ static void schedule_new_thread(struct k_thread *thread, s32_t delay)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_MULTITHREADING
|
#ifdef CONFIG_MULTITHREADING
|
||||||
|
|
||||||
|
k_tid_t k_thread_create(struct k_thread *new_thread, char *stack,
|
||||||
|
size_t stack_size, void (*entry)(void *, void *, void*),
|
||||||
|
void *p1, void *p2, void *p3,
|
||||||
|
int prio, u32_t options, s32_t delay)
|
||||||
|
{
|
||||||
|
__ASSERT(!_is_in_isr(), "Threads may not be created in ISRs");
|
||||||
|
_new_thread(new_thread, stack, stack_size, entry, p1, p2, p3, prio,
|
||||||
|
options);
|
||||||
|
|
||||||
|
schedule_new_thread(new_thread, delay);
|
||||||
|
return new_thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
k_tid_t k_thread_spawn(char *stack, size_t stack_size,
|
k_tid_t k_thread_spawn(char *stack, size_t stack_size,
|
||||||
void (*entry)(void *, void *, void*),
|
void (*entry)(void *, void *, void*),
|
||||||
void *p1, void *p2, void *p3,
|
void *p1, void *p2, void *p3,
|
||||||
int prio, u32_t options, s32_t delay)
|
int prio, u32_t options, s32_t delay)
|
||||||
{
|
{
|
||||||
__ASSERT(!_is_in_isr(), "");
|
|
||||||
|
|
||||||
struct k_thread *new_thread = (struct k_thread *)stack;
|
struct k_thread *new_thread = (struct k_thread *)stack;
|
||||||
|
|
||||||
_new_thread(stack, stack_size, entry, p1, p2, p3, prio, options);
|
return k_thread_create(new_thread, stack, stack_size, entry, p1, p2,
|
||||||
|
p3, prio, options, delay);
|
||||||
schedule_new_thread(new_thread, delay);
|
|
||||||
|
|
||||||
return new_thread;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int k_thread_cancel(k_tid_t tid)
|
int k_thread_cancel(k_tid_t tid)
|
||||||
|
@ -264,7 +275,7 @@ void _k_thread_group_op(u32_t groups, void (*func)(struct k_thread *))
|
||||||
_FOREACH_STATIC_THREAD(thread_data) {
|
_FOREACH_STATIC_THREAD(thread_data) {
|
||||||
if (is_in_any_group(thread_data, groups)) {
|
if (is_in_any_group(thread_data, groups)) {
|
||||||
key = irq_lock();
|
key = irq_lock();
|
||||||
func(thread_data->thread);
|
func(thread_data->init_thread);
|
||||||
irq_unlock(key);
|
irq_unlock(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -359,6 +370,7 @@ void _init_static_threads(void)
|
||||||
|
|
||||||
_FOREACH_STATIC_THREAD(thread_data) {
|
_FOREACH_STATIC_THREAD(thread_data) {
|
||||||
_new_thread(
|
_new_thread(
|
||||||
|
thread_data->init_thread,
|
||||||
thread_data->init_stack,
|
thread_data->init_stack,
|
||||||
thread_data->init_stack_size,
|
thread_data->init_stack_size,
|
||||||
thread_data->init_entry,
|
thread_data->init_entry,
|
||||||
|
@ -368,7 +380,7 @@ void _init_static_threads(void)
|
||||||
thread_data->init_prio,
|
thread_data->init_prio,
|
||||||
thread_data->init_options);
|
thread_data->init_options);
|
||||||
|
|
||||||
thread_data->thread->init_data = thread_data;
|
thread_data->init_thread->init_data = thread_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
_sched_lock();
|
_sched_lock();
|
||||||
|
@ -385,7 +397,7 @@ void _init_static_threads(void)
|
||||||
key = irq_lock();
|
key = irq_lock();
|
||||||
_FOREACH_STATIC_THREAD(thread_data) {
|
_FOREACH_STATIC_THREAD(thread_data) {
|
||||||
if (thread_data->init_delay != K_FOREVER) {
|
if (thread_data->init_delay != K_FOREVER) {
|
||||||
schedule_new_thread(thread_data->thread,
|
schedule_new_thread(thread_data->init_thread,
|
||||||
thread_data->init_delay);
|
thread_data->init_delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,9 +48,8 @@ void k_work_q_start(struct k_work_q *work_q, char *stack,
|
||||||
{
|
{
|
||||||
k_fifo_init(&work_q->fifo);
|
k_fifo_init(&work_q->fifo);
|
||||||
|
|
||||||
k_thread_spawn(stack, stack_size,
|
k_thread_create(&work_q->thread, stack, stack_size, work_q_main,
|
||||||
work_q_main, work_q, 0, 0,
|
work_q, 0, 0, prio, 0, 0);
|
||||||
prio, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SYS_CLOCK_EXISTS
|
#ifdef CONFIG_SYS_CLOCK_EXISTS
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue