Skip to content

Commit

Permalink
Fix nasa#1463, Implement separate allocator for task stacks
Browse files Browse the repository at this point in the history
Removes default use of malloc() for creating a task stack in VxWorks.
Replace with a mempool-based solution, that can also be replaced with
some other memory pool based on user preferences.
  • Loading branch information
jphickey committed May 28, 2024
1 parent 372ea65 commit 6fea765
Show file tree
Hide file tree
Showing 19 changed files with 1,189 additions and 120 deletions.
5 changes: 5 additions & 0 deletions src/os/vxworks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ else()
)
endif ()

# User-selectable mempool impl for task stack blocks
list(APPEND VXWORKS_IMPL_SRCLIST
src/os-impl-taskstack-default.c
)

# Defines an OBJECT target named "osal_vxworks_impl" with selected source files
add_library(osal_vxworks_impl OBJECT
${VXWORKS_BASE_SRCLIST}
Expand Down
7 changes: 4 additions & 3 deletions src/os/vxworks/inc/os-impl-tasks.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#define OS_IMPL_TASKS_H

#include "osconfig.h"
#include "os-impl-taskstack.h"
#include <taskLib.h>

#if defined(VX_WIND_TCB_SIZE)
Expand All @@ -42,12 +43,12 @@ typedef WIND_TCB OS_VxWorks_TCB_t;
#endif /* !defined(VX_WIND_TCB_SIZE) */

/*tasks */
typedef struct
typedef struct OS_impl_task_internal_record
{
OS_VxWorks_TCB_t tcb; /* Must be first */
TASK_ID vxid;
void * heap_block; /* set non-null if the stack was obtained with malloc() */
size_t heap_block_size;

OS_impl_task_stack_mblock_t stack;
} OS_impl_task_internal_record_t;

/* Tables where the OS object information is stored */
Expand Down
72 changes: 72 additions & 0 deletions src/os/vxworks/inc/os-impl-taskstack.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/************************************************************************
* NASA Docket No. GSC-18,719-1, and identified as “core Flight System: Bootes”
*
* Copyright (c) 2020 United States Government as represented by the
* Administrator of the National Aeronautics and Space Administration.
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
************************************************************************/

/**
* \file
*
* \ingroup vxworks
*
*/

#ifndef OS_IMPL_TASKSTACK_H
#define OS_IMPL_TASKSTACK_H

#include "osconfig.h"
#include "common_types.h"

typedef struct OS_impl_task_stack_mblock
{
void * block_ptr; /* set non-null if the stack was obtained from a memory pool */
size_t block_size;
} OS_impl_task_stack_mblock_t;

typedef struct OS_impl_task_stack_addr
{
cpuaddr stackaddr;
size_t usable_size;
} OS_impl_task_stack_addr_t;

/*
* internal helper function to release a stack block
*
* This wrapper permits stack blocks to be obtained from something
* other than the system heap. This function is invoked by the Task
* subsystem when it is finished using a block.
*/
void OS_VxWorks_TaskAPI_ReleaseStackBlock(OS_impl_task_stack_mblock_t *bp);

/*
* internal helper function to acquire a stack block
*
* This wrapper permits stack blocks to be obtained from something
* other than the system heap. This function is invoked by the Task
* subsystem when needs to obtain a new block for use as a task stack.
*/
void OS_VxWorks_TaskAPI_AcquireStackBlock(OS_impl_task_stack_mblock_t *bp, size_t block_size);

/*
* internal helper function to convert a stack block to stack address
*
* VxWorks requires that the application pass in the actual CPU stack pointer (SP)
* value to the task create call. This function performs the necessary conversion
* to accomodate for this. The usable stack size may be less than the block size
* due to alignment.
*/
void OS_VxWorks_TaskAPI_StackBlockToAddr(OS_impl_task_stack_addr_t *addr, void *block_ptr, size_t block_size);

#endif /* OS_IMPL_TASKSTACK_H */
91 changes: 18 additions & 73 deletions src/os/vxworks/src/os-impl-tasks.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "os-vxworks.h"
#include "os-impl-tasks.h"
#include "os-impl-taskstack.h"

#include "os-shared-task.h"
#include "os-shared-idmap.h"
Expand Down Expand Up @@ -112,10 +113,7 @@ int32 OS_TaskCreate_Impl(const OS_object_token_t *token, uint32 flags)
{
STATUS status;
int vxflags;
int vxpri;
size_t actualsz;
unsigned long userstackbase;
unsigned long actualstackbase;
OS_impl_task_stack_addr_t stack;
OS_impl_task_internal_record_t *lrec;
OS_task_internal_record_t * task;

Expand All @@ -133,14 +131,6 @@ int32 OS_TaskCreate_Impl(const OS_object_token_t *token, uint32 flags)
vxflags |= VX_FP_TASK;
}

/*
* Get priority/stack specs from main struct
* priority should be a direct passthru
*/
vxpri = task->priority;
actualsz = task->stack_size;
userstackbase = (unsigned long)task->stack_pointer;

/*
* NOTE: Using taskInit() here rather than taskSpawn() allows us
* to specify a specific statically-allocated WIND_TCB instance.
Expand All @@ -150,90 +140,45 @@ int32 OS_TaskCreate_Impl(const OS_object_token_t *token, uint32 flags)
* in turn provides an index into OSAL local data structures. With
* this we can have the equivalent of a taskVar that works on both
* UMP and SMP deployments.
*
* The difficulty with taskInit() is that we must also manually
* allocate the stack as well (there is no API that allows
* a specific WIND_TCB but automatically allocates the stack).
* Furthermore, VxWorks uses this pointer directly as the CPU
* stack pointer register, so we need to manually adjust it for
* downward-growing stacks.
*
* NOTE: Allocation of the stack requires a malloc() of some form.
* This is what taskSpawn() effectively does internally to create
* stack. If the system malloc() is unacceptable here then this
* could be replaced with a locally scoped statically allocated buffer.
*
* ALSO NOTE: The stack-rounding macros are normally supplied from
* vxWorks.h on relevant platforms. If not provided then it is
* assumed that no specific alignment is needed on this platform.
*/

if (userstackbase == 0)
if (task->stack_pointer == NULL)
{
/* add a little extra in case the base address needs alignment too.
* this helps ensure that the final aligned stack is not less
* than what was originally requested (but might be a bit more) */
actualsz += VX_IMPL_STACK_ALIGN_SIZE;
actualsz = VX_IMPL_STACK_ROUND_UP(actualsz);

/*
* VxWorks does not provide a way to deallocate
* a taskInit-provided stack when a task exits.
*
* So in this case we will find the leftover heap
* So in this case we will find the leftover stack
* buffer when OSAL reuses this local record block.
*
* If that leftover heap buffer is big enough it
* If that leftover stack buffer is big enough it
* can be used directly. Otherwise it needs to be
* re-created.
*/
if (lrec->heap_block_size < actualsz)
if (lrec->stack.block_size < task->stack_size)
{
if (lrec->heap_block != NULL)
{
/* release the old block */
free(lrec->heap_block);
lrec->heap_block_size = 0;
}
/* release the old block, if any */
OS_VxWorks_TaskAPI_ReleaseStackBlock(&lrec->stack);

/* allocate a new heap block to use for a stack */
lrec->heap_block = malloc(actualsz);

if (lrec->heap_block != NULL)
{
lrec->heap_block_size = actualsz;
}
OS_VxWorks_TaskAPI_AcquireStackBlock(&lrec->stack, task->stack_size);
}

userstackbase = (unsigned long)lrec->heap_block;
/* convert block pointer to values suitable for kernel */
OS_VxWorks_TaskAPI_StackBlockToAddr(&stack, lrec->stack.block_ptr, lrec->stack.block_size);
}

if (userstackbase == 0)
else
{
/* no stack - cannot create task */
return OS_ERROR;
/* convert user-supplied block to values suitable for kernel */
OS_VxWorks_TaskAPI_StackBlockToAddr(&stack, task->stack_pointer, task->stack_size);
}

actualstackbase = userstackbase;

/* also round the base address */
actualstackbase = VX_IMPL_STACK_ROUND_UP(actualstackbase);
actualsz -= (actualstackbase - userstackbase);
actualsz = VX_IMPL_STACK_ROUND_DOWN(actualsz);

/*
* On most CPUs the stack grows downward, so assume that to be
* the case in the event that _STACK_DIR is not defined/known
*/
#if !defined(_STACK_DIR) || (_STACK_DIR != _STACK_GROWS_UP)
actualstackbase += actualsz; /* move to last byte of stack block */
#endif

status = taskInit((WIND_TCB *)&lrec->tcb, /* address of new task's TCB */
(char *)task->task_name, vxpri, /* priority of new task */
(char *)task->task_name, /* name of task */
task->priority, /* priority of new task */
vxflags, /* task option word */
(char *)actualstackbase, /* base of new task's stack */
actualsz, /* size (bytes) of stack needed */
(char *)stack.stackaddr, /* actual stack pointer (SP) reg value */
stack.usable_size, /* actual usable size (bytes) of SP */
(FUNCPTR)OS_VxWorks_TaskEntry, /* entry point of new task */
OS_ObjectIdToInteger(OS_ObjectIdFromToken(token)), /* 1st arg is ID */
0, 0, 0, 0, 0, 0, 0, 0, 0);
Expand Down
Loading

0 comments on commit 6fea765

Please sign in to comment.