zephyr/doc/kernel/threads/lifecycle.rst

239 lines
7.7 KiB
ReStructuredText

.. _lifecycle_v2:
Lifecycle
#########
A :dfn:`thread` is a kernel object that is used for application processing
that is too lengthy or too complex to be performed by an ISR.
.. contents::
:local:
:depth: 2
Concepts
********
Any number of threads can be defined by an application. Each thread is
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.
The **size** of the stack area can be tailored to conform to the actual needs
of the thread's processing.
* An **entry point function**, which is invoked when the thread is started.
Up to 3 **argument values** can be passed to this function.
* A **scheduling priority**, which instructs the kernel's scheduler how to
allocate CPU time to the thread. (See :ref:`scheduling_v2`.)
* A set of **thread options**, which allow the thread to receive special
treatment by the kernel under specific circumstances.
(See :ref:`thread_options_v2`.)
* A **start delay**, which specifies how long the kernel should wait before
starting the thread.
.. _spawning_thread:
Thread Spawning
===============
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.
Specifying a start delay of :c:macro:`K_NO_WAIT` instructs the kernel
to start thread execution immediately. Alternatively, the kernel can be
instructed to delay execution of the thread by specifying a timeout
value -- for example, to allow device hardware used by the thread
to become available.
The kernel allows a delayed start to be cancelled before the thread begins
executing. A cancellation request has no effect if the thread has already
started. A thread whose delayed start was successfully cancelled must be
re-spawned before it can be used.
Thread Termination
==================
Once a thread is started it typically executes forever. However, a thread may
synchronously end its execution by returning from its entry point function.
This is known as **termination**.
A thread that terminates is responsible for releasing any shared resources
it may own (such as mutexes and dynamically allocated memory)
prior to returning, since the kernel does *not* reclaim them automatically.
.. note::
The kernel does not currently make any claims regarding an application's
ability to respawn a thread that terminates.
Thread Aborting
===============
A thread may asynchronously end its execution by **aborting**. The kernel
automatically aborts a thread if the thread triggers a fatal error condition,
such as dereferencing a null pointer.
A thread can also be aborted by another thread (or by itself)
by calling :cpp:func:`k_thread_abort()`. However, it is typically preferable
to signal a thread to terminate itself gracefully, rather than aborting it.
As with thread termination, the kernel does not reclaim shared resources
owned by an aborted thread.
.. note::
The kernel does not currently make any claims regarding an application's
ability to respawn a thread that aborts.
Thread Suspension
=================
A thread can be prevented from executing for an indefinite period of time
if it becomes **suspended**. The function :cpp:func:`k_thread_suspend()`
can be used to suspend any thread, including the calling thread.
Suspending a thread that is already suspended has no additional effect.
Once suspended, a thread cannot be scheduled until another thread calls
:cpp:func:`k_thread_resume()` to remove the suspension.
.. note::
A thread can prevent itself from executing for a specified period of time
using :cpp:func:`k_sleep()`. However, this is different from suspending
a thread since a sleeping thread becomes executable automatically when the
time limit is reached.
.. _thread_options_v2:
Thread Options
==============
The kernel supports a small set of :dfn:`thread options` that allow a thread
to receive special treatment under specific circumstances. The set of options
associated with a thread are specified when the thread is spawned.
A thread that does not require any thread option has an option value of zero.
A thread that requires a thread option specifies it by name, using the
:literal:`|` character as a separator if multiple options are needed
(i.e. combine options using the bitwise OR operator).
The following thread options are supported.
:c:macro:`K_ESSENTIAL`
This option tags the thread as an :dfn:`essential thread`. This instructs
the kernel to treat the termination or aborting of the thread as a fatal
system error.
By default, the thread is not considered to be an essential thread.
:c:macro:`K_FP_REGS` and :c:macro:`K_SSE_REGS`
These x86-specific options indicate that the thread uses the CPU's
floating point registers and SSE registers, respectively. This instructs
the kernel to take additional steps to save and restore the contents
of these registers when scheduling the thread.
(For more information see :ref:`float_v2`.)
By default, the kernel does not attempt to save and restore the contents
of these registers when scheduling the thread.
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.
The thread spawning function returns its thread id, which can be used
to reference the thread.
The following code spawns a thread that starts immediately.
.. code-block:: c
#define MY_STACK_SIZE 500
#define MY_PRIORITY 5
extern void my_entry_point(void *, void *, void *);
char __noinit __stack my_stack_area[MY_STACK_SIZE];
k_tid_t my_tid = k_thread_spawn(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 following code has the same effect as the code segment above.
.. code-block:: c
#define MY_STACK_SIZE 500
#define MY_PRIORITY 5
extern void my_entry_point(void *, void *, void *);
K_THREAD_DEFINE(my_tid, MY_STACK_SIZE,
my_entry_point, NULL, NULL, NULL,
MY_PRIORITY, 0, K_NO_WAIT);
Terminating a Thread
====================
A thread terminates itself by returning from its entry point function.
The following code illustrates the ways a thread can terminate.
.. code-block:: c
void my_entry_point(int unused1, int unused2, int unused3)
{
while (1) {
...
if (<some condition>) {
return; /* thread terminates from mid-entry point function */
}
...
}
/* thread terminates at end of entry point function */
}
Suggested Uses
**************
Use threads to handle processing that cannot be handled in an ISR.
Use separate threads to handle logically distinct processing operations
that can execute in parallel.
Configuration Options
*********************
Related configuration options:
* None.
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_cancel()`
* :cpp:func:`k_thread_abort()`
* :cpp:func:`k_thread_suspend()`
* :cpp:func:`k_thread_resume()`