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
|
||||
*/
|
||||
void _new_thread(char *pStackMem, size_t stackSize,
|
||||
void _new_thread(struct k_thread *thread, char *pStackMem, size_t stackSize,
|
||||
_thread_entry_t pEntry,
|
||||
void *parameter1, void *parameter2, void *parameter3,
|
||||
int priority, unsigned int options)
|
||||
|
@ -64,12 +64,9 @@ void _new_thread(char *pStackMem, size_t stackSize,
|
|||
char *stackEnd = pStackMem + stackSize;
|
||||
struct init_stack_frame *pInitCtx;
|
||||
|
||||
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 */
|
||||
|
||||
pInitCtx = (struct init_stack_frame *)(STACK_ROUND_DOWN(stackEnd) -
|
||||
sizeof(struct init_stack_frame));
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
* @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,
|
||||
void *parameter1, void *parameter2, void *parameter3,
|
||||
int priority, unsigned int options)
|
||||
|
@ -62,9 +62,8 @@ void _new_thread(char *pStackMem, size_t stackSize,
|
|||
|
||||
char *stackEnd = pStackMem + stackSize;
|
||||
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 */
|
||||
|
||||
|
|
|
@ -38,8 +38,8 @@ static ALWAYS_INLINE void kernel_arch_init(void)
|
|||
}
|
||||
|
||||
static ALWAYS_INLINE void
|
||||
_arch_switch_to_main_thread(char *main_stack, size_t main_stack_size,
|
||||
_thread_entry_t _main)
|
||||
_arch_switch_to_main_thread(struct k_thread *main_thread, char *main_stack,
|
||||
size_t main_stack_size, _thread_entry_t _main)
|
||||
{
|
||||
/* get high address of the stack, i.e. its start (stack grows down) */
|
||||
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 = (void *)STACK_ROUND_DOWN(start_of_main_stack);
|
||||
|
||||
_current = (void *)main_stack;
|
||||
_current = 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,
|
||||
void *arg1, void *arg2, void *arg3,
|
||||
int priority, unsigned int options)
|
||||
{
|
||||
_ASSERT_VALID_PRIO(priority, thread_func);
|
||||
|
||||
struct k_thread *thread;
|
||||
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 */
|
||||
iframe = (struct init_stack_frame *)
|
||||
|
|
|
@ -15,17 +15,16 @@ void _thread_entry_wrapper(_thread_entry_t thread,
|
|||
void *arg2,
|
||||
void *arg3);
|
||||
|
||||
void _new_thread(char *stack_memory, size_t stack_size,
|
||||
_thread_entry_t thread_func,
|
||||
void _new_thread(struct k_thread *thread, char *stack_memory,
|
||||
size_t stack_size, _thread_entry_t thread_func,
|
||||
void *arg1, void *arg2, void *arg3,
|
||||
int priority, unsigned int options)
|
||||
{
|
||||
_ASSERT_VALID_PRIO(priority, thread_func);
|
||||
|
||||
struct k_thread *thread;
|
||||
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 */
|
||||
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.
|
||||
*
|
||||
* @param thread pointer to thread struct memory
|
||||
* @param pStackMem pointer to thread stack memory
|
||||
* @param stackSize size of a stack in bytes
|
||||
* @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
|
||||
* threads and kernel tasks.
|
||||
*
|
||||
* The k_thread structure is carved from the "end" of the specified
|
||||
* thread stack memory.
|
||||
*
|
||||
* @param thread pointer to thread struct memory, including any space needed
|
||||
* for extra coprocessor context
|
||||
* @param pStackmem the pointer to aligned stack memory
|
||||
* @param stackSize the stack size in bytes
|
||||
* @param pEntry thread entry point routine
|
||||
|
@ -195,7 +195,7 @@ __asm__("\t.globl _thread_entry\n"
|
|||
*
|
||||
* @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,
|
||||
void *parameter1, void *parameter2, void *parameter3,
|
||||
int priority, unsigned int options)
|
||||
|
@ -203,9 +203,8 @@ void _new_thread(char *pStackMem, size_t stackSize,
|
|||
_ASSERT_VALID_PRIO(priority, pEntry);
|
||||
|
||||
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 */
|
||||
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
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
|
||||
* the other end of the stack, and thus reusable by the stack when not
|
||||
* needed anymore.
|
||||
|
@ -29,6 +29,7 @@ extern void _xt_user_exit(void);
|
|||
*
|
||||
* <options> is currently unused.
|
||||
*
|
||||
* @param thread pointer to k_thread memory
|
||||
* @param pStackmem the pointer to aligned stack memory
|
||||
* @param stackSize the stack size in bytes
|
||||
* @param pEntry thread entry point routine
|
||||
|
@ -41,23 +42,19 @@ extern void _xt_user_exit(void);
|
|||
* @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 *p1, void *p2, void *p3,
|
||||
int priority, unsigned int options)
|
||||
{
|
||||
/* Align stack end to maximum alignment requirement. */
|
||||
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
|
||||
u32_t *cpSA;
|
||||
char *cpStack;
|
||||
#endif
|
||||
|
||||
thread = _new_thread_init(pStack, stackSize, priority, options);
|
||||
_new_thread_init(thread, pStack, stackSize, priority, options);
|
||||
|
||||
#ifdef CONFIG_DEBUG
|
||||
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
|
||||
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_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
|
||||
: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
|
||||
: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 **stack area**, which is a region of memory used for the thread's
|
||||
control block (of type :c:type:`struct k_thread`) and for its stack.
|
||||
* A **stack area**, which is a region of memory used for the thread's stack.
|
||||
The **size** of the stack area can be tailored to conform to the actual needs
|
||||
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.
|
||||
Up to 3 **argument values** can be passed to this function.
|
||||
|
||||
|
@ -38,13 +40,12 @@ A thread has the following key properties:
|
|||
|
||||
.. _spawning_thread:
|
||||
|
||||
Thread Spawning
|
||||
Thread Creation
|
||||
===============
|
||||
|
||||
A thread must be spawned before it can be used. The kernel initializes
|
||||
the control block portion of the thread's stack area, as well as one
|
||||
end of the stack portion. The remainder of the thread's stack is typically
|
||||
left uninitialized.
|
||||
A thread must be created before it can be used. The kernel initializes
|
||||
the thread control block as well as one end of the stack portion. The remainder
|
||||
of the thread's stack is typically left uninitialized.
|
||||
|
||||
Specifying a start delay of :c:macro:`K_NO_WAIT` instructs the kernel
|
||||
to start thread execution immediately. Alternatively, the kernel can be
|
||||
|
@ -146,11 +147,9 @@ Implementation
|
|||
Spawning a Thread
|
||||
=================
|
||||
|
||||
A thread is spawned by defining its stack area and then calling
|
||||
:cpp:func:`k_thread_spawn()`. The stack area is an array of bytes
|
||||
whose size must equal :c:macro:`K_THREAD_SIZEOF` plus the size
|
||||
of the thread's stack. The stack area must be defined using the
|
||||
:c:macro:`__stack` attribute to ensure it is properly aligned.
|
||||
A thread is spawned by defining its stack area and its thread control block,
|
||||
and then calling :cpp:func:`k_thread_create()`. 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
|
||||
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 *);
|
||||
|
||||
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,
|
||||
my_entry_point, NULL, NULL, NULL,
|
||||
k_tid_t my_tid = k_thread_create(&my_thread_data, my_stack_area,
|
||||
MY_STACK_SIZE, my_entry_point,
|
||||
NULL, NULL, NULL,
|
||||
MY_PRIORITY, 0, K_NO_WAIT);
|
||||
|
||||
Alternatively, a thread can be spawned at compile time by calling
|
||||
: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.
|
||||
|
||||
|
@ -231,7 +232,7 @@ APIs
|
|||
The following thread APIs are provided by :file:`kernel.h`:
|
||||
|
||||
* :c:macro:`K_THREAD_DEFINE`
|
||||
* :cpp:func:`k_thread_spawn()`
|
||||
* :cpp:func:`k_thread_create()`
|
||||
* :cpp:func:`k_thread_cancel()`
|
||||
* :cpp:func:`k_thread_abort()`
|
||||
* :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`.
|
||||
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
|
||||
of bytes whose size must equal :c:macro:`K_THREAD_SIZEOF` plus the size
|
||||
of the thread's stack. The stack area must be defined using the
|
||||
:c:macro:`__stack` attribute to ensure it is properly aligned.
|
||||
and then calling :cpp:func:`k_work_q_start()`. 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.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define MY_STACK_SIZE (K_THREAD_SIZEOF + 500)
|
||||
#define MY_STACK_SIZE 512
|
||||
#define MY_PRIORITY 5
|
||||
|
||||
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
|
||||
* 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,
|
||||
* K_FP_REGS, and K_SSE_REGS. Multiple options may be specified by separating
|
||||
* 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.
|
||||
*/
|
||||
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,
|
||||
void *p1, void *p2, void *p3,
|
||||
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.
|
||||
*
|
||||
|
@ -469,10 +513,8 @@ extern void k_thread_abort(k_tid_t thread);
|
|||
#define _INACTIVE (-1)
|
||||
|
||||
struct _static_thread_data {
|
||||
union {
|
||||
struct k_thread *init_thread;
|
||||
char *init_stack;
|
||||
struct k_thread *thread;
|
||||
};
|
||||
unsigned int init_stack_size;
|
||||
void (*init_entry)(void *, void *, void *);
|
||||
void *init_p1;
|
||||
|
@ -485,11 +527,12 @@ struct _static_thread_data {
|
|||
u32_t init_groups;
|
||||
};
|
||||
|
||||
#define _THREAD_INITIALIZER(stack, stack_size, \
|
||||
#define _THREAD_INITIALIZER(thread, stack, stack_size, \
|
||||
entry, p1, p2, p3, \
|
||||
prio, options, delay, abort, groups) \
|
||||
{ \
|
||||
{.init_stack = (stack)}, \
|
||||
.init_thread = (thread), \
|
||||
.init_stack = (stack), \
|
||||
.init_stack_size = (stack_size), \
|
||||
.init_entry = (void (*)(void *, void *, void *))entry, \
|
||||
.init_p1 = (void *)p1, \
|
||||
|
@ -536,13 +579,15 @@ struct _static_thread_data {
|
|||
#define K_THREAD_DEFINE(name, stack_size, \
|
||||
entry, p1, p2, p3, \
|
||||
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) \
|
||||
__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, \
|
||||
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.
|
||||
|
@ -1795,6 +1840,7 @@ typedef void (*k_work_handler_t)(struct k_work *work);
|
|||
|
||||
struct k_work_q {
|
||||
struct k_fifo fifo;
|
||||
struct k_thread thread;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
|
@ -142,20 +142,19 @@ extern void _init_thread_base(struct _thread_base *thread_base,
|
|||
int priority, u32_t initial_state,
|
||||
unsigned int options);
|
||||
|
||||
static ALWAYS_INLINE struct k_thread *_new_thread_init(char *pStack,
|
||||
size_t stackSize,
|
||||
int prio,
|
||||
unsigned int options)
|
||||
static ALWAYS_INLINE void _new_thread_init(struct k_thread *thread,
|
||||
char *pStack, size_t stackSize,
|
||||
int prio, 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
|
||||
memset(pStack, 0xaa, stackSize);
|
||||
#endif
|
||||
|
||||
/* Initialize various struct k_thread members */
|
||||
thread = (struct k_thread *)pStack;
|
||||
|
||||
_init_thread_base(&thread->base, prio, _THREAD_PRESTART, options);
|
||||
|
||||
/* 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.size = (u32_t)stackSize;
|
||||
#endif /* CONFIG_THREAD_STACK_INFO */
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_THREAD_MONITOR)
|
||||
|
|
|
@ -43,7 +43,7 @@ FUNC_NORETURN void _Cstart(void);
|
|||
extern void _thread_entry(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 *p1, void *p2, void *p3,
|
||||
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 _idle_stack[IDLE_STACK_SIZE];
|
||||
|
||||
k_tid_t const _main_thread = (k_tid_t)_main_stack;
|
||||
k_tid_t const _idle_thread = (k_tid_t)_idle_stack;
|
||||
static struct k_thread _main_thread_s;
|
||||
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
|
||||
|
@ -271,15 +274,15 @@ static void prepare_multithreading(struct k_thread *dummy_thread)
|
|||
*/
|
||||
_ready_q.cache = _main_thread;
|
||||
|
||||
_new_thread(_main_stack, MAIN_STACK_SIZE,
|
||||
_main, NULL, NULL, NULL,
|
||||
_new_thread(_main_thread, _main_stack,
|
||||
MAIN_STACK_SIZE, _main, NULL, NULL, NULL,
|
||||
CONFIG_MAIN_THREAD_PRIORITY, K_ESSENTIAL);
|
||||
_mark_thread_as_started(_main_thread);
|
||||
_add_thread_to_ready_q(_main_thread);
|
||||
|
||||
#ifdef CONFIG_MULTITHREADING
|
||||
_new_thread(_idle_stack, IDLE_STACK_SIZE,
|
||||
idle, NULL, NULL, NULL,
|
||||
_new_thread(_idle_thread, _idle_stack,
|
||||
IDLE_STACK_SIZE, idle, NULL, NULL, NULL,
|
||||
K_LOWEST_THREAD_PRIO, K_ESSENTIAL);
|
||||
_mark_thread_as_started(_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)
|
||||
{
|
||||
#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
|
||||
/*
|
||||
* 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
|
||||
|
||||
#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,
|
||||
void (*entry)(void *, void *, void*),
|
||||
void *p1, void *p2, void *p3,
|
||||
int prio, u32_t options, s32_t delay)
|
||||
{
|
||||
__ASSERT(!_is_in_isr(), "");
|
||||
|
||||
struct k_thread *new_thread = (struct k_thread *)stack;
|
||||
|
||||
_new_thread(stack, stack_size, entry, p1, p2, p3, prio, options);
|
||||
|
||||
schedule_new_thread(new_thread, delay);
|
||||
|
||||
return new_thread;
|
||||
return k_thread_create(new_thread, stack, stack_size, entry, p1, p2,
|
||||
p3, prio, options, delay);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
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) {
|
||||
if (is_in_any_group(thread_data, groups)) {
|
||||
key = irq_lock();
|
||||
func(thread_data->thread);
|
||||
func(thread_data->init_thread);
|
||||
irq_unlock(key);
|
||||
}
|
||||
}
|
||||
|
@ -359,6 +370,7 @@ void _init_static_threads(void)
|
|||
|
||||
_FOREACH_STATIC_THREAD(thread_data) {
|
||||
_new_thread(
|
||||
thread_data->init_thread,
|
||||
thread_data->init_stack,
|
||||
thread_data->init_stack_size,
|
||||
thread_data->init_entry,
|
||||
|
@ -368,7 +380,7 @@ void _init_static_threads(void)
|
|||
thread_data->init_prio,
|
||||
thread_data->init_options);
|
||||
|
||||
thread_data->thread->init_data = thread_data;
|
||||
thread_data->init_thread->init_data = thread_data;
|
||||
}
|
||||
|
||||
_sched_lock();
|
||||
|
@ -385,7 +397,7 @@ void _init_static_threads(void)
|
|||
key = irq_lock();
|
||||
_FOREACH_STATIC_THREAD(thread_data) {
|
||||
if (thread_data->init_delay != K_FOREVER) {
|
||||
schedule_new_thread(thread_data->thread,
|
||||
schedule_new_thread(thread_data->init_thread,
|
||||
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_thread_spawn(stack, stack_size,
|
||||
work_q_main, work_q, 0, 0,
|
||||
prio, 0, 0);
|
||||
k_thread_create(&work_q->thread, stack, stack_size, work_q_main,
|
||||
work_q, 0, 0, prio, 0, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_CLOCK_EXISTS
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue