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:
taskname
: The name of the kernel thread to be startedstacksize
: The size of the custom stackpriority
: The priority of the kernel thread to be startedentry_point
: The entry point of the kernel thread to be startedargv
: An optional array of argument strings passed to the kernel thread
/* 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.