diff --git a/README.md b/README.md index 7ee49534b..4080f2f64 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,15 @@ The autogenerated OSAL user's guide can be viewed at and ### Development Build: v5.1.0-rc1+dev378 diff --git a/src/os/inc/osapi-common.h b/src/os/inc/osapi-common.h index 58e76d38b..d910a2aa6 100644 --- a/src/os/inc/osapi-common.h +++ b/src/os/inc/osapi-common.h @@ -140,6 +140,33 @@ void OS_Application_Run(void); */ int32 OS_API_Init(void); +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Teardown/de-initialization of OSAL API + * + * This is the inverse of OS_API_Init(). It will release all OS resources and + * return the system to a state similar to what it was prior to invoking + * OS_API_Init() initially. + * + * Normally for embedded applications, the OSAL is initialized after boot and will remain + * initialized in memory until the processor is rebooted. However for testing and + * developement purposes, it is potentially useful to reset back to initial conditions. + * + * For testing purposes, this API is designed/intended to be compatible with the + * UtTest_AddTeardown() routine provided by the UT-Assert subsystem. + * + * @note This is a "best-effort" routine and it may not always be possible/guaranteed + * to recover all resources, particularly in the case of off-nominal conditions, or if + * a resource is used outside of OSAL. + * + * For example, while this will attempt to unload all dynamically-loaded modules, doing + * so may not be possible and/or may induce undefined behavior if resources are in use by + * tasks/functions outside of OSAL. + * + * @return None + */ +void OS_API_Teardown(void); + /*-------------------------------------------------------------------------------------*/ /** * @brief Background thread implementation - waits forever for events to occur. diff --git a/src/os/inc/osapi-version.h b/src/os/inc/osapi-version.h index f7e0b5986..e919eccd6 100644 --- a/src/os/inc/osapi-version.h +++ b/src/os/inc/osapi-version.h @@ -34,7 +34,7 @@ /* * Development Build Macro Definitions */ -#define OS_BUILD_NUMBER 378 +#define OS_BUILD_NUMBER 387 #define OS_BUILD_BASELINE "v5.1.0-rc1" /* diff --git a/src/os/posix/src/os-impl-console.c b/src/os/posix/src/os-impl-console.c index 672770fc7..44da26742 100644 --- a/src/os/posix/src/os-impl-console.c +++ b/src/os/posix/src/os-impl-console.c @@ -100,7 +100,7 @@ static void *OS_ConsoleTask_Entry(void *arg) local = OS_OBJECT_TABLE_GET(OS_impl_console_table, token); /* Loop forever (unless shutdown is set) */ - while (OS_SharedGlobalVars.ShutdownFlag != OS_SHUTDOWN_MAGIC_NUMBER) + while (OS_SharedGlobalVars.GlobalState != OS_SHUTDOWN_MAGIC_NUMBER) { OS_ConsoleOutput_Impl(&token); sem_wait(&local->data_sem); diff --git a/src/os/rtems/src/os-impl-console.c b/src/os/rtems/src/os-impl-console.c index 7aa2622e3..08cac6524 100644 --- a/src/os/rtems/src/os-impl-console.c +++ b/src/os/rtems/src/os-impl-console.c @@ -123,7 +123,7 @@ static void OS_ConsoleTask_Entry(rtems_task_argument arg) local = OS_OBJECT_TABLE_GET(OS_impl_console_table, token); /* Loop forever (unless shutdown is set) */ - while (OS_SharedGlobalVars.ShutdownFlag != OS_SHUTDOWN_MAGIC_NUMBER) + while (OS_SharedGlobalVars.GlobalState != OS_SHUTDOWN_MAGIC_NUMBER) { OS_ConsoleOutput_Impl(&token); rtems_semaphore_obtain(local->data_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT); diff --git a/src/os/shared/inc/os-shared-common.h b/src/os/shared/inc/os-shared-common.h index d5bc78e4a..c6cb302fc 100644 --- a/src/os/shared/inc/os-shared-common.h +++ b/src/os/shared/inc/os-shared-common.h @@ -32,15 +32,23 @@ #include "os-shared-globaldefs.h" /* - * A "magic number" that when written to the "ShutdownFlag" member - * of the global state structure indicates an active shutdown request. + * Flag values for the "GlobalState" member the global state structure */ -#define OS_SHUTDOWN_MAGIC_NUMBER 0xABADC0DE +#define OS_INIT_MAGIC_NUMBER 0xBE57C0DE /**< Indicates that OS_API_Init() has been successfully run */ +#define OS_SHUTDOWN_MAGIC_NUMBER 0xABADC0DE /**< Indicates that a system shutdown request is pending */ /* Global variables that are common between implementations */ struct OS_shared_global_vars { - bool Initialized; + /* + * Tracks whether OS_API_Init() has been called or if + * there is a shutdown request pending. + * + * After boot/first startup this should have 0 (from BSS clearing) + * After OS_API_Init() is called this has OS_INIT_MAGIC_NUMBER + * After OS_ApplicationShutdown() this has OS_SHUTDOWN_MAGIC_NUMBER + */ + volatile uint32 GlobalState; /* * The console device ID used for OS_printf() calls @@ -48,13 +56,12 @@ struct OS_shared_global_vars osal_id_t PrintfConsoleId; /* - * PrintfEnabled and ShutdownFlag are marked "volatile" + * PrintfEnabled and GlobalState are marked "volatile" * because they are updated and read by different threads */ - volatile bool PrintfEnabled; - volatile uint32 ShutdownFlag; - uint32 MicroSecPerTick; - uint32 TicksPerSecond; + volatile bool PrintfEnabled; + uint32 MicroSecPerTick; + uint32 TicksPerSecond; /* * The event handler is an application-defined callback diff --git a/src/os/shared/src/osapi-common.c b/src/os/shared/src/osapi-common.c index 2543d9887..d466f4d03 100644 --- a/src/os/shared/src/osapi-common.c +++ b/src/os/shared/src/osapi-common.c @@ -58,9 +58,8 @@ #include "os-shared-time.h" OS_SharedGlobalVars_t OS_SharedGlobalVars = { - .Initialized = false, + .GlobalState = 0, .PrintfEnabled = false, - .ShutdownFlag = 0, .MicroSecPerTick = 0, /* invalid, _must_ be set by implementation init */ .TicksPerSecond = 0, /* invalid, _must_ be set by implementation init */ .EventHandler = NULL, @@ -112,13 +111,29 @@ int32 OS_API_Init(void) osal_objtype_t idtype; uint32 microSecPerSec; - if (OS_SharedGlobalVars.Initialized != false) + /* + * If OSAL is already initialized, not really a big issue, just return. + * This is not typically expected though, so its worth a debug statement. + * + * However this can validly occur when running tests on some platforms + * without a reset/reload between invocations. + */ + if (OS_SharedGlobalVars.GlobalState == OS_INIT_MAGIC_NUMBER) { - OS_DEBUG("WARNING: BUG - initialization function called multiple times\n"); - return OS_ERROR; + OS_DEBUG("NOTE: ignored redundant OS_API_Init() call\n"); + return OS_SUCCESS; } - OS_SharedGlobalVars.Initialized = true; + /* Wipe global state structure to be sure everything is clean */ + memset(&OS_SharedGlobalVars, 0, sizeof(OS_SharedGlobalVars)); + + /* Reset debug to default level if enabled */ +#if defined(OSAL_CONFIG_DEBUG_PRINTF) + OS_SharedGlobalVars.DebugLevel = 1; +#endif + + /* Set flag that says OSAL has been initialized */ + OS_SharedGlobalVars.GlobalState = OS_INIT_MAGIC_NUMBER; /* Initialize the common table that everything shares */ return_code = OS_ObjectIdInit(); @@ -216,9 +231,43 @@ int32 OS_API_Init(void) (long)OS_SharedGlobalVars.TicksPerSecond); } + if (return_code != OS_SUCCESS) + { + /* + * Some part of init failed, so set global flag that says OSAL is in shutdown state. + * + * In particular if certain internal resources (such as the console utility task) + * were created, this should cause those tasks to self-exit such that the system + * is ultimately returned to the same state it started in. + */ + OS_SharedGlobalVars.GlobalState = OS_SHUTDOWN_MAGIC_NUMBER; + } + return (return_code); } /* end OS_API_Init */ +/*---------------------------------------------------------------- + * + * Function: OS_API_Teardown + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +void OS_API_Teardown(void) +{ + /* + * This should delete any remaining user-created objects/tasks + */ + OS_DeleteAllObjects(); + + /* + * This should cause the "internal" objects (e.g. console utility task) + * to exit, and will prevent any new objects from being created. + */ + OS_ApplicationShutdown(true); +} + /*---------------------------------------------------------------- * * Function: OS_RegisterEventHandler @@ -359,7 +408,7 @@ void OS_IdleLoop() * In most "real" embedded systems, this will never happen. * However it will happen in debugging situations (CTRL+C, etc). */ - while (OS_SharedGlobalVars.ShutdownFlag != OS_SHUTDOWN_MAGIC_NUMBER) + while (OS_SharedGlobalVars.GlobalState != OS_SHUTDOWN_MAGIC_NUMBER) { OS_IdleLoop_Impl(); } @@ -377,7 +426,7 @@ void OS_ApplicationShutdown(uint8 flag) { if (flag == true) { - OS_SharedGlobalVars.ShutdownFlag = OS_SHUTDOWN_MAGIC_NUMBER; + OS_SharedGlobalVars.GlobalState = OS_SHUTDOWN_MAGIC_NUMBER; } /* diff --git a/src/os/shared/src/osapi-idmap.c b/src/os/shared/src/osapi-idmap.c index 758f74307..ab3a71883 100644 --- a/src/os/shared/src/osapi-idmap.c +++ b/src/os/shared/src/osapi-idmap.c @@ -324,7 +324,11 @@ int32 OS_ObjectIdTransactionInit(OS_lock_mode_t lock_mode, osal_objtype_t idtype { memset(token, 0, sizeof(*token)); - if (OS_SharedGlobalVars.Initialized == false) + /* + * Confirm that OSAL has been fully initialized before allowing any transactions + */ + if (OS_SharedGlobalVars.GlobalState != OS_INIT_MAGIC_NUMBER && + OS_SharedGlobalVars.GlobalState != OS_SHUTDOWN_MAGIC_NUMBER) { return OS_ERROR; } @@ -333,7 +337,7 @@ int32 OS_ObjectIdTransactionInit(OS_lock_mode_t lock_mode, osal_objtype_t idtype * only "exclusive" locks allowed after shutdown request (this is mode used for delete). * All regular ops will be blocked. */ - if (OS_SharedGlobalVars.ShutdownFlag == OS_SHUTDOWN_MAGIC_NUMBER && lock_mode != OS_LOCK_MODE_EXCLUSIVE) + if (OS_SharedGlobalVars.GlobalState == OS_SHUTDOWN_MAGIC_NUMBER && lock_mode != OS_LOCK_MODE_EXCLUSIVE) { return OS_ERR_INCORRECT_OBJ_STATE; } @@ -1211,7 +1215,10 @@ int32 OS_ObjectIdAllocateNew(osal_objtype_t idtype, const char *name, OS_object_ { int32 return_code; - if (OS_SharedGlobalVars.ShutdownFlag == OS_SHUTDOWN_MAGIC_NUMBER) + /* + * No new objects can be created after Shutdown request + */ + if (OS_SharedGlobalVars.GlobalState == OS_SHUTDOWN_MAGIC_NUMBER) { return OS_ERR_INCORRECT_OBJ_STATE; } diff --git a/src/os/shared/src/osapi-printf.c b/src/os/shared/src/osapi-printf.c index a21f55b36..c2aede39d 100644 --- a/src/os/shared/src/osapi-printf.c +++ b/src/os/shared/src/osapi-printf.c @@ -258,7 +258,7 @@ void OS_printf(const char *String, ...) BUGCHECK((String) != NULL, ) - if (!OS_SharedGlobalVars.Initialized) + if (OS_SharedGlobalVars.GlobalState != OS_INIT_MAGIC_NUMBER) { /* * Catch some historical mis-use of the OS_printf() call. @@ -277,7 +277,7 @@ void OS_printf(const char *String, ...) * If debugging is not enabled, then this message will be silently * discarded. */ - OS_DEBUG("BUG: OS_printf() called before init: %s", String); + OS_DEBUG("BUG: OS_printf() called when OSAL not initialized: %s", String); } else if (OS_SharedGlobalVars.PrintfEnabled) { diff --git a/src/os/vxworks/src/os-impl-console.c b/src/os/vxworks/src/os-impl-console.c index 9fc250814..a6b816492 100644 --- a/src/os/vxworks/src/os-impl-console.c +++ b/src/os/vxworks/src/os-impl-console.c @@ -107,7 +107,7 @@ int OS_VxWorks_ConsoleTask_Entry(int arg) local = OS_OBJECT_TABLE_GET(OS_impl_console_table, token); /* Loop forever (unless shutdown is set) */ - while (OS_SharedGlobalVars.ShutdownFlag != OS_SHUTDOWN_MAGIC_NUMBER) + while (OS_SharedGlobalVars.GlobalState != OS_SHUTDOWN_MAGIC_NUMBER) { OS_ConsoleOutput_Impl(&token); if (semTake(local->datasem, WAIT_FOREVER) == ERROR) diff --git a/src/tests/bin-sem-flush-test/bin-sem-flush-test.c b/src/tests/bin-sem-flush-test/bin-sem-flush-test.c index 33297a34c..9916c8f42 100644 --- a/src/tests/bin-sem-flush-test/bin-sem-flush-test.c +++ b/src/tests/bin-sem-flush-test/bin-sem-flush-test.c @@ -177,6 +177,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/bin-sem-test/bin-sem-test.c b/src/tests/bin-sem-test/bin-sem-test.c index 36fa6cc4f..847616ff0 100644 --- a/src/tests/bin-sem-test/bin-sem-test.c +++ b/src/tests/bin-sem-test/bin-sem-test.c @@ -186,6 +186,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/bin-sem-timeout-test/bin-sem-timeout-test.c b/src/tests/bin-sem-timeout-test/bin-sem-timeout-test.c index 78c72022e..cb926a1a2 100644 --- a/src/tests/bin-sem-timeout-test/bin-sem-timeout-test.c +++ b/src/tests/bin-sem-timeout-test/bin-sem-timeout-test.c @@ -181,6 +181,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/count-sem-test/count-sem-test.c b/src/tests/count-sem-test/count-sem-test.c index 48efe2c8b..4001392b8 100644 --- a/src/tests/count-sem-test/count-sem-test.c +++ b/src/tests/count-sem-test/count-sem-test.c @@ -151,6 +151,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/file-api-test/file-api-test.c b/src/tests/file-api-test/file-api-test.c index a0ced207f..5b548ee52 100644 --- a/src/tests/file-api-test/file-api-test.c +++ b/src/tests/file-api-test/file-api-test.c @@ -57,6 +57,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * This test case requires a fixed virtual dir for one test case. * Just map /test to a dir of the same name, relative to current dir. diff --git a/src/tests/file-sys-add-fixed-map-api-test/file-sys-add-fixed-map-api-test.c b/src/tests/file-sys-add-fixed-map-api-test/file-sys-add-fixed-map-api-test.c index e3fd8567d..710da0d29 100644 --- a/src/tests/file-sys-add-fixed-map-api-test/file-sys-add-fixed-map-api-test.c +++ b/src/tests/file-sys-add-fixed-map-api-test/file-sys-add-fixed-map-api-test.c @@ -96,6 +96,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/idmap-api-test/idmap-api-test.c b/src/tests/idmap-api-test/idmap-api-test.c index 3a9ab8327..d8cd1ca72 100644 --- a/src/tests/idmap-api-test/idmap-api-test.c +++ b/src/tests/idmap-api-test/idmap-api-test.c @@ -348,6 +348,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/mutex-test/mutex-test.c b/src/tests/mutex-test/mutex-test.c index d47de5741..a34330e85 100644 --- a/src/tests/mutex-test/mutex-test.c +++ b/src/tests/mutex-test/mutex-test.c @@ -217,6 +217,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/network-api-test/network-api-test.c b/src/tests/network-api-test/network-api-test.c index 6e53a42ad..d2689bdff 100644 --- a/src/tests/network-api-test/network-api-test.c +++ b/src/tests/network-api-test/network-api-test.c @@ -658,6 +658,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/osal-core-test/osal-core-test.c b/src/tests/osal-core-test/osal-core-test.c index a70aa4aec..f4d728619 100644 --- a/src/tests/osal-core-test/osal-core-test.c +++ b/src/tests/osal-core-test/osal-core-test.c @@ -96,6 +96,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + UtTest_Add(TestTasks, NULL, NULL, "TASK"); UtTest_Add(TestQueues, NULL, NULL, "MSGQ"); UtTest_Add(TestBinaries, NULL, NULL, "BSEM"); diff --git a/src/tests/queue-test/queue-test.c b/src/tests/queue-test/queue-test.c index 9d36294b1..a7f1526c4 100644 --- a/src/tests/queue-test/queue-test.c +++ b/src/tests/queue-test/queue-test.c @@ -247,6 +247,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/select-test/select-test.c b/src/tests/select-test/select-test.c index 84b213964..6479e4c41 100644 --- a/src/tests/select-test/select-test.c +++ b/src/tests/select-test/select-test.c @@ -596,6 +596,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/sem-speed-test/sem-speed-test.c b/src/tests/sem-speed-test/sem-speed-test.c index 3c2a61379..fdda695b6 100644 --- a/src/tests/sem-speed-test/sem-speed-test.c +++ b/src/tests/sem-speed-test/sem-speed-test.c @@ -150,6 +150,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/shell-test/shell-test.c b/src/tests/shell-test/shell-test.c index f05ff0f9f..9546b0eb9 100644 --- a/src/tests/shell-test/shell-test.c +++ b/src/tests/shell-test/shell-test.c @@ -30,15 +30,36 @@ #define OS_TEST_SHELL_FILENAME "/drive0/shell_test.txt" +const char OS_TEST_SHELL_COMMAND[] = "echo"; +const char OS_TEST_SHELL_STRING[] = "ValueToEchoInTheFile"; + +/* + * Extra chars to allow for quoting and whitespace. + * + * There needs to be spaces between arguments, and depending + * on the shell config and its behavior it may echo extra whitespace + * and/or other chars, and a newline itself may be multiple chars (CR+LF). + * + * This allows up to this many extra chars surrounding the test string. + */ +#define OS_TEST_SHELL_MAX_EXTRA_CHARS 8 + +/* + * Sizes for the echo buffer and command buffer + * (both include some extra chars) + */ +#define OS_TEST_SHELL_ECHO_BUFFER_SIZE (sizeof(OS_TEST_SHELL_STRING) + OS_TEST_SHELL_MAX_EXTRA_CHARS) +#define OS_TEST_SHELL_CMD_BUFFER_SIZE (sizeof(OS_TEST_SHELL_COMMAND) + OS_TEST_SHELL_ECHO_BUFFER_SIZE) + /* *************************************** MAIN ************************************** */ void TestOutputToFile(void) { - char cmd[33]; + char cmd[OS_TEST_SHELL_CMD_BUFFER_SIZE + 1]; /* +1 char for term byte */ char filename[OS_MAX_PATH_LEN]; - char buffer[21]; - char copyofbuffer[21]; + char buffer[OS_TEST_SHELL_ECHO_BUFFER_SIZE + 1]; /* +1 char for term byte */ size_t size; + int32 filepos; int32 status; osal_id_t fd; @@ -48,17 +69,12 @@ void TestOutputToFile(void) strncpy(filename, "/drive0/Filename1", sizeof(filename) - 1); filename[sizeof(filename) - 1] = 0; - strcpy(buffer, "ValueToEchoInTheFile"); - strcpy(copyofbuffer, buffer); /* hold a copy of the buffer */ - /* Open In R/W mode */ status = OS_OpenCreate(&fd, OS_TEST_SHELL_FILENAME, OS_FILE_FLAG_CREATE, OS_READ_WRITE); UtAssert_True(status >= OS_SUCCESS, "status after creat = %d", (int)status); - /* Write the string */ - size = strlen(buffer); - - snprintf(cmd, sizeof(cmd), "echo -n \"%s\"", buffer); + /* assemble command */ + snprintf(cmd, sizeof(cmd), "%s \"%s\"", OS_TEST_SHELL_COMMAND, OS_TEST_SHELL_STRING); status = OS_ShellOutputToFile(cmd, fd); if (status == OS_ERR_NOT_IMPLEMENTED) @@ -69,19 +85,43 @@ void TestOutputToFile(void) { UtAssert_True(status >= OS_SUCCESS, "status after shell output to file = %d", (int)status); - strcpy(buffer, ""); - - /* lseek back to the beginning of the file */ - status = OS_lseek(fd, 0, 0); - UtAssert_True(status >= OS_SUCCESS, "status after lseek = %d", (int)status); - - /*Read what we wrote to the file */ - status = OS_read(fd, (void *)buffer, size); - UtAssert_True(status == size, "status after read = %d size = %lu", (int)status, (unsigned long)size); - if (status >= OS_SUCCESS) + /* output content should be at least this size */ + size = sizeof(OS_TEST_SHELL_STRING) - 1; + + /* Use lseek to determine size of the file */ + filepos = OS_lseek(fd, 0, OS_SEEK_END); + UtAssert_True(filepos >= size, "size of output file=%d, echoed string len=%lu", (int)filepos, + (unsigned long)size); + + /* + * Different shells vary in how the echoed output actually appears in the file. + * + * Depending on config it may echo the command itself in addition to the output, + * and there may be whitespace/newlines that should be ignored. + * + * Either way the content should appear toward the _end_ of the file. + */ + if (filepos < OS_TEST_SHELL_ECHO_BUFFER_SIZE) + { + filepos = 0; + } + else { - UtAssert_True(strcmp(buffer, copyofbuffer) == 0, "Read: %s, Written: %s", buffer, copyofbuffer); + filepos -= OS_TEST_SHELL_ECHO_BUFFER_SIZE; } + + status = OS_lseek(fd, filepos, OS_SEEK_SET); + UtAssert_True(status == filepos, "lseek to position %d, result=%d", (int)filepos, (int)status); + + /* Read what we wrote to the file */ + /* By memset() first and reading one byte less than the buffer, the result is ensured to be terminated */ + memset(buffer, 0, sizeof(buffer)); + status = OS_read(fd, buffer, sizeof(buffer) - 1); + UtAssert_True(status >= size, "status after read = %d, min valid size = %lu", (int)status, (unsigned long)size); + + /* The test should pass if the expected string is anywhere in the buffer */ + UtAssert_True(strstr(buffer, OS_TEST_SHELL_STRING) != NULL, "Read: \'%s\', Expected: \'%s\'", buffer, + OS_TEST_SHELL_STRING); } /* close the file */ @@ -101,6 +141,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/symbol-api-test/symbol-api-test.c b/src/tests/symbol-api-test/symbol-api-test.c index 60f5a767c..bfe43ea0d 100644 --- a/src/tests/symbol-api-test/symbol-api-test.c +++ b/src/tests/symbol-api-test/symbol-api-test.c @@ -112,6 +112,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/time-base-api-test/time-base-api-test.c b/src/tests/time-base-api-test/time-base-api-test.c index 94bc69a9b..775b5229a 100644 --- a/src/tests/time-base-api-test/time-base-api-test.c +++ b/src/tests/time-base-api-test/time-base-api-test.c @@ -264,6 +264,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/timer-add-api-test/timer-add-api-test.c b/src/tests/timer-add-api-test/timer-add-api-test.c index 5ff9541b4..917db9e8d 100644 --- a/src/tests/timer-add-api-test/timer-add-api-test.c +++ b/src/tests/timer-add-api-test/timer-add-api-test.c @@ -199,6 +199,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the test setup and check routines in UT assert */ diff --git a/src/tests/timer-test/timer-test.c b/src/tests/timer-test/timer-test.c index 79ba39d5b..2863dafbd 100644 --- a/src/tests/timer-test/timer-test.c +++ b/src/tests/timer-test/timer-test.c @@ -74,6 +74,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * Register the timer test setup and check routines in UT assert */ diff --git a/src/unit-test-coverage/shared/src/coveragetest-common.c b/src/unit-test-coverage/shared/src/coveragetest-common.c index 479105e2d..e2f35695f 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-common.c +++ b/src/unit-test-coverage/shared/src/coveragetest-common.c @@ -95,39 +95,54 @@ void Test_OS_API_Init(void) /* Execute Test */ Test_MicroSecPerTick = 0; Test_TicksPerSecond = 0; - OS_SharedGlobalVars.Initialized = false; + OS_SharedGlobalVars.GlobalState = 0; OSAPI_TEST_FUNCTION_RC(OS_API_Init(), OS_ERROR); + UtAssert_UINT32_EQ(OS_SharedGlobalVars.GlobalState, OS_SHUTDOWN_MAGIC_NUMBER); Test_MicroSecPerTick = 1000; Test_TicksPerSecond = 1000; - OS_SharedGlobalVars.Initialized = false; + OS_SharedGlobalVars.GlobalState = 0; OSAPI_TEST_FUNCTION_RC(OS_API_Init(), OS_SUCCESS); Test_MicroSecPerTick = 1000; Test_TicksPerSecond = 1001; - OS_SharedGlobalVars.Initialized = false; + OS_SharedGlobalVars.GlobalState = 0; OSAPI_TEST_FUNCTION_RC(OS_API_Init(), OS_SUCCESS); + UtAssert_UINT32_EQ(OS_SharedGlobalVars.GlobalState, OS_INIT_MAGIC_NUMBER); - /* Second call should return ERROR */ - OSAPI_TEST_FUNCTION_RC(OS_API_Init(), OS_ERROR); + /* Second call should return SUCCESS (but is a no-op) */ + OSAPI_TEST_FUNCTION_RC(OS_API_Init(), OS_SUCCESS); + UtAssert_UINT32_EQ(OS_SharedGlobalVars.GlobalState, OS_INIT_MAGIC_NUMBER); /* other error paths */ - OS_SharedGlobalVars.Initialized = false; + OS_SharedGlobalVars.GlobalState = 0; UT_SetDefaultReturnValue(UT_KEY(OS_ObjectIdInit), -222); OSAPI_TEST_FUNCTION_RC(OS_API_Init(), -222); UT_ResetState(UT_KEY(OS_ObjectIdInit)); - OS_SharedGlobalVars.Initialized = false; + OS_SharedGlobalVars.GlobalState = 0; UT_SetDefaultReturnValue(UT_KEY(OS_API_Impl_Init), -333); OSAPI_TEST_FUNCTION_RC(OS_API_Init(), -333); UT_ResetState(UT_KEY(OS_API_Impl_Init)); - OS_SharedGlobalVars.Initialized = false; + OS_SharedGlobalVars.GlobalState = 0; UT_SetDefaultReturnValue(UT_KEY(OS_TaskAPI_Init), -444); OSAPI_TEST_FUNCTION_RC(OS_API_Init(), -444); UT_ResetState(UT_KEY(OS_TaskAPI_Init)); } +void Test_OS_API_Teardown(void) +{ + /* + * Test Case For: + * void OS_API_Teardown(void); + */ + + /* Just need to call the API for coverage; there are no conditionals + * and the internal functions are each tested separately */ + OS_API_Teardown(); +} + void Test_OS_ApplicationExit(void) { /* @@ -255,6 +270,8 @@ void Test_OS_IdleLoopAndShutdown(void) */ uint32 CallCount = 0; + OS_SharedGlobalVars.GlobalState = OS_INIT_MAGIC_NUMBER; + UT_SetHookFunction(UT_KEY(OS_IdleLoop_Impl), SetShutdownFlagHook, NULL); OS_IdleLoop(); @@ -325,4 +342,5 @@ void UtTest_Setup(void) ADD_TEST(OS_IdleLoopAndShutdown); ADD_TEST(OS_ApplicationExit); ADD_TEST(OS_NotifyEvent); + ADD_TEST(OS_API_Teardown); } diff --git a/src/unit-test-coverage/shared/src/coveragetest-idmap.c b/src/unit-test-coverage/shared/src/coveragetest-idmap.c index 83590c08b..70b6e7329 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-idmap.c +++ b/src/unit-test-coverage/shared/src/coveragetest-idmap.c @@ -482,13 +482,13 @@ void Test_OS_ObjectIdGetById(void) OS_object_token_t token2; /* verify that the call returns ERROR when not initialized */ - OS_SharedGlobalVars.Initialized = false; + OS_SharedGlobalVars.GlobalState = 0; actual = OS_ObjectIdGetById(OS_LOCK_MODE_NONE, 0, OS_OBJECT_ID_UNDEFINED, &token1); expected = OS_ERROR; UtAssert_True(actual == expected, "OS_ObjectIdGetById(uninitialized) (%ld) == OS_ERROR", (long)actual); /* set "true" for the remainder of tests */ - OS_SharedGlobalVars.Initialized = true; + OS_SharedGlobalVars.GlobalState = OS_INIT_MAGIC_NUMBER; OS_ObjectIdCompose_Impl(OS_OBJECT_TYPE_OS_TASK, 1000, &refobjid); OS_ObjectIdToArrayIndex(OS_OBJECT_TYPE_OS_TASK, refobjid, &local_idx); @@ -516,17 +516,16 @@ void Test_OS_ObjectIdGetById(void) UtAssert_True(rptr->refcount == 0, "refcount (%u) == 0", (unsigned int)rptr->refcount); /* attempt to get non-exclusive lock during shutdown should fail */ - OS_SharedGlobalVars.ShutdownFlag = OS_SHUTDOWN_MAGIC_NUMBER; - expected = OS_ERR_INCORRECT_OBJ_STATE; - actual = OS_ObjectIdGetById(OS_LOCK_MODE_NONE, OS_OBJECT_TYPE_OS_TASK, refobjid, &token1); + OS_SharedGlobalVars.GlobalState = OS_SHUTDOWN_MAGIC_NUMBER; + expected = OS_ERR_INCORRECT_OBJ_STATE; + actual = OS_ObjectIdGetById(OS_LOCK_MODE_NONE, OS_OBJECT_TYPE_OS_TASK, refobjid, &token1); UtAssert_True(actual == expected, "OS_ObjectIdGetById() (%ld) == OS_ERR_INCORRECT_OBJ_STATE", (long)actual); - OS_SharedGlobalVars.ShutdownFlag = 0; + OS_SharedGlobalVars.GlobalState = OS_INIT_MAGIC_NUMBER; /* attempt to get lock for invalid type object should fail */ expected = OS_ERR_INCORRECT_OBJ_TYPE; actual = OS_ObjectIdGetById(OS_LOCK_MODE_NONE, 0xFFFF, refobjid, &token1); UtAssert_True(actual == expected, "OS_ObjectIdGetById() (%ld) == OS_ERR_INCORRECT_OBJ_TYPE", (long)actual); - OS_SharedGlobalVars.ShutdownFlag = 0; /* clear out state entry */ memset(&OS_global_task_table[local_idx], 0, sizeof(OS_global_task_table[local_idx])); @@ -702,10 +701,10 @@ void Test_OS_ObjectIdAllocateNew(void) actual = OS_ObjectIdGetByName(OS_LOCK_MODE_NONE, OS_OBJECT_TYPE_OS_TASK, "UT_alloc", &token); UtAssert_True(actual == expected, "OS_ObjectIdGetByName() (%ld) == OS_ERR_INCORRECT_OBJ_STATE", (long)actual); - OS_SharedGlobalVars.ShutdownFlag = OS_SHUTDOWN_MAGIC_NUMBER; - expected = OS_ERR_INCORRECT_OBJ_STATE; - actual = OS_ObjectIdAllocateNew(OS_OBJECT_TYPE_OS_TASK, "UT_alloc", &token); - OS_SharedGlobalVars.ShutdownFlag = 0; + OS_SharedGlobalVars.GlobalState = OS_SHUTDOWN_MAGIC_NUMBER; + expected = OS_ERR_INCORRECT_OBJ_STATE; + actual = OS_ObjectIdAllocateNew(OS_OBJECT_TYPE_OS_TASK, "UT_alloc", &token); + OS_SharedGlobalVars.GlobalState = OS_INIT_MAGIC_NUMBER; UtAssert_True(actual == expected, "OS_ObjectIdAllocate() (%ld) == OS_ERR_INCORRECT_OBJ_STATE", (long)actual); expected = OS_ERR_INCORRECT_OBJ_TYPE; @@ -773,8 +772,7 @@ void Test_OS_ObjectIdTransaction(void) UtAssert_STUB_COUNT(OS_Lock_Global_Impl, 0); /* shutdown will prevent transactions */ - OS_SharedGlobalVars.Initialized = true; - OS_SharedGlobalVars.ShutdownFlag = OS_SHUTDOWN_MAGIC_NUMBER; + OS_SharedGlobalVars.GlobalState = OS_SHUTDOWN_MAGIC_NUMBER; OSAPI_TEST_FUNCTION_RC(OS_ObjectIdTransactionInit(OS_LOCK_MODE_GLOBAL, OS_OBJECT_TYPE_OS_BINSEM, &token), OS_ERR_INCORRECT_OBJ_STATE); UtAssert_UINT32_EQ(token.lock_mode, OS_LOCK_MODE_NONE); @@ -793,7 +791,7 @@ void Test_OS_ObjectIdTransaction(void) UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 1); /* other cases for normal operating mode */ - OS_SharedGlobalVars.ShutdownFlag = 0; + OS_SharedGlobalVars.GlobalState = OS_INIT_MAGIC_NUMBER; OSAPI_TEST_FUNCTION_RC(OS_ObjectIdTransactionInit(OS_LOCK_MODE_GLOBAL, OS_OBJECT_TYPE_OS_COUNTSEM, &token), OS_SUCCESS); UtAssert_UINT32_EQ(token.lock_mode, OS_LOCK_MODE_GLOBAL); @@ -1081,10 +1079,10 @@ void Osapi_Test_Setup(void) /* * The OS_SharedGlobalVars is also used here, but set the - * "Initialized" field to true by default, as this is needed by most tests. + * "GlobalState" field to init by default, as this is needed by most tests. */ memset(&OS_SharedGlobalVars, 0, sizeof(OS_SharedGlobalVars)); - OS_SharedGlobalVars.Initialized = true; + OS_SharedGlobalVars.GlobalState = OS_INIT_MAGIC_NUMBER; } /* diff --git a/src/unit-test-coverage/shared/src/coveragetest-printf.c b/src/unit-test-coverage/shared/src/coveragetest-printf.c index e27780d1d..967781511 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-printf.c +++ b/src/unit-test-coverage/shared/src/coveragetest-printf.c @@ -68,13 +68,13 @@ void Test_OS_printf(void) /* catch case where OS_printf called before init */ OS_SharedGlobalVars.PrintfConsoleId = OS_OBJECT_ID_UNDEFINED; - OS_SharedGlobalVars.Initialized = false; + OS_SharedGlobalVars.GlobalState = 0; OS_printf("UnitTest1"); UtAssert_True(OS_console_table[0].WritePos == 0, "WritePos (%lu) >= 0", (unsigned long)OS_console_table[0].WritePos); /* because printf is disabled, the call count should _not_ increase here */ - OS_SharedGlobalVars.Initialized = true; + OS_SharedGlobalVars.GlobalState = OS_INIT_MAGIC_NUMBER; OS_printf_disable(); OS_printf("UnitTest2"); UtAssert_True(OS_console_table[0].WritePos == 0, "WritePos (%lu) >= 0", diff --git a/src/unit-tests/oscore-test/ut_oscore_test.c b/src/unit-tests/oscore-test/ut_oscore_test.c index e1662fd66..9a48689b8 100644 --- a/src/unit-tests/oscore-test/ut_oscore_test.c +++ b/src/unit-tests/oscore-test/ut_oscore_test.c @@ -188,6 +188,9 @@ void UT_os_init_task_get_info_test() void UtTest_Setup(void) { + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + UtTest_Add(UT_os_apiinit_test, NULL, NULL, "OS_API_Init"); UtTest_Add(UT_os_printf_test, NULL, NULL, "OS_printf"); diff --git a/src/unit-tests/osfile-test/ut_osfile_test.c b/src/unit-tests/osfile-test/ut_osfile_test.c index 925fdb612..db9484a8b 100644 --- a/src/unit-tests/osfile-test/ut_osfile_test.c +++ b/src/unit-tests/osfile-test/ut_osfile_test.c @@ -132,6 +132,9 @@ void UT_os_init_file_misc() void UtTest_Setup(void) { + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + UT_os_initfs_test(); if (UT_os_setup_fs() == OS_SUCCESS) diff --git a/src/unit-tests/osfilesys-test/ut_osfilesys_test.c b/src/unit-tests/osfilesys-test/ut_osfilesys_test.c index 5a8496d72..248ae5296 100644 --- a/src/unit-tests/osfilesys-test/ut_osfilesys_test.c +++ b/src/unit-tests/osfilesys-test/ut_osfilesys_test.c @@ -121,6 +121,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + UT_os_init_fs_misc(); UtTest_Add(UT_os_makefs_test, NULL, NULL, "OS_mkfs"); diff --git a/src/unit-tests/osloader-test/ut_osloader_test.c b/src/unit-tests/osloader-test/ut_osloader_test.c index 7dc7d9c6c..d0adbff8b 100644 --- a/src/unit-tests/osloader-test/ut_osloader_test.c +++ b/src/unit-tests/osloader-test/ut_osloader_test.c @@ -67,6 +67,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + /* * This test needs to load the modules from the filesystem, so * there must be a virtual path corresponding to the path where diff --git a/src/unit-tests/osnetwork-test/ut_osnetwork_test.c b/src/unit-tests/osnetwork-test/ut_osnetwork_test.c index a550d2f4a..7277b83dd 100644 --- a/src/unit-tests/osnetwork-test/ut_osnetwork_test.c +++ b/src/unit-tests/osnetwork-test/ut_osnetwork_test.c @@ -65,6 +65,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + UtTest_Add(UT_os_networkgetid_test, NULL, NULL, "OS_NetworkGetID"); UtTest_Add(UT_os_networkgethostname_test, NULL, NULL, "OS_NetworkGetHostName"); } diff --git a/src/unit-tests/ostimer-test/ut_ostimer_test.c b/src/unit-tests/ostimer-test/ut_ostimer_test.c index dcbe25d10..68e94ec89 100644 --- a/src/unit-tests/ostimer-test/ut_ostimer_test.c +++ b/src/unit-tests/ostimer-test/ut_ostimer_test.c @@ -193,6 +193,9 @@ void UtTest_Setup(void) UtAssert_Abort("OS_API_Init() failed"); } + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); + UT_os_init_timer_misc(); UtTest_Add(UT_os_timercreate_test, UT_os_setup_timercreate_test, NULL, "OS_TimerCreate");