diff --git a/src/os/vxworks/CMakeLists.txt b/src/os/vxworks/CMakeLists.txt index 5bcc7f4d3..c149a7d70 100644 --- a/src/os/vxworks/CMakeLists.txt +++ b/src/os/vxworks/CMakeLists.txt @@ -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} diff --git a/src/os/vxworks/inc/os-impl-tasks.h b/src/os/vxworks/inc/os-impl-tasks.h index aab87482b..2c49a3d32 100644 --- a/src/os/vxworks/inc/os-impl-tasks.h +++ b/src/os/vxworks/inc/os-impl-tasks.h @@ -27,6 +27,7 @@ #define OS_IMPL_TASKS_H #include "osconfig.h" +#include "os-impl-taskstack.h" #include #if defined(VX_WIND_TCB_SIZE) @@ -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 */ diff --git a/src/os/vxworks/inc/os-impl-taskstack.h b/src/os/vxworks/inc/os-impl-taskstack.h new file mode 100644 index 000000000..eecc74fda --- /dev/null +++ b/src/os/vxworks/inc/os-impl-taskstack.h @@ -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 */ diff --git a/src/os/vxworks/src/os-impl-tasks.c b/src/os/vxworks/src/os-impl-tasks.c index 9e5eef498..0869782bb 100644 --- a/src/os/vxworks/src/os-impl-tasks.c +++ b/src/os/vxworks/src/os-impl-tasks.c @@ -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" @@ -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; @@ -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. @@ -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); diff --git a/src/os/vxworks/src/os-impl-taskstack-default.c b/src/os/vxworks/src/os-impl-taskstack-default.c new file mode 100644 index 000000000..fe91e1637 --- /dev/null +++ b/src/os/vxworks/src/os-impl-taskstack-default.c @@ -0,0 +1,191 @@ +/************************************************************************ + * 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 + * \author joseph.p.hickey@nasa.gov + * + */ +/**************************************************************************************** + INCLUDE FILES +****************************************************************************************/ + +#include "os-vxworks.h" +#include "os-impl-taskstack.h" + +#include "os-shared-task.h" +#include "os-shared-idmap.h" +#include "os-shared-timebase.h" +#include "osapi-bsp.h" + +#include +#include +#include + +/**************************************************************************************** + DEFINES +****************************************************************************************/ + +/* + * macros for stack size manipulation. + * These are normally provided by vxWorks.h if relevant for the platform. + * If they are not defined, use a reasonable default/substitute. + */ +#if defined(_STACK_ALIGN_SIZE) +#define VX_IMPL_STACK_ALIGN_SIZE _STACK_ALIGN_SIZE +#else +#define VX_IMPL_STACK_ALIGN_SIZE ((size_t)16) +#endif + +#if defined(STACK_ROUND_DOWN) +#define VX_IMPL_STACK_ROUND_DOWN(x) STACK_ROUND_DOWN(x) +#else +#define VX_IMPL_STACK_ROUND_DOWN(x) ((x) & ~(VX_IMPL_STACK_ALIGN_SIZE - 1)) +#endif + +#if defined(STACK_ROUND_UP) +#define VX_IMPL_STACK_ROUND_UP(x) STACK_ROUND_UP(x) +#else +#define VX_IMPL_STACK_ROUND_UP(x) (((x) + (VX_IMPL_STACK_ALIGN_SIZE - 1)) & ~(VX_IMPL_STACK_ALIGN_SIZE - 1)) +#endif + +/* Use the VxWorks system partition by default */ +#if !defined(VX_IMPL_STACK_MEMPARTID) +extern PART_ID memSysPartId; +#define VX_IMPL_STACK_MEMPARTID memSysPartId +#endif + +/* Define a reasonable minimum stack size for sanity check */ +#if !defined(VX_IMPL_STACK_MIN) +#define VX_IMPL_STACK_MIN (VX_IMPL_STACK_ALIGN_SIZE * 16) +#endif + +/* + * 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) +{ + if (bp->block_ptr != NULL) + { + memPartFree(VX_IMPL_STACK_MEMPARTID, bp->block_ptr); + } + + bp->block_size = 0; + bp->block_ptr = NULL; +} + +/*---------------------------------------------------------------- + * + * Purpose: Implemented per internal OSAL API + * See prototype for argument/return detail + * + * internal helper function to acquire a stack block + * + *-----------------------------------------------------------------*/ +void OS_VxWorks_TaskAPI_AcquireStackBlock(OS_impl_task_stack_mblock_t *bp, size_t block_size) +{ + size_t actualsz; + void * mempool_block; + + /* + * NOTE: The stack-rounding/alignment 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. + */ + + /* 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 = block_size + VX_IMPL_STACK_ALIGN_SIZE; + actualsz = VX_IMPL_STACK_ROUND_UP(actualsz); + + /* this call should always return an aligned block */ + mempool_block = memPartAlignedAlloc(VX_IMPL_STACK_MEMPARTID, /* memory partition to allocate from */ + actualsz, /* number of bytes to allocate */ + VX_IMPL_STACK_ALIGN_SIZE /* boundary to align to */ + ); + + bp->block_ptr = mempool_block; + + if (mempool_block == NULL) + { + bp->block_size = 0; + } + else + { + bp->block_size = actualsz; + } +} + +/*---------------------------------------------------------------- + * + * Purpose: Implemented per internal OSAL API + * See prototype for argument/return detail + * + * internal helper function to acquire a stack block + * + *-----------------------------------------------------------------*/ +void OS_VxWorks_TaskAPI_StackBlockToAddr(OS_impl_task_stack_addr_t *addr, void *block_ptr, size_t block_size) +{ + cpuaddr start_addr; + cpuaddr end_addr; + size_t usable_size; + + /* got a block, now adjust for cpu-specific requirements */ + + /* convert to integer memory address */ + start_addr = (cpuaddr)block_ptr; + end_addr = start_addr + block_size - 1; + + start_addr += (VX_IMPL_STACK_ALIGN_SIZE - 1); + start_addr &= ~(VX_IMPL_STACK_ALIGN_SIZE - 1); + end_addr &= ~(VX_IMPL_STACK_ALIGN_SIZE - 1); + + if (end_addr <= start_addr) + { + /* This should not happen */ + usable_size = 0; + } + else + { + usable_size = end_addr - start_addr; + } + + /* + * export the address to the caller. This is the value that + * should be used for the actual VxWorks task stack pointer + * + * VxWorks uses the address directly as the CPU stack pointer register, + * this needs to compensate for downward-growing stacks. + * + * 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) + addr->stackaddr = end_addr; /* stack grows down: SP set to upper address bound */ +#else + addr->stackaddr = start_addr; /* stack grows up: SP set to lower address bound */ +#endif + + addr->usable_size = usable_size; +} \ No newline at end of file diff --git a/src/unit-test-coverage/ut-stubs/CMakeLists.txt b/src/unit-test-coverage/ut-stubs/CMakeLists.txt index b970cf8a2..130aed70e 100644 --- a/src/unit-test-coverage/ut-stubs/CMakeLists.txt +++ b/src/unit-test-coverage/ut-stubs/CMakeLists.txt @@ -71,6 +71,7 @@ add_library(ut_libc_stubs STATIC EXCLUDE_FROM_ALL src/vxworks-hostLib-stubs.c src/vxworks-intLib-stubs.c src/vxworks-loadLib-stubs.c + src/vxworks-memPartLib-handlers.c src/vxworks-memPartLib-stubs.c src/vxworks-moduleLib-stubs.c src/vxworks-msgQLib-stubs.c diff --git a/src/unit-test-coverage/ut-stubs/inc/OCS_memPartLib.h b/src/unit-test-coverage/ut-stubs/inc/OCS_memPartLib.h index d862e7faf..bd31a95bc 100644 --- a/src/unit-test-coverage/ut-stubs/inc/OCS_memPartLib.h +++ b/src/unit-test-coverage/ut-stubs/inc/OCS_memPartLib.h @@ -56,6 +56,32 @@ extern OCS_STATUS OCS_memPartShow(OCS_PART_ID partId, /* partition ID */ extern OCS_STATUS OCS_memPartInfoGet(OCS_PART_ID partId, /* partition ID */ OCS_MEM_PART_STATS *ppartStats /* partition stats structure */); +extern OCS_PART_ID OCS_memPartCreate(char * pPool, /* pointer to memory area */ + unsigned int poolSize /* size in bytes */ +); + +extern OCS_STATUS OCS_memPartAddToPool(OCS_PART_ID partId, /* partition to initialize */ + char * pPool, /* pointer to memory block */ + unsigned int poolSize /* block size in bytes */ +); + +extern void *OCS_memPartAlignedAlloc(OCS_PART_ID partId, /* memory partition to allocate from */ + unsigned int nBytes, /* number of bytes to allocate */ + unsigned int alignment /* boundary to align to */ +); + +extern void *OCS_memPartAlloc(OCS_PART_ID partId, /* memory partition to allocate from */ + unsigned int nBytes /* number of bytes to allocate */ +); + +extern OCS_STATUS OCS_memPartFree(OCS_PART_ID partId, /* memory partition to add block to */ + char * pBlock /* pointer to block of memory to free */ +); + +extern void OCS_memAddToPool(char * pPool, /* pointer to memory block */ + unsigned int poolSize /* block size in bytes */ +); + extern OCS_PART_ID OCS_memSysPartId; #endif /* OCS_MEMPARTLIB_H */ diff --git a/src/unit-test-coverage/ut-stubs/override_inc/memPartLib.h b/src/unit-test-coverage/ut-stubs/override_inc/memPartLib.h index 77e146e4d..e05517959 100644 --- a/src/unit-test-coverage/ut-stubs/override_inc/memPartLib.h +++ b/src/unit-test-coverage/ut-stubs/override_inc/memPartLib.h @@ -35,8 +35,15 @@ #define PART_ID OCS_PART_ID #define MEM_PART_STATS OCS_MEM_PART_STATS -#define memPartShow OCS_memPartShow -#define memPartInfoGet OCS_memPartInfoGet -#define memSysPartId OCS_memSysPartId +#define memAddToPool OCS_memAddToPool +#define memPartAddToPool OCS_memPartAddToPool +#define memPartAlignedAlloc OCS_memPartAlignedAlloc +#define memPartAlloc OCS_memPartAlloc +#define memPartCreate OCS_memPartCreate +#define memPartFree OCS_memPartFree +#define memPartInfoGet OCS_memPartInfoGet +#define memPartShow OCS_memPartShow + +#define memSysPartId OCS_memSysPartId #endif /* OVERRIDE_MEMPARTLIB_H */ diff --git a/src/unit-test-coverage/ut-stubs/src/vxworks-memPartLib-handlers.c b/src/unit-test-coverage/ut-stubs/src/vxworks-memPartLib-handlers.c new file mode 100644 index 000000000..fcf70a6d3 --- /dev/null +++ b/src/unit-test-coverage/ut-stubs/src/vxworks-memPartLib-handlers.c @@ -0,0 +1,49 @@ +/************************************************************************ + * 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 + * \author joseph.p.hickey@nasa.gov + * + * Stub implementations for the functions defined in the OSAL API + * + * The stub implementation can be used for unit testing applications built + * on top of OSAL. The stubs do not do any real function, but allow + * the return code to be crafted such that error paths in the application + * can be executed. + */ + +#include "OCS_memPartLib.h" +#include "utstubs.h" + +#include + +/* instance of the global (OK here for now, may need to move to a separate unit) */ +OCS_PART_ID OCS_memSysPartId; + +/* + * ----------------------------------------------------------------- + * Default handler implementation for 'OCS_memPartInfoGet' stub + * ----------------------------------------------------------------- + */ +void UT_DefaultHandler_OCS_memPartInfoGet(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) +{ + OCS_MEM_PART_STATS *ppartStats = UT_Hook_GetArgValueByName(Context, "ppartStats", OCS_MEM_PART_STATS *); + + memset(ppartStats, 0, sizeof(*ppartStats)); +} diff --git a/src/unit-test-coverage/ut-stubs/src/vxworks-memPartLib-stubs.c b/src/unit-test-coverage/ut-stubs/src/vxworks-memPartLib-stubs.c index 8b9e8fbfc..8b9e8e09a 100644 --- a/src/unit-test-coverage/ut-stubs/src/vxworks-memPartLib-stubs.c +++ b/src/unit-test-coverage/ut-stubs/src/vxworks-memPartLib-stubs.c @@ -16,22 +16,145 @@ * limitations under the License. ************************************************************************/ -/* OSAL coverage stub replacement for memPartLib.h */ -#include -#include -#include "utstubs.h" +/** + * @file + * + * Auto-Generated stub implementations for functions defined in OCS_memPartLib header + */ #include "OCS_memPartLib.h" +#include "utgenstub.h" -OCS_STATUS OCS_memPartShow(OCS_PART_ID partId, int type) +/* + * ---------------------------------------------------- + * Generated stub function for OCS_memAddToPool() + * ---------------------------------------------------- + */ +void OCS_memAddToPool(char *pPool, unsigned int poolSize) +{ + UT_GenStub_AddParam(OCS_memAddToPool, char *, pPool); + UT_GenStub_AddParam(OCS_memAddToPool, unsigned int, poolSize); + + UT_GenStub_Execute(OCS_memAddToPool, Basic, NULL); +} + +/* + * ---------------------------------------------------- + * Generated stub function for OCS_memPartAddToPool() + * ---------------------------------------------------- + */ +OCS_STATUS OCS_memPartAddToPool(OCS_PART_ID partId, char *pPool, unsigned int poolSize) +{ + UT_GenStub_SetupReturnBuffer(OCS_memPartAddToPool, OCS_STATUS); + + UT_GenStub_AddParam(OCS_memPartAddToPool, OCS_PART_ID, partId); + UT_GenStub_AddParam(OCS_memPartAddToPool, char *, pPool); + UT_GenStub_AddParam(OCS_memPartAddToPool, unsigned int, poolSize); + + UT_GenStub_Execute(OCS_memPartAddToPool, Basic, NULL); + + return UT_GenStub_GetReturnValue(OCS_memPartAddToPool, OCS_STATUS); +} + +/* + * ---------------------------------------------------- + * Generated stub function for OCS_memPartAlignedAlloc() + * ---------------------------------------------------- + */ +void *OCS_memPartAlignedAlloc(OCS_PART_ID partId, unsigned int nBytes, unsigned int alignment) +{ + UT_GenStub_SetupReturnBuffer(OCS_memPartAlignedAlloc, void *); + + UT_GenStub_AddParam(OCS_memPartAlignedAlloc, OCS_PART_ID, partId); + UT_GenStub_AddParam(OCS_memPartAlignedAlloc, unsigned int, nBytes); + UT_GenStub_AddParam(OCS_memPartAlignedAlloc, unsigned int, alignment); + + UT_GenStub_Execute(OCS_memPartAlignedAlloc, Basic, NULL); + + return UT_GenStub_GetReturnValue(OCS_memPartAlignedAlloc, void *); +} + +/* + * ---------------------------------------------------- + * Generated stub function for OCS_memPartAlloc() + * ---------------------------------------------------- + */ +void *OCS_memPartAlloc(OCS_PART_ID partId, unsigned int nBytes) +{ + UT_GenStub_SetupReturnBuffer(OCS_memPartAlloc, void *); + + UT_GenStub_AddParam(OCS_memPartAlloc, OCS_PART_ID, partId); + UT_GenStub_AddParam(OCS_memPartAlloc, unsigned int, nBytes); + + UT_GenStub_Execute(OCS_memPartAlloc, Basic, NULL); + + return UT_GenStub_GetReturnValue(OCS_memPartAlloc, void *); +} + +/* + * ---------------------------------------------------- + * Generated stub function for OCS_memPartCreate() + * ---------------------------------------------------- + */ +OCS_PART_ID OCS_memPartCreate(char *pPool, unsigned int poolSize) { - return UT_DEFAULT_IMPL(OCS_memPartShow); + UT_GenStub_SetupReturnBuffer(OCS_memPartCreate, OCS_PART_ID); + + UT_GenStub_AddParam(OCS_memPartCreate, char *, pPool); + UT_GenStub_AddParam(OCS_memPartCreate, unsigned int, poolSize); + + UT_GenStub_Execute(OCS_memPartCreate, Basic, NULL); + + return UT_GenStub_GetReturnValue(OCS_memPartCreate, OCS_PART_ID); } +/* + * ---------------------------------------------------- + * Generated stub function for OCS_memPartFree() + * ---------------------------------------------------- + */ +OCS_STATUS OCS_memPartFree(OCS_PART_ID partId, char *pBlock) +{ + UT_GenStub_SetupReturnBuffer(OCS_memPartFree, OCS_STATUS); + + UT_GenStub_AddParam(OCS_memPartFree, OCS_PART_ID, partId); + UT_GenStub_AddParam(OCS_memPartFree, char *, pBlock); + + UT_GenStub_Execute(OCS_memPartFree, Basic, NULL); + + return UT_GenStub_GetReturnValue(OCS_memPartFree, OCS_STATUS); +} + +/* + * ---------------------------------------------------- + * Generated stub function for OCS_memPartInfoGet() + * ---------------------------------------------------- + */ OCS_STATUS OCS_memPartInfoGet(OCS_PART_ID partId, OCS_MEM_PART_STATS *ppartStats) { - memset(ppartStats, 0, sizeof(*ppartStats)); - return UT_DEFAULT_IMPL(OCS_memPartInfoGet); + UT_GenStub_SetupReturnBuffer(OCS_memPartInfoGet, OCS_STATUS); + + UT_GenStub_AddParam(OCS_memPartInfoGet, OCS_PART_ID, partId); + UT_GenStub_AddParam(OCS_memPartInfoGet, OCS_MEM_PART_STATS *, ppartStats); + + UT_GenStub_Execute(OCS_memPartInfoGet, Basic, NULL); + + return UT_GenStub_GetReturnValue(OCS_memPartInfoGet, OCS_STATUS); } -OCS_PART_ID OCS_memSysPartId; +/* + * ---------------------------------------------------- + * Generated stub function for OCS_memPartShow() + * ---------------------------------------------------- + */ +OCS_STATUS OCS_memPartShow(OCS_PART_ID partId, int type) +{ + UT_GenStub_SetupReturnBuffer(OCS_memPartShow, OCS_STATUS); + + UT_GenStub_AddParam(OCS_memPartShow, OCS_PART_ID, partId); + UT_GenStub_AddParam(OCS_memPartShow, int, type); + + UT_GenStub_Execute(OCS_memPartShow, Basic, NULL); + + return UT_GenStub_GetReturnValue(OCS_memPartShow, OCS_STATUS); +} diff --git a/src/unit-test-coverage/vxworks/CMakeLists.txt b/src/unit-test-coverage/vxworks/CMakeLists.txt index d60402652..e56c59950 100644 --- a/src/unit-test-coverage/vxworks/CMakeLists.txt +++ b/src/unit-test-coverage/vxworks/CMakeLists.txt @@ -18,6 +18,7 @@ set(VXWORKS_MODULE_LIST sockets symtab tasks + taskstack-default timebase ) diff --git a/src/unit-test-coverage/vxworks/src/coveragetest-tasks.c b/src/unit-test-coverage/vxworks/src/coveragetest-tasks.c index 88b3baa54..6d33e0f8b 100644 --- a/src/unit-test-coverage/vxworks/src/coveragetest-tasks.c +++ b/src/unit-test-coverage/vxworks/src/coveragetest-tasks.c @@ -29,6 +29,8 @@ #include "os-shared-idmap.h" #include "os-shared-timebase.h" +#include "os-impl-taskstack.h" + #include "OCS_stdlib.h" /* @@ -63,47 +65,33 @@ void Test_OS_TaskCreate_Impl(void) * int32 OS_TaskCreate_Impl (uint32 task_id, uint32 flags) */ OS_object_token_t token = UT_TOKEN_0; + OS_impl_task_stack_mblock_t blk; char userstack[500]; - UT_SetDataBuffer(UT_KEY(OCS_malloc), TestHeap, sizeof(TestHeap), false); - UT_SetDataBuffer(UT_KEY(OCS_free), TestHeap, sizeof(TestHeap), false); - - /* create task with stack size of 250 - this should invoke malloc() to get the stack. - * The first call checks the failure path and ensures that a malloc failure gets handled */ - OS_task_table[0].stack_size = 250; - UT_SetDefaultReturnValue(UT_KEY(OCS_malloc), OS_ERROR); - OSAPI_TEST_FUNCTION_RC(OS_TaskCreate_Impl(&token, 0), OS_ERROR); - - UT_ClearDefaultReturnValue(UT_KEY(OCS_malloc)); - OSAPI_TEST_FUNCTION_RC(OS_TaskCreate_Impl(&token, OS_FP_ENABLED), OS_SUCCESS); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_malloc)) == 2, "malloc() called"); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_free)) == 0, "free() not called"); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_taskInit)) == 1, "taskInit() called"); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_taskActivate)) == 1, "taskActivate() called"); + /* nominal, default stack aquired from pool */ + OS_task_table[0].stack_pointer = NULL; + OS_task_table[0].stack_size = sizeof(userstack); + blk.block_ptr = userstack; + blk.block_size = sizeof(userstack); + UT_SetDataBuffer(UT_KEY(OS_VxWorks_TaskAPI_AcquireStackBlock), &blk, sizeof(blk), false); + OSAPI_TEST_FUNCTION_RC(OS_TaskCreate_Impl(&token, 0), OS_SUCCESS); - /* create again with smaller stack - this should re-use existing buffer */ - OS_task_table[0].stack_size = 100; - OSAPI_TEST_FUNCTION_RC(OS_TaskCreate_Impl(&token, OS_FP_ENABLED), OS_SUCCESS); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_malloc)) == 2, "malloc() not called"); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_free)) == 0, "free() not called"); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_taskInit)) == 2, "taskInit() called"); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_taskActivate)) == 2, "taskActivate() called"); + /* nominal, but skip the pool realloc */ + OS_task_table[0].stack_pointer = NULL; + OS_task_table[0].stack_size = sizeof(userstack) / 2; + OSAPI_TEST_FUNCTION_RC(OS_TaskCreate_Impl(&token, 0), OS_SUCCESS); - /* create again with larger stack - this should free existing and malloc() new buffer */ - OS_task_table[0].stack_size = 400; + /* nominal, user-supplied stack */ + OS_task_table[0].stack_pointer = userstack; + OS_task_table[0].stack_size = sizeof(userstack); OSAPI_TEST_FUNCTION_RC(OS_TaskCreate_Impl(&token, OS_FP_ENABLED), OS_SUCCESS); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_malloc)) == 3, "malloc() called"); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_free)) == 1, "free() called"); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_taskInit)) == 3, "taskInit() called"); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_taskActivate)) == 3, "taskActivate() called"); - /* create again with nonzero userstackbase */ + /* nominal, user-supplied stack */ OS_task_table[0].stack_pointer = userstack; OS_task_table[0].stack_size = sizeof(userstack); OSAPI_TEST_FUNCTION_RC(OS_TaskCreate_Impl(&token, OS_FP_ENABLED), OS_SUCCESS); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_malloc)) == 3, "malloc() not called"); - /* other failure modes */ + /* failure of taskInit() */ UT_SetDefaultReturnValue(UT_KEY(OCS_taskInit), -1); OSAPI_TEST_FUNCTION_RC(OS_TaskCreate_Impl(&token, 0), OS_ERROR); } diff --git a/src/unit-test-coverage/vxworks/src/coveragetest-taskstack-default.c b/src/unit-test-coverage/vxworks/src/coveragetest-taskstack-default.c new file mode 100644 index 000000000..7c410fed3 --- /dev/null +++ b/src/unit-test-coverage/vxworks/src/coveragetest-taskstack-default.c @@ -0,0 +1,134 @@ +/************************************************************************ + * 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 + * \author joseph.p.hickey@nasa.gov + * + */ +#include "os-vxworks-coveragetest.h" + +#include "os-impl-taskstack.h" +#include "OCS_memPartLib.h" + +void Test_OS_VxWorks_TaskAPI_ReleaseStackBlock(void) +{ + /* + * Test function for: + * void OS_VxWorks_TaskAPI_ReleaseStackBlock(OS_impl_task_stack_mblock_t *bp); + */ + + OS_impl_task_stack_mblock_t blk; + char my_block[100]; + + memset(&blk, 0, sizeof(blk)); + + /* nominal, no-op when blk.block_ptr is NULL */ + UtAssert_VOIDCALL(OS_VxWorks_TaskAPI_ReleaseStackBlock(&blk)); + UtAssert_NULL(blk.block_ptr); + UtAssert_STUB_COUNT(OCS_memPartFree, 0); + + /* nominal, should release when blk.block_ptr is non-NULL */ + blk.block_ptr = my_block; + blk.block_size = sizeof(my_block); + UtAssert_VOIDCALL(OS_VxWorks_TaskAPI_ReleaseStackBlock(&blk)); + UtAssert_NULL(blk.block_ptr); + UtAssert_ZERO(blk.block_size); + UtAssert_STUB_COUNT(OCS_memPartFree, 1); +} + +void Test_OS_VxWorks_TaskAPI_AcquireStackBlock(void) +{ + /* + * Test function for: + * void OS_VxWorks_TaskAPI_AcquireStackBlock(OS_impl_task_stack_mblock_t *bp, size_t block_size); + */ + OS_impl_task_stack_mblock_t blk; + char my_block[100]; + + memset(&blk, 0, sizeof(blk)); + + /* memPartAlignedAlloc() returns NULL by default, so this is an error case */ + UtAssert_VOIDCALL(OS_VxWorks_TaskAPI_AcquireStackBlock(&blk, sizeof(my_block))); + UtAssert_STUB_COUNT(OCS_memPartAlignedAlloc, 1); + UtAssert_NULL(blk.block_ptr); + UtAssert_ZERO(blk.block_size); + + /* nominal, memPartAlignedAlloc() returns pointer to block */ + UT_SetDefaultReturnValue(UT_KEY(OCS_memPartAlignedAlloc), (UT_IntReturn_t)my_block); + UtAssert_VOIDCALL(OS_VxWorks_TaskAPI_AcquireStackBlock(&blk, sizeof(my_block))); + UtAssert_STUB_COUNT(OCS_memPartAlignedAlloc, 2); + UtAssert_ADDRESS_EQ(blk.block_ptr, my_block); + UtAssert_GTEQ(size_t, blk.block_size, sizeof(my_block)); /* could be larger due to rounding */ +} + +void Test_OS_VxWorks_TaskAPI_StackBlockToAddr(void) +{ + /* + * Test function for: + * void OS_VxWorks_TaskAPI_StackBlockToAddr(OS_impl_task_stack_addr_t *addr, void *block_ptr, size_t block_size); + */ + + OS_impl_task_stack_addr_t addr; + char my_block[100]; + + memset(&addr, 0, sizeof(addr)); + + /* nominal */ + UtAssert_VOIDCALL(OS_VxWorks_TaskAPI_StackBlockToAddr(&addr, my_block, sizeof(my_block))); + UtAssert_GTEQ(cpuaddr, addr.stackaddr, (cpuaddr)my_block); /* this could be the start or end of block */ + UtAssert_LTEQ(size_t, addr.usable_size, sizeof(my_block)); + UtAssert_GT(size_t, addr.usable_size, 0); + + /* block too small */ + UtAssert_VOIDCALL(OS_VxWorks_TaskAPI_StackBlockToAddr(&addr, my_block, 0)); + UtAssert_ZERO(addr.usable_size); +} + +/* ------------------- End of test cases --------------------------------------*/ + +/* Osapi_Test_Setup + * + * Purpose: + * Called by the unit test tool to set up the app prior to each test + */ +void Osapi_Test_Setup(void) +{ + UT_ResetState(0); +} + +/* + * Osapi_Test_Teardown + * + * Purpose: + * Called by the unit test tool to tear down the app after each test + */ +void Osapi_Test_Teardown(void) {} + +/* UtTest_Setup + * + * Purpose: + * Registers the test cases to execute with the unit test tool + */ +void UtTest_Setup(void) +{ + ADD_TEST(OS_VxWorks_TaskAPI_ReleaseStackBlock); + ADD_TEST(OS_VxWorks_TaskAPI_AcquireStackBlock); + ADD_TEST(OS_VxWorks_TaskAPI_StackBlockToAddr); +} diff --git a/src/unit-test-coverage/vxworks/ut-stubs/CMakeLists.txt b/src/unit-test-coverage/vxworks/ut-stubs/CMakeLists.txt index 5d09cd107..b54f669b8 100644 --- a/src/unit-test-coverage/vxworks/ut-stubs/CMakeLists.txt +++ b/src/unit-test-coverage/vxworks/ut-stubs/CMakeLists.txt @@ -1,4 +1,7 @@ add_library(ut_vxworks_impl_stubs + src/os-impl-taskstack-handlers.c + src/os-impl-taskstack-stubs.c + src/vxworks-os-impl-binsem-stubs.c src/vxworks-os-impl-common-stubs.c src/vxworks-os-impl-countsem-stubs.c @@ -13,6 +16,6 @@ add_library(ut_vxworks_impl_stubs src/vxworks-os-impl-timer-stubs.c ) -target_link_libraries(ut_vxworks_impl_stubs PUBLIC +target_link_libraries(ut_vxworks_impl_stubs PUBLIC ut_osapi_stub_headers ) diff --git a/src/unit-test-coverage/vxworks/ut-stubs/src/os-impl-taskstack-handlers.c b/src/unit-test-coverage/vxworks/ut-stubs/src/os-impl-taskstack-handlers.c new file mode 100644 index 000000000..6007e6818 --- /dev/null +++ b/src/unit-test-coverage/vxworks/ut-stubs/src/os-impl-taskstack-handlers.c @@ -0,0 +1,73 @@ +/************************************************************************ + * 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 + * \author joseph.p.hickey@nasa.gov + * + * Stub implementations for the functions defined in the OSAL API + * + * The stub implementation can be used for unit testing applications built + * on top of OSAL. The stubs do not do any real function, but allow + * the return code to be crafted such that error paths in the application + * can be executed. + */ + +#include "os-impl-taskstack.h" +#include "utstubs.h" + +#include + +/* + * ----------------------------------------------------------------- + * Default handler implementation for 'OS_VxWorks_TaskAPI_AcquireStackBlock' stub + * ----------------------------------------------------------------- + */ +void UT_DefaultHandler_OS_VxWorks_TaskAPI_AcquireStackBlock(void *UserObj, UT_EntryKey_t FuncKey, + const UT_StubContext_t *Context) +{ + OS_impl_task_stack_mblock_t *bp = UT_Hook_GetArgValueByName(Context, "bp", OS_impl_task_stack_mblock_t *); + int32 status; + + UT_Stub_GetInt32StatusCode(Context, &status); + + if (status == 0 && UT_Stub_CopyToLocal(UT_KEY(OS_VxWorks_TaskAPI_AcquireStackBlock), bp, sizeof(*bp)) < sizeof(*bp)) + { + memset(bp, 0, sizeof(*bp)); + } +} + +/* + * ----------------------------------------------------------------- + * Default handler implementation for 'OS_VxWorks_TaskAPI_StackBlockToAddr' stub + * ----------------------------------------------------------------- + */ +void UT_DefaultHandler_OS_VxWorks_TaskAPI_StackBlockToAddr(void *UserObj, UT_EntryKey_t FuncKey, + const UT_StubContext_t *Context) +{ + OS_impl_task_stack_addr_t *addr = UT_Hook_GetArgValueByName(Context, "addr", OS_impl_task_stack_addr_t *); + int32 status; + + UT_Stub_GetInt32StatusCode(Context, &status); + + if (status == 0 && + UT_Stub_CopyToLocal(UT_KEY(OS_VxWorks_TaskAPI_AcquireStackBlock), addr, sizeof(*addr)) < sizeof(*addr)) + { + memset(addr, 0, sizeof(*addr)); + } +} diff --git a/src/unit-test-coverage/vxworks/ut-stubs/src/os-impl-taskstack-stubs.c b/src/unit-test-coverage/vxworks/ut-stubs/src/os-impl-taskstack-stubs.c new file mode 100644 index 000000000..f1d3af920 --- /dev/null +++ b/src/unit-test-coverage/vxworks/ut-stubs/src/os-impl-taskstack-stubs.c @@ -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 + * + * Auto-Generated stub implementations for functions defined in os-impl-taskstack header + */ + +#include "os-impl-taskstack.h" +#include "utgenstub.h" + +void UT_DefaultHandler_OS_VxWorks_TaskAPI_AcquireStackBlock(void *, UT_EntryKey_t, const UT_StubContext_t *); +void UT_DefaultHandler_OS_VxWorks_TaskAPI_StackBlockToAddr(void *, UT_EntryKey_t, const UT_StubContext_t *); + +/* + * ---------------------------------------------------- + * Generated stub function for OS_VxWorks_TaskAPI_AcquireStackBlock() + * ---------------------------------------------------- + */ +void OS_VxWorks_TaskAPI_AcquireStackBlock(OS_impl_task_stack_mblock_t *bp, size_t block_size) +{ + UT_GenStub_SetupReturnBuffer(OS_VxWorks_TaskAPI_AcquireStackBlock, void *); + + UT_GenStub_AddParam(OS_VxWorks_TaskAPI_AcquireStackBlock, OS_impl_task_stack_mblock_t *, bp); + UT_GenStub_AddParam(OS_VxWorks_TaskAPI_AcquireStackBlock, size_t, block_size); + + UT_GenStub_Execute(OS_VxWorks_TaskAPI_AcquireStackBlock, Basic, + UT_DefaultHandler_OS_VxWorks_TaskAPI_AcquireStackBlock); +} + +/* + * ---------------------------------------------------- + * Generated stub function for OS_VxWorks_TaskAPI_ReleaseStackBlock() + * ---------------------------------------------------- + */ +void OS_VxWorks_TaskAPI_ReleaseStackBlock(OS_impl_task_stack_mblock_t *bp) +{ + UT_GenStub_AddParam(OS_VxWorks_TaskAPI_ReleaseStackBlock, OS_impl_task_stack_mblock_t *, bp); + + UT_GenStub_Execute(OS_VxWorks_TaskAPI_ReleaseStackBlock, Basic, NULL); +} + +/* + * ---------------------------------------------------- + * Generated stub function for OS_VxWorks_TaskAPI_StackBlockToAddr() + * ---------------------------------------------------- + */ +void OS_VxWorks_TaskAPI_StackBlockToAddr(OS_impl_task_stack_addr_t *addr, void *block_ptr, size_t block_size) +{ + UT_GenStub_AddParam(OS_VxWorks_TaskAPI_StackBlockToAddr, OS_impl_task_stack_addr_t *, addr); + UT_GenStub_AddParam(OS_VxWorks_TaskAPI_StackBlockToAddr, void *, block_ptr); + UT_GenStub_AddParam(OS_VxWorks_TaskAPI_StackBlockToAddr, size_t, block_size); + + UT_GenStub_Execute(OS_VxWorks_TaskAPI_StackBlockToAddr, Basic, + UT_DefaultHandler_OS_VxWorks_TaskAPI_StackBlockToAddr); +}