Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #1463, Implement separate allocator for task stacks #1464

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading