134 lines
4.5 KiB
ReStructuredText
134 lines
4.5 KiB
ReStructuredText
=================================
|
|
Kernel Threads with Custom Stacks
|
|
=================================
|
|
|
|
.. warning::
|
|
Migrated from:
|
|
https://cwiki.apache.org/confluence/display/NUTTX/Kernel+Threads+with+Custom+Stacks
|
|
|
|
|
|
Background
|
|
==========
|
|
|
|
Under certain conditions, it may be necessary to create a kernel thread whose
|
|
stack lives in some custom memory. This page provides and example of how that
|
|
would be done:
|
|
|
|
Example
|
|
=======
|
|
|
|
Here is the body of some function. It expects to have the following inputs:
|
|
|
|
1. ``taskname``: The name of the kernel thread to be started
|
|
2. ``stacksize``: The size of the custom stack
|
|
3. ``priority``: The priority of the kernel thread to be started
|
|
4. ``entry_point``: The entry point of the kernel thread to be started
|
|
5. ``argv``: An optional array of argument strings passed to the kernel thread
|
|
|
|
.. code-block:: c
|
|
|
|
/* Allocate a TCB for the new kernel thread. kmm_zalloc() is
|
|
* used to that all fields of the new TCB will be zeroed.
|
|
*/
|
|
|
|
tcb = (FAR struct task_tcb_s *)kmm_zalloc(sizeof(struct task_tcb_s));
|
|
if (tcb == NULL)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Indicate (1) that this is a kernel thread and that (2) a custom
|
|
* stack will be used.
|
|
*/
|
|
|
|
tcb->flags = TCB_FLAG_TTYPE_KERNEL | TCB_FLAG_CUSTOM_STACK;
|
|
|
|
/* Allocate the custom stack for the new kernel thread.
|
|
*
|
|
* Do whatever it takes to get a reference to the custom stack.
|
|
* Here custom_alloc() is used as a placeholder for whatever
|
|
* that may be.
|
|
*/
|
|
|
|
stack = (FAR uint32_t *)custom_alloc(stacksize);
|
|
if (stack == NULL)
|
|
{
|
|
kmm_free(tcb);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Initialize the TCB. This will initialize all remaining
|
|
* fields of the TCB, associate the stack to the TCB, allocate
|
|
* any additional resources needed by the kernel thread, and
|
|
* place the TCB in a list of inactive tasks.
|
|
*/
|
|
|
|
ret = task_init((FAR struct tcb_s *)tcb, progname, priority,
|
|
stack, stacksize, entry_point, argv);
|
|
if (ret < 0)
|
|
{
|
|
kmm_free(tcb);
|
|
custom_free(stack);
|
|
return ret;
|
|
}
|
|
|
|
/* Then activate the kernel thread at the provided priority */
|
|
|
|
ret = task_activate((FAR struct tcb_s *)tcb);
|
|
if (ret < 0)
|
|
{
|
|
/* nxtask_unit() will undo all of the operations of nxtask_init().
|
|
* It also has the side-effect of freeing the TCB which it assumes
|
|
* was allocated with one of the kmm_malloc()functions.
|
|
*/
|
|
|
|
nxtask_uninit(tcb);
|
|
custom_free(stack);
|
|
return ret;
|
|
}
|
|
|
|
return OK;
|
|
|
|
|
|
Freeing the TCB
|
|
===============
|
|
|
|
Prior to calling ``nxtask_init()``, the TCB can be freed using the kmm
|
|
allocator, specifically the function ``kmm_free()``. However, after
|
|
``nxtask_init()`` is called, additional resources will be associated with the
|
|
TCB and you must then call ``nxtask_uninit()`` to free the TCB and all of its
|
|
associated resources. ``kmm_free()`` will be used internally by
|
|
``nxtask_uninit()`` to free the TCB. Note that in any event, the TCB must be
|
|
allocated with one of the ``kmm_malloc()`` allocation functions.
|
|
|
|
You must never free the TCB after ``nxtask_activate()`` returns successfully.
|
|
|
|
Freeing the Custom Stack Memory
|
|
===============================
|
|
|
|
The effect of the ``TCB_FLAG_CUSTOM_STACK`` flag is that the OS will not
|
|
attempt to free the custom stack memory if the kernel thread exits, crashes,
|
|
or is killed. Does this matter in your implementation? Could this result in
|
|
some kind of memory leak? If any kind of clean-up is required by your
|
|
application to free the custom stack memory, you will probably want to use
|
|
an ``on_exit()`` or ``atexit()`` function to get a callback when the kernel
|
|
thread is terminated.
|
|
|
|
If ``TCB_FLAG_CUSTOM_STACK`` were not set in the TCB flags, the OS would
|
|
attempt to free the stack using ``kmm_free()`` which is probably not what you
|
|
want in this case.
|
|
|
|
The actual logic is a slightly more complex and somewhat redundant:
|
|
|
|
* If ``TCB_FLAG_CUSTOM_STACK`` is set in the TCB flags, no attempt will be made
|
|
to free the custom stack.
|
|
* If ``TCB_FLAG_CUSTOM_STACK`` is not set in the TCB flags, the stack will be
|
|
de-allocated for the kernel thread only if the stack lies in the kernel
|
|
memory pool.
|
|
|
|
So in reality ``TCB_FLAG_CUSTOM_STACK`` may not be necessary. But the safest
|
|
option is to include it in all cases where you do not expect the custom stack
|
|
to be de-allocated.
|
|
|
|
You must not free the custom stack after ``nxtask_activate()`` returns
|
|
successfully and until the kernel thread is terminated. |