diff --git a/README.md b/README.md index 72d57a312..fe32818ce 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,32 @@ The autogenerated OSAL user's guide can be viewed at + ### Development Build: 5.1.0-rc1+dev149 - Document UtAssert_Message parameters, also adds "see also" note for helper macros. diff --git a/src/bsp/pc-rtems/src/bsp_console.c b/src/bsp/pc-rtems/src/bsp_console.c index 9a954c20e..85e521736 100644 --- a/src/bsp/pc-rtems/src/bsp_console.c +++ b/src/bsp/pc-rtems/src/bsp_console.c @@ -41,7 +41,7 @@ OS_BSP_ConsoleOutput_Impl See full description in header ------------------------------------------------------------------*/ -void OS_BSP_ConsoleOutput_Impl(const char *Str, uint32 DataLen) +void OS_BSP_ConsoleOutput_Impl(const char *Str, size_t DataLen) { /* writes the raw data directly to STDOUT_FILENO (unbuffered) */ write(STDOUT_FILENO, Str, DataLen); diff --git a/src/os/inc/common_types.h b/src/os/inc/common_types.h index 937f9db83..ae36830e5 100644 --- a/src/os/inc/common_types.h +++ b/src/os/inc/common_types.h @@ -53,8 +53,7 @@ extern "C" ** Define compiler specific macros ** The __extension__ compiler pragma is required ** for the uint64 type using GCC with the ANSI C90 standard. -** Other macros can go in here as needed, for example alignment -** pragmas. +** Other macros can go in here as needed. ** ** NOTE: The white-box (coverage) unit testing may need to disable ** these extra attributes. These test builds define the OSAPI_NO_SPECIAL_ATTRIBS @@ -62,14 +61,10 @@ extern "C" */ #if defined(__GNUC__) && !defined(OSAPI_NO_SPECIAL_ATTRIBS) #define _EXTENSION_ __extension__ -#define OS_PACK __attribute__((packed)) -#define OS_ALIGN(n) __attribute__((aligned(n))) #define OS_USED __attribute__((used)) #define OS_PRINTF(n, m) __attribute__((format(printf, n, m))) #else #define _EXTENSION_ -#define OS_PACK -#define OS_ALIGN(n) #define OS_USED #define OS_PRINTF(n, m) #endif diff --git a/src/os/inc/osapi-clock.h b/src/os/inc/osapi-clock.h index f664d3582..30b7215e0 100644 --- a/src/os/inc/osapi-clock.h +++ b/src/os/inc/osapi-clock.h @@ -28,14 +28,26 @@ #include "osconfig.h" #include "common_types.h" -/** @brief OSAL time */ +/** + * @brief OSAL time interval structure + * + * This is used to represent a basic time interval. + * + * When used with OS_GetLocalTime/OS_SetLocalTime, this represents the + * interval from the OS's epoch point, typically 01 Jan 1970 00:00:00 UTC + * on systems that have a persistent real time clock (RTC), or the system + * boot time if there is no RTC available. + * + * Applications should not directly access fields within this structure, + * as the definition may change in future versions of OSAL. Instead, + * applications should use the accessor/conversion methods defined below. + */ typedef struct { uint32 seconds; uint32 microsecs; } OS_time_t; - /** @defgroup OSAPIClock OSAL Real Time Clock APIs * @{ */ @@ -66,7 +78,329 @@ int32 OS_GetLocalTime(OS_time_t *time_struct); * * @return Set local time status, see @ref OSReturnCodes */ -int32 OS_SetLocalTime(OS_time_t *time_struct); +int32 OS_SetLocalTime(const OS_time_t *time_struct); + + +/*-------------------------------------------------------------------------------------*/ +/* + * Accessor / Unit Conversion routines for OS_time_t + * + * These routines allow the user to simply interpret OS_time_t intervals into + * in normalized units of whole seconds, milliseconds, microseconds, or nanoseconds. + */ +/*-------------------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Get interval from an OS_time_t object normalized to whole number of seconds + * + * Extracts the number of whole seconds from a given OS_time_t object, discarding + * any fractional component. + * + * This may also replace a direct read of the "seconds" field from + * the OS_time_t object from previous versions of OSAL, where the + * structure was defined with separate seconds/microseconds fields. + * + * @sa OS_TimeGetMicrosecondsPart() + * + * @param[in] tm Time interval value + * @returns Whole number of seconds in time interval + */ +static inline int64 OS_TimeGetTotalSeconds(OS_time_t tm) +{ + return (tm.seconds); +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Get interval from an OS_time_t object normalized to millisecond units + * + * Note this refers to the complete interval, not just the fractional part. + * + * @param[in] tm Time interval value + * @returns Whole number of milliseconds in time interval + */ +static inline int64 OS_TimeGetTotalMilliseconds(OS_time_t tm) +{ + return (((int64)tm.seconds * 1000) + (tm.microsecs / 1000)); +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Get interval from an OS_time_t object normalized to microsecond units + * + * Note this refers to the complete interval, not just the fractional part. + * + * @param[in] tm Time interval value + * @returns Whole number of microseconds in time interval + */ +static inline int64 OS_TimeGetTotalMicroseconds(OS_time_t tm) +{ + return (((int64)tm.seconds * 1000000) + tm.microsecs); +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Get interval from an OS_time_t object normalized to nanosecond units + * + * Note this refers to the complete interval, not just the fractional part. + * + * @note There is no protection against overflow of the 64-bit return value. + * Applications must use caution to ensure that the interval does not exceed the + * representable range of a signed 64 bit integer - approximately 140 years. + * + * @param[in] tm Time interval value + * @returns Whole number of microseconds in time interval + */ +static inline int64 OS_TimeGetTotalNanoseconds(OS_time_t tm) +{ + return (((int64)tm.seconds * 1000000000) + (tm.microsecs * 1000)); +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Get subseconds portion (fractional part only) from an OS_time_t object + * + * Extracts the fractional part from a given OS_time_t object. + * Units returned are in ticks, not normalized to any standard time unit. + * + * @param[in] tm Time interval value + * @returns Fractional/subsecond portion of time interval in ticks + */ +static inline int64 OS_TimeGetFractionalPart(OS_time_t tm) +{ + return (tm.microsecs); +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Get 32-bit normalized subseconds (fractional part only) from an OS_time_t object + * + * Extracts the fractional part from a given OS_time_t object in maximum precision, + * with units of 2^(-32) sec. This is a base-2 fixed-point fractional value + * with the point left-justified in the 32-bit value (i.e. left of MSB). + * + * This is (mostly) compatible with the CFE "subseconds" value, where 0x80000000 represents + * exactly one half second, and 0 represents a full second. + * + * @param[in] tm Time interval value + * @returns Fractional/subsecond portion of time interval as 32-bit fixed point value + */ +static inline uint32 OS_TimeGetSubsecondsPart(OS_time_t tm) +{ + /* + * This computation avoids a 32-bit left shift which may not be implemented. + * + * It also must round up, otherwise this may result in a value one + * less than the original when converted back to usec again. + */ + return (((OS_TimeGetFractionalPart(tm) << 26) + 15624) / 15625); +} + + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Get milliseconds portion (fractional part only) from an OS_time_t object + * + * Extracts the fractional part from a given OS_time_t object normalized + * to units of milliseconds. + * + * @sa OS_TimeGetTotalSeconds() + * + * @param[in] tm Time interval value + * @returns Number of milliseconds in time interval + */ +static inline uint32 OS_TimeGetMillisecondsPart(OS_time_t tm) +{ + return OS_TimeGetFractionalPart(tm) / 1000; +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Get microseconds portion (fractional part only) from an OS_time_t object + * + * Extracts the fractional part from a given OS_time_t object normalized + * to units of microseconds. + * + * This function may be used to adapt applications initially implemented + * using an older OSAL version where OS_time_t was a structure containing + * a "seconds" and "microsecs" field. + * + * This function will obtain a value that is compatible with the "microsecs" field of + * OS_time_t as it was defined in previous versions of OSAL, as well as the "tv_usec" + * field of POSIX-style "struct timeval" values. + * + * @sa OS_TimeGetTotalSeconds() + * + * @param[in] tm Time interval value + * @returns Number of microseconds in time interval + */ +static inline uint32 OS_TimeGetMicrosecondsPart(OS_time_t tm) +{ + return OS_TimeGetFractionalPart(tm); +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Get nanoseconds portion (fractional part only) from an OS_time_t object + * + * Extracts the only number of nanoseconds from a given OS_time_t object. + * + * This function will obtain a value that is compatible with the "tv_nsec" field + * of POSIX-style "struct timespec" values. + * + * @sa OS_TimeGetTotalSeconds() + * + * @param[in] tm Time interval value + * @returns Number of nanoseconds in time interval + */ +static inline uint32 OS_TimeGetNanosecondsPart(OS_time_t tm) +{ + return OS_TimeGetFractionalPart(tm) * 1000; +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Assemble/Convert a number of seconds + nanoseconds into an OS_time_t interval + * + * This creates an OS_time_t value using a whole number of seconds and a fractional + * part in units of nanoseconds. This is the inverse of OS_TimeGetTotalSeconds() + * and OS_TimeGetNanosecondsPart(), and should recreate the original OS_time_t + * value from these separate values (aside from any potential conversion losses + * due to limited resolution of the data types/units). + * + * @sa OS_TimeGetTotalSeconds(), OS_TimeGetNanosecondsPart() + * + * @param[in] seconds Whole number of seconds + * @param[in] nanoseconds Number of nanoseconds (fractional part only) + * @returns The input arguments represented as an OS_time_t interval + */ +static inline OS_time_t OS_TimeAssembleFromNanoseconds(int64 seconds, uint32 nanoseconds) +{ + OS_time_t result; + result.seconds = seconds; + result.microsecs = nanoseconds / 1000; + return result; +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Assemble/Convert a number of seconds + microseconds into an OS_time_t interval + * + * This creates an OS_time_t value using a whole number of seconds and a fractional + * part in units of microseconds. This is the inverse of OS_TimeGetTotalSeconds() + * and OS_TimeGetMicrosecondsPart(), and should recreate the original OS_time_t + * value from these separate values (aside from any potential conversion losses + * due to limited resolution of the data types/units). + * + * @sa OS_TimeGetTotalSeconds(), OS_TimeGetMicrosecondsPart() + * + * @param[in] seconds Whole number of seconds + * @param[in] microseconds Number of microseconds (fractional part only) + * @returns The input arguments represented as an OS_time_t interval + */ +static inline OS_time_t OS_TimeAssembleFromMicroseconds(int64 seconds, uint32 microseconds) +{ + OS_time_t result; + result.seconds = seconds; + result.microsecs = microseconds; + return result; +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Assemble/Convert a number of seconds + milliseconds into an OS_time_t interval + * + * This creates an OS_time_t value using a whole number of seconds and a fractional + * part in units of milliseconds. This is the inverse of OS_TimeGetTotalSeconds() + * and OS_TimeGetMillisecondsPart(), and should recreate the original OS_time_t + * value from these separate values (aside from any potential conversion losses + * due to limited resolution of the data types/units). + * + * @sa OS_TimeGetTotalSeconds(), OS_TimeGetMillisecondsPart() + * + * @param[in] seconds Whole number of seconds + * @param[in] milliseconds Number of milliseconds (fractional part only) + * @returns The input arguments represented as an OS_time_t interval + */ +static inline OS_time_t OS_TimeAssembleFromMilliseconds(int64 seconds, uint32 milliseconds) +{ + OS_time_t result; + result.seconds = seconds; + result.microsecs = milliseconds * 1000; + return result; +} + + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Assemble/Convert a number of seconds + subseconds into an OS_time_t interval + * + * This creates an OS_time_t value using a whole number of seconds and a fractional + * part in units of sub-seconds (1/2^32). This is the inverse of OS_TimeGetTotalSeconds() + * and OS_TimeGetSubsecondsPart(), and should recreate the original OS_time_t + * value from these separate values (aside from any potential conversion losses + * due to limited resolution of the data types/units). + * + * @sa OS_TimeGetTotalSeconds(), OS_TimeGetNanosecondsPart() + * @param[in] seconds Whole number of seconds + * @param[in] subseconds Number of subseconds (32 bit fixed point fractional part) + * @returns The input arguments represented as an OS_time_t interval + */ +static inline OS_time_t OS_TimeAssembleFromSubseconds(int64 seconds, uint32 subseconds) +{ + OS_time_t result; + result.seconds = seconds; + /* this should not round in any way, as the 32-bit input value has higher precision */ + result.microsecs = ((int64)subseconds * 15625) >> 26; + return result; +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Computes the sum of two time intervals + * + * @param[in] time1 The first interval + * @param[in] time2 The second interval + * + * @return The sum of the two intervals (time1 + time2) + */ +static inline OS_time_t OS_TimeAdd(OS_time_t time1, OS_time_t time2) +{ + OS_time_t result = time1; + result.seconds += time2.seconds; + result.microsecs += time2.microsecs; + if (result.microsecs >= 1000000) + { + ++result.seconds; + result.microsecs -= 1000000; + } + return result; +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Computes the difference between two time intervals + * + * @param[in] time1 The first interval + * @param[in] time2 The second interval + * + * @return The difference of the two intervals (time1 - time2) + */ +static inline OS_time_t OS_TimeSubtract(OS_time_t time1, OS_time_t time2) +{ + OS_time_t result = time1; + result.seconds -= time2.seconds; + result.microsecs -= time2.microsecs; + if (result.microsecs >= 1000000) + { + --result.seconds; + result.microsecs += 1000000; + } + return result; +} + + /**@}*/ #endif diff --git a/src/os/inc/osapi-file.h b/src/os/inc/osapi-file.h index fea9f7519..011da6872 100644 --- a/src/os/inc/osapi-file.h +++ b/src/os/inc/osapi-file.h @@ -27,6 +27,7 @@ #include "osconfig.h" #include "common_types.h" +#include "osapi-clock.h" /** @defgroup OSFileAccess OSAL File Access Option Defines @@ -63,9 +64,9 @@ typedef struct */ typedef struct { - uint32 FileModeBits; - int32 FileTime; - size_t FileSize; + uint32 FileModeBits; + OS_time_t FileTime; + size_t FileSize; } os_fstat_t; /** @@ -96,8 +97,8 @@ enum #define OS_FILESTAT_READ(x) ((x).FileModeBits & OS_FILESTAT_MODE_READ) /** @brief Access file stat size field */ #define OS_FILESTAT_SIZE(x) ((x).FileSize) -/** @brief Access file stat time field */ -#define OS_FILESTAT_TIME(x) ((x).FileTime) +/** @brief Access file stat time field as a whole number of seconds */ +#define OS_FILESTAT_TIME(x) (OS_TimeGetTotalSeconds((x).FileTime)) /** * @brief Flags that can be used with opening of a file (bitmask) diff --git a/src/os/inc/osapi-filesys.h b/src/os/inc/osapi-filesys.h index 8b3d6797c..8e37bdfb4 100644 --- a/src/os/inc/osapi-filesys.h +++ b/src/os/inc/osapi-filesys.h @@ -41,6 +41,19 @@ typedef struct uint32 FreeVolumes; /**< @brief Total number of volumes free */ } os_fsinfo_t; +/* + * @brief The data type filled in by the OS_FileSysStatVolume() call. + * + * Encapsulates detail information about the size and available space + * in a mounted file system volume. + */ +typedef struct +{ + size_t block_size; /**< Block size of underlying FS */ + osal_blockcount_t total_blocks; /**< Total blocks in underlying FS */ + osal_blockcount_t blocks_free; /**< Available blocks in underlying FS */ +} OS_statvfs_t; + /* * Exported Functions */ @@ -56,6 +69,16 @@ typedef struct * This mimics the behavior of a "FS_BASED" entry in the VolumeTable but is registered * at runtime. It is intended to be called by the PSP/BSP prior to starting the application. * + * @note OSAL virtual mount points are required to be a single, non-empty top-level directory + * name. Virtual path names always follow the form /\/\/\. + * Only the relative path may be omitted/empty (i.e. /\/\) but the + * virtual mount point must be present and not an empty string. In particular this means + * it is not possible to directly refer to files in the "root" of the native file system + * from OSAL. However it is possible to create a virtual map to the root, such as by calling: + * + * OS_FileSysAddFixedMap(&fs_id, "/", "/root"); + * + * * @param[out] filesys_id A non-zero OSAL ID reflecting the file system * @param[in] phys_path The native system directory (an existing mount point) * @param[in] virt_path The virtual mount point of this filesystem @@ -201,6 +224,30 @@ int32 OS_fsBlocksFree(const char *name); */ int32 OS_fsBytesFree(const char *name, uint64 *bytes_free); +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Obtains information about size and free space in a volume + * + * Populates the supplied OS_statvfs_t structure, which includes + * the block size and total/free blocks in a file system volume. + * + * This replaces two older OSAL calls: + * + * OS_fsBlocksFree() is determined by reading the blocks_free + * output struct member + * OS_fsBytesFree() is determined by multiplying blocks_free + * by the block_size member + * + * @param[in] name The device/path to operate on + * @param[out] statbuf Output structure to populate + * + * @return Execution status, see @ref OSReturnCodes + * @retval #OS_SUCCESS @copybrief OS_SUCCESS + * @retval #OS_INVALID_POINTER if name or statbuf is NULL + * @retval #OS_ERROR if the OS call failed + */ +int32 OS_FileSysStatVolume(const char *name, OS_statvfs_t *statbuf); + /*-------------------------------------------------------------------------------------*/ /** * @brief Checks the health of a file system and repairs it if necessary diff --git a/src/os/inc/osapi-version.h b/src/os/inc/osapi-version.h index 3b17e2e7d..d6945377e 100644 --- a/src/os/inc/osapi-version.h +++ b/src/os/inc/osapi-version.h @@ -30,7 +30,7 @@ /* * Development Build Macro Definitions */ -#define OS_BUILD_NUMBER 149 +#define OS_BUILD_NUMBER 184 #define OS_BUILD_BASELINE "v5.1.0-rc1" /* diff --git a/src/os/portable/os-impl-posix-files.c b/src/os/portable/os-impl-posix-files.c index cb8d7df96..d97a205fa 100644 --- a/src/os/portable/os-impl-posix-files.c +++ b/src/os/portable/os-impl-posix-files.c @@ -45,6 +45,7 @@ #include #include #include +#include #include "os-impl-files.h" #include "os-shared-file.h" @@ -133,10 +134,11 @@ int32 OS_FileOpen_Impl(const OS_object_token_t *token, const char *local_path, i *-----------------------------------------------------------------*/ int32 OS_FileStat_Impl(const char *local_path, os_fstat_t *FileStats) { - struct stat st; - mode_t readbits; - mode_t writebits; - mode_t execbits; + struct stat st; + mode_t readbits; + mode_t writebits; + mode_t execbits; + struct timespec filetime; if (stat(local_path, &st) < 0) { @@ -144,7 +146,31 @@ int32 OS_FileStat_Impl(const char *local_path, os_fstat_t *FileStats) } FileStats->FileSize = st.st_size; - FileStats->FileTime = st.st_mtime; + + /* + * NOTE: Traditional timestamps are only a whole number of seconds (time_t) + * POSIX.1-2008 expands this to have a full "struct timespec" with nanosecond + * resolution. + * + * GLIBC (and likely other C libraries that use similar feature selection) + * will expose this value based on _POSIX_C_SOURCE or _XOPEN_SOURCE minimum + * values. Otherwise this just falls back to standard 1-second resolution + * available via the "st_mtime" member. + */ +#if (_POSIX_C_SOURCE >= 200809L) || (_XOPEN_SOURCE >= 700) + /* + * Better - use the full resolution (seconds + nanoseconds) as specified in POSIX.1-2008 + */ + filetime = st.st_mtim; +#else + /* + * Fallback - every POSIX-compliant implementation must expose "st_mtime" field. + */ + filetime.tv_sec = st.st_mtime; + filetime.tv_nsec = 0; +#endif + + FileStats->FileTime = OS_TimeAssembleFromNanoseconds(filetime.tv_sec, filetime.tv_nsec); /* note that the "fst_mode" member is already zeroed by the caller */ if (S_ISDIR(st.st_mode)) @@ -203,6 +229,7 @@ int32 OS_FileChmod_Impl(const char *local_path, uint32 access) mode_t writebits; struct stat st; int fd; + int32 status; /* Open file to avoid filename race potential */ fd = open(local_path, O_RDONLY, 0); @@ -211,10 +238,16 @@ int32 OS_FileChmod_Impl(const char *local_path, uint32 access) fd = open(local_path, O_WRONLY, 0); if (fd < 0) { + OS_DEBUG("open(%s): %s (%d)\n", local_path, strerror(errno), errno); return OS_ERROR; - } + } } + /* + * NOTE: After this point, execution must proceed to the end of this routine + * so that the "fd" opened above can be properly closed. + */ + /* * In order to preserve any OTHER mode bits, * first stat() the file and then modify the st_mode @@ -226,58 +259,81 @@ int32 OS_FileChmod_Impl(const char *local_path, uint32 access) */ if (fstat(fd, &st) < 0) { - return OS_ERROR; + OS_DEBUG("fstat(%s): %s (%d)\n", local_path, strerror(errno), errno); + status = OS_ERROR; } - - /* always check world bits */ - readbits = S_IROTH; - writebits = S_IWOTH; - - if (OS_IMPL_SELF_EUID == st.st_uid) + else { - /* we own the file so use user bits */ - readbits |= S_IRUSR; - writebits |= S_IWUSR; - } + /* always check world bits */ + readbits = S_IROTH; + writebits = S_IWOTH; - if (OS_IMPL_SELF_EGID == st.st_gid) - { - /* our group owns the file so use group bits */ - readbits |= S_IRGRP; - writebits |= S_IWGRP; - } + if (OS_IMPL_SELF_EUID == st.st_uid) + { + /* we own the file so use user bits */ + readbits |= S_IRUSR; + writebits |= S_IWUSR; + } - if (access == OS_WRITE_ONLY || access == OS_READ_WRITE) - { - /* set all "write" mode bits */ - st.st_mode |= writebits; - } - else - { - /* clear all "write" mode bits */ - st.st_mode &= ~writebits; - } + if (OS_IMPL_SELF_EGID == st.st_gid) + { + /* our group owns the file so use group bits */ + readbits |= S_IRGRP; + writebits |= S_IWGRP; + } - if (access == OS_READ_ONLY || access == OS_READ_WRITE) - { - /* set all "read" mode bits */ - st.st_mode |= readbits; - } - else - { - /* clear all "read" mode bits */ - st.st_mode &= ~readbits; - } + if (access == OS_WRITE_ONLY || access == OS_READ_WRITE) + { + /* set all "write" mode bits */ + st.st_mode |= writebits; + } + else + { + /* clear all "write" mode bits */ + st.st_mode &= ~writebits; + } - /* finally, write the modified mode back to the file */ - if (fchmod(fd, st.st_mode) < 0) - { - return OS_ERROR; + if (access == OS_READ_ONLY || access == OS_READ_WRITE) + { + /* set all "read" mode bits */ + st.st_mode |= readbits; + } + else + { + /* clear all "read" mode bits */ + st.st_mode &= ~readbits; + } + + /* finally, write the modified mode back to the file */ + if (fchmod(fd, st.st_mode) < 0) + { + /* + * These particular errnos generally indicate that the + * underlying filesystem does not support chmod() + * + * This is often the case for FAT / DOSFS filesystems + * which do not have UNIX-style permissions, or (in the + * case of EROFS) if the filesystem is mounted read-only. + */ + if (errno == ENOTSUP || errno == ENOSYS || errno == EROFS) + { + status = OS_ERR_NOT_IMPLEMENTED; + } + else + { + OS_DEBUG("fchmod(%s): %s (%d)\n", local_path, strerror(errno), errno); + status = OS_ERROR; + } + } + else + { + status = OS_SUCCESS; + } } close(fd); - return OS_SUCCESS; + return status; } /* end OS_FileChmod_Impl */ diff --git a/src/os/portable/os-impl-posix-gettime.c b/src/os/portable/os-impl-posix-gettime.c index 59175d0a0..ddf59232f 100644 --- a/src/os/portable/os-impl-posix-gettime.c +++ b/src/os/portable/os-impl-posix-gettime.c @@ -73,9 +73,8 @@ int32 OS_GetLocalTime_Impl(OS_time_t *time_struct) if (Status == 0) { - time_struct->seconds = time.tv_sec; - time_struct->microsecs = time.tv_nsec / 1000; - ReturnCode = OS_SUCCESS; + *time_struct = OS_TimeAssembleFromNanoseconds(time.tv_sec, time.tv_nsec); + ReturnCode = OS_SUCCESS; } else { @@ -100,8 +99,8 @@ int32 OS_SetLocalTime_Impl(const OS_time_t *time_struct) int32 ReturnCode; struct timespec time; - time.tv_sec = time_struct->seconds; - time.tv_nsec = (time_struct->microsecs * 1000); + time.tv_sec = OS_TimeGetTotalSeconds(*time_struct); + time.tv_nsec = OS_TimeGetNanosecondsPart(*time_struct); Status = clock_settime(OSAL_GETTIME_SOURCE_CLOCK, &time); diff --git a/src/os/posix/inc/os-impl-idmap.h b/src/os/posix/inc/os-impl-idmap.h new file mode 100644 index 000000000..fcedf13ef --- /dev/null +++ b/src/os/posix/inc/os-impl-idmap.h @@ -0,0 +1,44 @@ +/* + * NASA Docket No. GSC-18,370-1, and identified as "Operating System Abstraction Layer" + * + * Copyright (c) 2019 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 os-impl-idmap.h + * \ingroup posix + * \author joseph.p.hickey@nasa.gov + * + */ + +#ifndef OS_IMPL_IDMAP_H +#define OS_IMPL_IDMAP_H + +#include "osconfig.h" +#include "osapi-idmap.h" +#include + +typedef struct +{ + pthread_mutex_t mutex; + pthread_cond_t cond; +} OS_impl_objtype_lock_t; + +/* Tables where the lock state information is stored */ +extern OS_impl_objtype_lock_t *const OS_impl_objtype_lock_table[OS_OBJECT_TYPE_USER]; + +#endif /* OS_IMPL_IDMAP_H */ diff --git a/src/os/posix/src/os-impl-idmap.c b/src/os/posix/src/os-impl-idmap.c index 348bb75ad..2ec48dda3 100644 --- a/src/os/posix/src/os-impl-idmap.c +++ b/src/os/posix/src/os-impl-idmap.c @@ -34,45 +34,36 @@ #include #include "os-shared-idmap.h" - -typedef struct +#include "os-impl-idmap.h" + +static OS_impl_objtype_lock_t OS_global_task_table_lock; +static OS_impl_objtype_lock_t OS_queue_table_lock; +static OS_impl_objtype_lock_t OS_bin_sem_table_lock; +static OS_impl_objtype_lock_t OS_mutex_table_lock; +static OS_impl_objtype_lock_t OS_count_sem_table_lock; +static OS_impl_objtype_lock_t OS_stream_table_lock; +static OS_impl_objtype_lock_t OS_dir_table_lock; +static OS_impl_objtype_lock_t OS_timebase_table_lock; +static OS_impl_objtype_lock_t OS_timecb_table_lock; +static OS_impl_objtype_lock_t OS_module_table_lock; +static OS_impl_objtype_lock_t OS_filesys_table_lock; +static OS_impl_objtype_lock_t OS_console_lock; + +OS_impl_objtype_lock_t * const OS_impl_objtype_lock_table[OS_OBJECT_TYPE_USER] = { - pthread_mutex_t mutex; - pthread_cond_t cond; -} POSIX_GlobalLock_t; - -static POSIX_GlobalLock_t OS_global_task_table_mut; -static POSIX_GlobalLock_t OS_queue_table_mut; -static POSIX_GlobalLock_t OS_bin_sem_table_mut; -static POSIX_GlobalLock_t OS_mutex_table_mut; -static POSIX_GlobalLock_t OS_count_sem_table_mut; -static POSIX_GlobalLock_t OS_stream_table_mut; -static POSIX_GlobalLock_t OS_dir_table_mut; -static POSIX_GlobalLock_t OS_timebase_table_mut; -static POSIX_GlobalLock_t OS_timecb_table_mut; -static POSIX_GlobalLock_t OS_module_table_mut; -static POSIX_GlobalLock_t OS_filesys_table_mut; -static POSIX_GlobalLock_t OS_console_mut; - -static POSIX_GlobalLock_t *const MUTEX_TABLE[] = { [OS_OBJECT_TYPE_UNDEFINED] = NULL, - [OS_OBJECT_TYPE_OS_TASK] = &OS_global_task_table_mut, - [OS_OBJECT_TYPE_OS_QUEUE] = &OS_queue_table_mut, - [OS_OBJECT_TYPE_OS_COUNTSEM] = &OS_count_sem_table_mut, - [OS_OBJECT_TYPE_OS_BINSEM] = &OS_bin_sem_table_mut, - [OS_OBJECT_TYPE_OS_MUTEX] = &OS_mutex_table_mut, - [OS_OBJECT_TYPE_OS_STREAM] = &OS_stream_table_mut, - [OS_OBJECT_TYPE_OS_DIR] = &OS_dir_table_mut, - [OS_OBJECT_TYPE_OS_TIMEBASE] = &OS_timebase_table_mut, - [OS_OBJECT_TYPE_OS_TIMECB] = &OS_timecb_table_mut, - [OS_OBJECT_TYPE_OS_MODULE] = &OS_module_table_mut, - [OS_OBJECT_TYPE_OS_FILESYS] = &OS_filesys_table_mut, - [OS_OBJECT_TYPE_OS_CONSOLE] = &OS_console_mut, -}; - -enum -{ - MUTEX_TABLE_SIZE = (sizeof(MUTEX_TABLE) / sizeof(MUTEX_TABLE[0])) + [OS_OBJECT_TYPE_OS_TASK] = &OS_global_task_table_lock, + [OS_OBJECT_TYPE_OS_QUEUE] = &OS_queue_table_lock, + [OS_OBJECT_TYPE_OS_COUNTSEM] = &OS_count_sem_table_lock, + [OS_OBJECT_TYPE_OS_BINSEM] = &OS_bin_sem_table_lock, + [OS_OBJECT_TYPE_OS_MUTEX] = &OS_mutex_table_lock, + [OS_OBJECT_TYPE_OS_STREAM] = &OS_stream_table_lock, + [OS_OBJECT_TYPE_OS_DIR] = &OS_dir_table_lock, + [OS_OBJECT_TYPE_OS_TIMEBASE] = &OS_timebase_table_lock, + [OS_OBJECT_TYPE_OS_TIMECB] = &OS_timecb_table_lock, + [OS_OBJECT_TYPE_OS_MODULE] = &OS_module_table_lock, + [OS_OBJECT_TYPE_OS_FILESYS] = &OS_filesys_table_lock, + [OS_OBJECT_TYPE_OS_CONSOLE] = &OS_console_lock, }; /*--------------------------------------------------------------------------------------- @@ -92,31 +83,19 @@ void OS_Posix_ReleaseTableMutex(void *mut) * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_Lock_Global_Impl(osal_objtype_t idtype) +void OS_Lock_Global_Impl(osal_objtype_t idtype) { - POSIX_GlobalLock_t *mut; + OS_impl_objtype_lock_t *impl; int ret; - if (idtype < MUTEX_TABLE_SIZE) - { - mut = MUTEX_TABLE[idtype]; - } - else - { - mut = NULL; - } + impl = OS_impl_objtype_lock_table[idtype]; - if (mut != NULL) + ret = pthread_mutex_lock(&impl->mutex); + if (ret != 0) { - ret = pthread_mutex_lock(&mut->mutex); - if (ret != 0) - { - OS_DEBUG("pthread_mutex_lock(&mut->mutex): %s", strerror(ret)); - return OS_ERROR; - } + OS_DEBUG("pthread_mutex_lock(&impl->mutex): %s", strerror(ret)); } - return OS_SUCCESS; } /* end OS_Lock_Global_Impl */ /*---------------------------------------------------------------- @@ -127,39 +106,27 @@ int32 OS_Lock_Global_Impl(osal_objtype_t idtype) * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_Unlock_Global_Impl(osal_objtype_t idtype) +void OS_Unlock_Global_Impl(osal_objtype_t idtype) { - POSIX_GlobalLock_t *mut; + OS_impl_objtype_lock_t *impl; int ret; - if (idtype < MUTEX_TABLE_SIZE) - { - mut = MUTEX_TABLE[idtype]; - } - else + impl = OS_impl_objtype_lock_table[idtype]; + + /* Notify any waiting threads that the state _may_ have changed */ + ret = pthread_cond_broadcast(&impl->cond); + if (ret != 0) { - mut = NULL; + OS_DEBUG("pthread_cond_broadcast(&impl->cond): %s", strerror(ret)); + /* unexpected but keep going (not critical) */ } - if (mut != NULL) + ret = pthread_mutex_unlock(&impl->mutex); + if (ret != 0) { - /* Notify any waiting threads that the state _may_ have changed */ - ret = pthread_cond_broadcast(&mut->cond); - if (ret != 0) - { - OS_DEBUG("pthread_cond_broadcast(&mut->cond): %s", strerror(ret)); - /* unexpected but keep going (not critical) */ - } - - ret = pthread_mutex_unlock(&mut->mutex); - if (ret != 0) - { - OS_DEBUG("pthread_mutex_unlock(&mut->mutex): %s", strerror(ret)); - return OS_ERROR; - } + OS_DEBUG("pthread_mutex_unlock(&impl->mutex): %s", strerror(ret)); } - return OS_SUCCESS; } /* end OS_Unlock_Global_Impl */ /*---------------------------------------------------------------- @@ -172,42 +139,39 @@ int32 OS_Unlock_Global_Impl(osal_objtype_t idtype) *-----------------------------------------------------------------*/ void OS_WaitForStateChange_Impl(osal_objtype_t idtype, uint32 attempts) { - POSIX_GlobalLock_t *impl; + OS_impl_objtype_lock_t *impl; struct timespec ts; - impl = MUTEX_TABLE[idtype]; + impl = OS_impl_objtype_lock_table[idtype]; - if (impl != NULL) - { - /* - * because pthread_cond_timedwait() is also a cancellation point, - * this pushes a cleanup handler to ensure that if canceled during this call, - * the mutex will be released. - */ - pthread_cleanup_push(OS_Posix_ReleaseTableMutex, &impl->mutex); + /* + * because pthread_cond_timedwait() is also a cancellation point, + * this pushes a cleanup handler to ensure that if canceled during this call, + * the mutex will be released. + */ + pthread_cleanup_push(OS_Posix_ReleaseTableMutex, &impl->mutex); - clock_gettime(CLOCK_REALTIME, &ts); + clock_gettime(CLOCK_REALTIME, &ts); - if (attempts <= 10) - { - /* Wait an increasing amount of time, starting at 10ms */ - ts.tv_nsec += attempts * attempts * 10000000; - if (ts.tv_nsec >= 1000000000) - { - ts.tv_nsec -= 1000000000; - ++ts.tv_sec; - } - } - else + if (attempts <= 10) + { + /* Wait an increasing amount of time, starting at 10ms */ + ts.tv_nsec += attempts * attempts * 10000000; + if (ts.tv_nsec >= 1000000000) { - /* wait 1 second (max for polling) */ + ts.tv_nsec -= 1000000000; ++ts.tv_sec; } + } + else + { + /* wait 1 second (max for polling) */ + ++ts.tv_sec; + } - pthread_cond_timedwait(&impl->cond, &impl->mutex, &ts); + pthread_cond_timedwait(&impl->cond, &impl->mutex, &ts); - pthread_cleanup_pop(false); - } + pthread_cleanup_pop(false); } /*--------------------------------------------------------------------------------------- @@ -222,23 +186,16 @@ int32 OS_Posix_TableMutex_Init(osal_objtype_t idtype) int ret; int32 return_code = OS_SUCCESS; pthread_mutexattr_t mutex_attr; - POSIX_GlobalLock_t *impl; + OS_impl_objtype_lock_t *impl; - do + impl = OS_impl_objtype_lock_table[idtype]; + if (impl == NULL) { - if (idtype >= MUTEX_TABLE_SIZE) - { - break; - } - - impl = MUTEX_TABLE[idtype]; - - /* Initialize the table mutex for the given idtype */ - if (impl == NULL) - { - break; - } + return OS_SUCCESS; + } + do + { /* * initialize the pthread mutex attribute structure with default values */ diff --git a/src/os/posix/src/os-impl-tasks.c b/src/os/posix/src/os-impl-tasks.c index b87197239..5fd06e8bf 100644 --- a/src/os/posix/src/os-impl-tasks.c +++ b/src/os/posix/src/os-impl-tasks.c @@ -484,6 +484,16 @@ int32 OS_Posix_InternalTaskCreate_Impl(pthread_t *pthr, osal_priority_t priority return (OS_ERROR); } + /* + ** Set the thread to be joinable by default + */ + return_code = pthread_attr_setdetachstate(&custom_attr, PTHREAD_CREATE_JOINABLE); + if (return_code != 0) + { + OS_DEBUG("pthread_attr_setdetachstate error in OS_TaskCreate: %s\n", strerror(return_code)); + return (OS_ERROR); + } + /* ** Test to see if the original main task scheduling priority worked. ** If so, then also set the attributes for this task. Otherwise attributes @@ -548,12 +558,6 @@ int32 OS_Posix_InternalTaskCreate_Impl(pthread_t *pthr, osal_priority_t priority ** Do not treat anything bad that happens after this point as fatal. ** The task is running, after all - better to leave well enough alone. */ - return_code = pthread_detach(*pthr); - if (return_code != 0) - { - OS_DEBUG("pthread_detach error in OS_TaskCreate: %s\n", strerror(return_code)); - } - return_code = pthread_attr_destroy(&custom_attr); if (return_code != 0) { @@ -590,6 +594,33 @@ int32 OS_TaskCreate_Impl(const OS_object_token_t *token, uint32 flags) return return_code; } /* end OS_TaskCreate_Impl */ +/*---------------------------------------------------------------- + * + * Function: OS_TaskDetach_Impl + * + * Purpose: Implemented per internal OSAL API + * See prototype for argument/return detail + * + *-----------------------------------------------------------------*/ +int32 OS_TaskDetach_Impl(const OS_object_token_t *token) +{ + OS_impl_task_internal_record_t *impl; + int ret; + + impl = OS_OBJECT_TABLE_GET(OS_impl_task_table, *token); + + ret = pthread_detach(impl->id); + + if (ret != 0) + { + OS_DEBUG("pthread_detach: Failed on Task ID = %lu, err = %s\n", + OS_ObjectIdToInteger(OS_ObjectIdFromToken(token)), strerror(ret)); + return OS_ERROR; + } + + return OS_SUCCESS; +} + /*---------------------------------------------------------------- * * Function: OS_TaskMatch_Impl @@ -623,6 +654,8 @@ int32 OS_TaskMatch_Impl(const OS_object_token_t *token) int32 OS_TaskDelete_Impl(const OS_object_token_t *token) { OS_impl_task_internal_record_t *impl; + void * retval; + int ret; impl = OS_OBJECT_TABLE_GET(OS_impl_task_table, *token); @@ -632,7 +665,35 @@ int32 OS_TaskDelete_Impl(const OS_object_token_t *token) ** to cancel here is that the thread ID is invalid because it already exited itself, ** and if that is true there is nothing wrong - everything is OK to continue normally. */ - pthread_cancel(impl->id); + ret = pthread_cancel(impl->id); + if (ret != 0) + { + OS_DEBUG("pthread_cancel: Failed on Task ID = %lu, err = %s\n", + OS_ObjectIdToInteger(OS_ObjectIdFromToken(token)), strerror(ret)); + + /* fall through (will still return OS_SUCCESS) */ + } + else + { + /* + * Note that "pthread_cancel" is a request - and successful return above + * only means that the cancellation request is pending. + * + * pthread_join() will wait until the thread has actually exited. + * + * This is important for CFE, as task deletion often occurs in + * conjunction with an application reload - which means the next + * call is likely to be OS_ModuleUnload(). So is critical that all + * tasks potentially executing code within that module have actually + * been stopped - not just pending cancellation. + */ + ret = pthread_join(impl->id, &retval); + if (ret != 0) + { + OS_DEBUG("pthread_join: Failed on Task ID = %lu, err = %s\n", + OS_ObjectIdToInteger(OS_ObjectIdFromToken(token)), strerror(ret)); + } + } return OS_SUCCESS; } /* end OS_TaskDelete_Impl */ @@ -738,6 +799,17 @@ int32 OS_TaskRegister_Impl(osal_id_t global_task_id) { int32 return_code; OS_U32ValueWrapper_t arg; + int old_state; + int old_type; + + /* + * Set cancel state=ENABLED, type=DEFERRED + * This should be the default for new threads, but + * setting explicitly to be sure that a pthread_join() + * will work as expected in case this thread is deleted. + */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_state); + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_type); arg.opaque_arg = 0; arg.id = global_task_id; diff --git a/src/os/posix/src/os-impl-timebase.c b/src/os/posix/src/os-impl-timebase.c index f20a7393f..87828730b 100644 --- a/src/os/posix/src/os-impl-timebase.c +++ b/src/os/posix/src/os-impl-timebase.c @@ -387,7 +387,7 @@ int32 OS_TimeBaseCreate_Impl(const OS_object_token_t *token) */ for (idx = 0; idx < OS_MAX_TIMEBASES; ++idx) { - if (OS_ObjectIdDefined(OS_global_timebase_table[idx].active_id) && + if (OS_ObjectIdIsValid(OS_global_timebase_table[idx].active_id) && OS_impl_timebase_table[idx].assigned_signal != 0) { sigaddset(&local->sigset, OS_impl_timebase_table[idx].assigned_signal); diff --git a/src/os/rtems/inc/os-impl-idmap.h b/src/os/rtems/inc/os-impl-idmap.h new file mode 100644 index 000000000..c953afbcf --- /dev/null +++ b/src/os/rtems/inc/os-impl-idmap.h @@ -0,0 +1,43 @@ +/* + * NASA Docket No. GSC-18,370-1, and identified as "Operating System Abstraction Layer" + * + * Copyright (c) 2019 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 os-impl-idmap.h + * \ingroup rtems + * \author joseph.p.hickey@nasa.gov + * + */ + +#ifndef OS_IMPL_IDMAP_H +#define OS_IMPL_IDMAP_H + +#include "osconfig.h" +#include "osapi-idmap.h" +#include + +typedef struct +{ + rtems_id id; +} OS_impl_objtype_lock_t; + +/* Tables where the lock state information is stored */ +extern OS_impl_objtype_lock_t *const OS_impl_objtype_lock_table[OS_OBJECT_TYPE_USER]; + +#endif /* OS_IMPL_IDMAP_H */ diff --git a/src/os/rtems/src/os-impl-idmap.c b/src/os/rtems/src/os-impl-idmap.c index 5036e97b1..340cc9fc0 100644 --- a/src/os/rtems/src/os-impl-idmap.c +++ b/src/os/rtems/src/os-impl-idmap.c @@ -33,6 +33,7 @@ #include "os-rtems.h" #include "os-shared-idmap.h" +#include "os-impl-idmap.h" /**************************************************************************************** DEFINES @@ -44,38 +45,34 @@ GLOBALS ***************************************************************************************/ -rtems_id OS_task_table_sem; -rtems_id OS_queue_table_sem; -rtems_id OS_bin_sem_table_sem; -rtems_id OS_mutex_table_sem; -rtems_id OS_count_sem_table_sem; -rtems_id OS_stream_table_mut; -rtems_id OS_dir_table_mut; -rtems_id OS_timebase_table_mut; -rtems_id OS_timecb_table_mut; -rtems_id OS_module_table_mut; -rtems_id OS_filesys_table_mut; -rtems_id OS_console_mut; - -static rtems_id *const MUTEX_TABLE[] = { - [OS_OBJECT_TYPE_UNDEFINED] = NULL, - [OS_OBJECT_TYPE_OS_TASK] = &OS_task_table_sem, - [OS_OBJECT_TYPE_OS_QUEUE] = &OS_queue_table_sem, - [OS_OBJECT_TYPE_OS_COUNTSEM] = &OS_count_sem_table_sem, - [OS_OBJECT_TYPE_OS_BINSEM] = &OS_bin_sem_table_sem, - [OS_OBJECT_TYPE_OS_MUTEX] = &OS_mutex_table_sem, - [OS_OBJECT_TYPE_OS_STREAM] = &OS_stream_table_mut, - [OS_OBJECT_TYPE_OS_DIR] = &OS_dir_table_mut, - [OS_OBJECT_TYPE_OS_TIMEBASE] = &OS_timebase_table_mut, - [OS_OBJECT_TYPE_OS_TIMECB] = &OS_timecb_table_mut, - [OS_OBJECT_TYPE_OS_MODULE] = &OS_module_table_mut, - [OS_OBJECT_TYPE_OS_FILESYS] = &OS_filesys_table_mut, - [OS_OBJECT_TYPE_OS_CONSOLE] = &OS_console_mut, -}; - -enum +static OS_impl_objtype_lock_t OS_task_table_lock; +static OS_impl_objtype_lock_t OS_queue_table_lock; +static OS_impl_objtype_lock_t OS_bin_sem_table_lock; +static OS_impl_objtype_lock_t OS_mutex_table_lock; +static OS_impl_objtype_lock_t OS_count_sem_table_lock; +static OS_impl_objtype_lock_t OS_stream_table_lock; +static OS_impl_objtype_lock_t OS_dir_table_lock; +static OS_impl_objtype_lock_t OS_timebase_table_lock; +static OS_impl_objtype_lock_t OS_timecb_table_lock; +static OS_impl_objtype_lock_t OS_module_table_lock; +static OS_impl_objtype_lock_t OS_filesys_table_lock; +static OS_impl_objtype_lock_t OS_console_lock; + +OS_impl_objtype_lock_t *const OS_impl_objtype_lock_table[OS_OBJECT_TYPE_USER] = { - MUTEX_TABLE_SIZE = (sizeof(MUTEX_TABLE) / sizeof(MUTEX_TABLE[0])) + [OS_OBJECT_TYPE_UNDEFINED] = NULL, + [OS_OBJECT_TYPE_OS_TASK] = &OS_task_table_lock, + [OS_OBJECT_TYPE_OS_QUEUE] = &OS_queue_table_lock, + [OS_OBJECT_TYPE_OS_COUNTSEM] = &OS_count_sem_table_lock, + [OS_OBJECT_TYPE_OS_BINSEM] = &OS_bin_sem_table_lock, + [OS_OBJECT_TYPE_OS_MUTEX] = &OS_mutex_table_lock, + [OS_OBJECT_TYPE_OS_STREAM] = &OS_stream_table_lock, + [OS_OBJECT_TYPE_OS_DIR] = &OS_dir_table_lock, + [OS_OBJECT_TYPE_OS_TIMEBASE] = &OS_timebase_table_lock, + [OS_OBJECT_TYPE_OS_TIMECB] = &OS_timecb_table_lock, + [OS_OBJECT_TYPE_OS_MODULE] = &OS_module_table_lock, + [OS_OBJECT_TYPE_OS_FILESYS] = &OS_filesys_table_lock, + [OS_OBJECT_TYPE_OS_CONSOLE] = &OS_console_lock, }; /*---------------------------------------------------------------- @@ -86,30 +83,19 @@ enum * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_Lock_Global_Impl(osal_objtype_t idtype) +void OS_Lock_Global_Impl(osal_objtype_t idtype) { - rtems_id *mut; - - if (idtype < MUTEX_TABLE_SIZE) - { - mut = MUTEX_TABLE[idtype]; - } - else - { - mut = NULL; - } + OS_impl_objtype_lock_t *impl; + rtems_status_code rtems_sc; - if (mut == NULL) - { - return OS_ERROR; - } + impl = OS_impl_objtype_lock_table[idtype]; - if (rtems_semaphore_obtain(*mut, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != 0) + rtems_sc = rtems_semaphore_obtain(impl->id, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (rtems_sc != RTEMS_SUCCESSFUL) { - return OS_ERROR; + OS_DEBUG("OS_Lock_Global_Impl: rtems_semaphore_obtain failed: %s\n", rtems_status_text(rtems_sc)); } - return OS_SUCCESS; } /* end OS_Lock_Global_Impl */ /*---------------------------------------------------------------- @@ -120,30 +106,19 @@ int32 OS_Lock_Global_Impl(osal_objtype_t idtype) * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_Unlock_Global_Impl(osal_objtype_t idtype) +void OS_Unlock_Global_Impl(osal_objtype_t idtype) { - rtems_id *mut; - - if (idtype < MUTEX_TABLE_SIZE) - { - mut = MUTEX_TABLE[idtype]; - } - else - { - mut = NULL; - } + OS_impl_objtype_lock_t *impl; + rtems_status_code rtems_sc; - if (mut == NULL) - { - return OS_ERROR; - } + impl = OS_impl_objtype_lock_table[idtype]; - if (rtems_semaphore_release(*mut) != 0) + rtems_sc = rtems_semaphore_release(impl->id); + if (rtems_sc != RTEMS_SUCCESSFUL) { - return OS_ERROR; + OS_DEBUG("OS_Unlock_Global_Impl: rtems_semaphore_release failed: %s\n", rtems_status_text(rtems_sc)); } - return OS_SUCCESS; } /* end OS_Unlock_Global_Impl */ /*---------------------------------------------------------------- @@ -156,19 +131,19 @@ int32 OS_Unlock_Global_Impl(osal_objtype_t idtype) *-----------------------------------------------------------------*/ void OS_WaitForStateChange_Impl(osal_objtype_t idtype, uint32 attempts) { - uint32 wait_ms; + rtems_interval wait_ticks; if (attempts <= 10) { - wait_ms = attempts * attempts * 10; + wait_ticks = attempts * attempts; } else { - wait_ms = 1000; + wait_ticks = 100; } OS_Unlock_Global_Impl(idtype); - OS_TaskDelay(wait_ms); + rtems_task_wake_after(wait_ticks); OS_Lock_Global_Impl(idtype); } @@ -186,20 +161,22 @@ void OS_WaitForStateChange_Impl(osal_objtype_t idtype, uint32 attempts) ---------------------------------------------------------------------------------------*/ int32 OS_Rtems_TableMutex_Init(osal_objtype_t idtype) { - int32 return_code = OS_SUCCESS; + OS_impl_objtype_lock_t *impl; rtems_status_code rtems_sc; - /* Initialize the table mutex for the given idtype */ - if (idtype < MUTEX_TABLE_SIZE && MUTEX_TABLE[idtype] != NULL) + impl = OS_impl_objtype_lock_table[idtype]; + if (impl == NULL) { - rtems_sc = rtems_semaphore_create(idtype, 1, OSAL_TABLE_MUTEX_ATTRIBS, 0, MUTEX_TABLE[idtype]); + return OS_SUCCESS; + } - if (rtems_sc != RTEMS_SUCCESSFUL) - { - OS_DEBUG("Error: rtems_semaphore_create failed: %s\n", rtems_status_text(rtems_sc)); - return_code = OS_ERROR; - } + /* Initialize the table mutex for the given idtype */ + rtems_sc = rtems_semaphore_create(idtype, 1, OSAL_TABLE_MUTEX_ATTRIBS, 0, &impl->id); + if (rtems_sc != RTEMS_SUCCESSFUL) + { + OS_DEBUG("Error: rtems_semaphore_create failed: %s\n", rtems_status_text(rtems_sc)); + return OS_ERROR; } - return (return_code); + return OS_SUCCESS; } /* end OS_Rtems_TableMutex_Init */ diff --git a/src/os/rtems/src/os-impl-network.c b/src/os/rtems/src/os-impl-network.c index c5a8a20ef..19c92e485 100644 --- a/src/os/rtems/src/os-impl-network.c +++ b/src/os/rtems/src/os-impl-network.c @@ -57,7 +57,7 @@ int32 OS_NetworkGetID_Impl(int32 *IdBuf) * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_NetworkGetHostName_Impl(char *host_name, uint32 name_len) +int32 OS_NetworkGetHostName_Impl(char *host_name, size_t name_len) { int32 return_code; diff --git a/src/os/rtems/src/os-impl-queues.c b/src/os/rtems/src/os-impl-queues.c index 58e978ceb..014e9e9ba 100644 --- a/src/os/rtems/src/os-impl-queues.c +++ b/src/os/rtems/src/os-impl-queues.c @@ -156,7 +156,7 @@ int32 OS_QueueDelete_Impl(const OS_object_token_t *token) * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_QueueGet_Impl(const OS_object_token_t *token, void *data, uint32 size, uint32 *size_copied, int32 timeout) +int32 OS_QueueGet_Impl(const OS_object_token_t *token, void *data, size_t size, size_t *size_copied, int32 timeout) { int32 return_code; rtems_status_code status; @@ -253,7 +253,7 @@ int32 OS_QueueGet_Impl(const OS_object_token_t *token, void *data, uint32 size, * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_QueuePut_Impl(const OS_object_token_t *token, const void *data, uint32 size, uint32 flags) +int32 OS_QueuePut_Impl(const OS_object_token_t *token, const void *data, size_t size, uint32 flags) { rtems_status_code status; rtems_id rtems_queue_id; diff --git a/src/os/rtems/src/os-impl-tasks.c b/src/os/rtems/src/os-impl-tasks.c index 606846648..f1fa62b4b 100644 --- a/src/os/rtems/src/os-impl-tasks.c +++ b/src/os/rtems/src/os-impl-tasks.c @@ -173,6 +173,20 @@ int32 OS_TaskDelete_Impl(const OS_object_token_t *token) return OS_SUCCESS; } /* end OS_TaskDelete_Impl */ +/*---------------------------------------------------------------- + * + * Function: OS_TaskDetach_Impl + * + * Purpose: Implemented per internal OSAL API + * See prototype for argument/return detail + * + *-----------------------------------------------------------------*/ +int32 OS_TaskDetach_Impl(const OS_object_token_t *token) +{ + /* No-op on RTEMS */ + return OS_SUCCESS; +} + /*---------------------------------------------------------------- * * Function: OS_TaskExit_Impl @@ -359,7 +373,7 @@ int32 OS_TaskGetInfo_Impl(const OS_object_token_t *token, OS_task_prop_t *task_p * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_TaskValidateSystemData_Impl(const void *sysdata, uint32 sysdata_size) +int32 OS_TaskValidateSystemData_Impl(const void *sysdata, size_t sysdata_size) { if (sysdata == NULL || sysdata_size != sizeof(rtems_id)) { diff --git a/src/os/shared/inc/os-shared-common.h b/src/os/shared/inc/os-shared-common.h index b13d9fb49..c3ae45f76 100644 --- a/src/os/shared/inc/os-shared-common.h +++ b/src/os/shared/inc/os-shared-common.h @@ -128,20 +128,4 @@ void OS_IdleLoop_Impl(void); ------------------------------------------------------------------*/ void OS_ApplicationShutdown_Impl(void); -/*---------------------------------------------------------------- - - Function: OS_WaitForStateChange_Impl - - Purpose: Block the caller until some sort of change event - has occurred for the given object type, such as a record changing - state i.e. the acquisition or release of a lock/refcount from - another thread. - - It is not guaranteed what, if any, state change has actually - occured when this function returns. This may be implement as - a simple OS_TaskDelay(). - - ------------------------------------------------------------------*/ -void OS_WaitForStateChange_Impl(osal_objtype_t objtype, uint32 attempts); - #endif /* OS_SHARED_COMMON_H */ diff --git a/src/os/shared/inc/os-shared-filesys.h b/src/os/shared/inc/os-shared-filesys.h index e00058301..717699f1f 100644 --- a/src/os/shared/inc/os-shared-filesys.h +++ b/src/os/shared/inc/os-shared-filesys.h @@ -84,22 +84,6 @@ enum OS_FILESYS_TYPE_MAX }; -/* - * The data type filled in by the "statvfs" call. - * - * This is defined here since there is no public API to get this info, - * only the total bytes free is accessible via the current OSAL API. - * - * However, returning the detailed info at this level means that the - * more detailed information could be made available with a new API call. - */ -typedef struct -{ - size_t block_size; - osal_blockcount_t total_blocks; - osal_blockcount_t blocks_free; -} OS_statvfs_t; - typedef struct { char device_name[OS_FS_DEV_NAME_LEN]; /**< The name of the underlying block device, if applicable */ diff --git a/src/os/shared/inc/os-shared-idmap.h b/src/os/shared/inc/os-shared-idmap.h index 2a3201932..a08e16628 100644 --- a/src/os/shared/inc/os-shared-idmap.h +++ b/src/os/shared/inc/os-shared-idmap.h @@ -31,8 +31,6 @@ #include "osapi-idmap.h" #include -#define OS_OBJECT_EXCL_REQ_FLAG 0x0001 - #define OS_OBJECT_ID_RESERVED ((osal_id_t) {0xFFFFFFFF}) /* @@ -44,7 +42,6 @@ struct OS_common_record osal_id_t active_id; osal_id_t creator; uint16 refcount; - uint16 flags; }; /* @@ -52,18 +49,29 @@ struct OS_common_record */ typedef enum { - OS_LOCK_MODE_NONE, /**< Do not lock global table at all (use with caution) */ - OS_LOCK_MODE_GLOBAL, /**< Lock during operation, and if successful, leave global table locked */ - OS_LOCK_MODE_EXCLUSIVE, /**< Like OS_LOCK_MODE_GLOBAL but must be exclusive (refcount == zero) */ - OS_LOCK_MODE_REFCOUNT, /**< If operation succeeds, increment refcount and unlock global table */ + OS_LOCK_MODE_NONE, /**< Quick ID validity check, does not lock global table at all (use with caution) */ + OS_LOCK_MODE_GLOBAL, /**< Confirm ID match, and if successful, leave global table locked */ + OS_LOCK_MODE_REFCOUNT, /**< Confirm ID match, increment refcount, and unlock global table. ID is not changed. */ + OS_LOCK_MODE_EXCLUSIVE, /**< Confirm ID match AND refcount equal zero, then change ID to RESERVED value and unlock global. */ + OS_LOCK_MODE_RESERVED /**< Confirm ID is already set to RESERVED, otherwise like OS_LOCK_MODE_GLOBAL. */ } OS_lock_mode_t; +/* + * A unique key value issued when obtaining a table lock, based on a + * the a combination of the requesting task ID and a transaction ID + */ +typedef struct +{ + uint32 key_value; +} osal_key_t; + /* * Actual (non-abstract) definition of "OS_object_token_t" */ struct OS_object_token { OS_lock_mode_t lock_mode; + osal_key_t lock_key; osal_objtype_t obj_type; osal_index_t obj_idx; osal_id_t obj_id; @@ -148,7 +156,7 @@ int32 OS_ObjectIdInit(void); Returns: OS_SUCCESS on success, or relevant error code ------------------------------------------------------------------*/ -void OS_Lock_Global(osal_objtype_t idtype); +void OS_Lock_Global(OS_object_token_t *token); /*---------------------------------------------------------------- Function: OS_Lock_Global @@ -157,7 +165,7 @@ void OS_Lock_Global(osal_objtype_t idtype); Returns: OS_SUCCESS on success, or relevant error code ------------------------------------------------------------------*/ -int32 OS_Lock_Global_Impl(osal_objtype_t idtype); +void OS_Lock_Global_Impl(osal_objtype_t idtype); /*---------------------------------------------------------------- Function: OS_Unlock_Global @@ -166,7 +174,7 @@ int32 OS_Lock_Global_Impl(osal_objtype_t idtype); Returns: OS_SUCCESS on success, or relevant error code ------------------------------------------------------------------*/ -void OS_Unlock_Global(osal_objtype_t idtype); +void OS_Unlock_Global(OS_object_token_t *token); /*---------------------------------------------------------------- Function: OS_Unlock_Global @@ -175,7 +183,7 @@ void OS_Unlock_Global(osal_objtype_t idtype); Returns: OS_SUCCESS on success, or relevant error code ------------------------------------------------------------------*/ -int32 OS_Unlock_Global_Impl(osal_objtype_t idtype); +void OS_Unlock_Global_Impl(osal_objtype_t idtype); /*---------------------------------------------------------------- @@ -188,7 +196,24 @@ int32 OS_Unlock_Global_Impl(osal_objtype_t idtype); before returning from this function. -----------------------------------------------------------------*/ -void OS_WaitForStateChange(osal_objtype_t idtype, uint32 attempts); +void OS_WaitForStateChange(OS_object_token_t *token, uint32 attempts); + +/*---------------------------------------------------------------- + + Function: OS_WaitForStateChange_Impl + + Purpose: Block the caller until some sort of change event + has occurred for the given object type, such as a record changing + state i.e. the acquisition or release of a lock/refcount from + another thread. + + It is not guaranteed what, if any, state change has actually + occured when this function returns. This may be implement as + a simple OS_TaskDelay(). + + ------------------------------------------------------------------*/ +void OS_WaitForStateChange_Impl(osal_objtype_t objtype, uint32 attempts); + /* Function prototypes for routines implemented in common layers but private to OSAL @@ -228,6 +253,26 @@ static inline void OS_ObjectIdCompose_Impl(osal_objtype_t idtype, uint32 idseria *result = OS_ObjectIdFromInteger((idtype << OS_OBJECT_TYPE_SHIFT) | idserial); } +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Check if an object ID represents a valid/active value. + * + * This tests that the ID value is within the range specifically used by + * valid OSAL IDs. This is smaller than the set of defined IDs. + * + * For example, the value of OS_OBJECT_ID_RESERVED is defined but not valid. + * So while OS_ObjectIdDefined() will match entries being actively created or + * deleted, OS_ObjectIdIsValid() will not. + * + * @param[in] object_id The object ID + * @returns true if table entry is valid + */ +static inline bool OS_ObjectIdIsValid(osal_id_t object_id) +{ + osal_objtype_t objtype = OS_ObjectIdToType_Impl(object_id); + return (objtype > OS_OBJECT_TYPE_UNDEFINED && objtype < OS_OBJECT_TYPE_USER); +} + /*---------------------------------------------------------------- Function: OS_GetMaxForObjectType @@ -488,13 +533,14 @@ static inline const OS_object_token_t *OS_ObjectIdIteratorRef(OS_object_iter_t * Returns: None ------------------------------------------------------------------*/ -int32 OS_ObjectIdIteratorProcessEntry(OS_object_iter_t *iter, int32 (*func)(osal_id_t)); +int32 OS_ObjectIdIteratorProcessEntry(OS_object_iter_t *iter, int32 (*func)(osal_id_t,void*)); /* * Internal helper functions * These are not normally called outside this unit, but need * to be exposed for unit testing. */ +bool OS_ObjectFilterActive(void *ref, const OS_object_token_t *token, const OS_common_record_t *obj); bool OS_ObjectNameMatch(void *ref, const OS_object_token_t *token, const OS_common_record_t *obj); int32 OS_ObjectIdFindNextMatch(OS_ObjectMatchFunc_t MatchFunc, void *arg, OS_object_token_t *token); int32 OS_ObjectIdFindNextFree(OS_object_token_t *token); diff --git a/src/os/shared/inc/os-shared-task.h b/src/os/shared/inc/os-shared-task.h index 4c7d74b22..f6826f05f 100644 --- a/src/os/shared/inc/os-shared-task.h +++ b/src/os/shared/inc/os-shared-task.h @@ -95,6 +95,16 @@ int32 OS_TaskMatch_Impl(const OS_object_token_t *token); ------------------------------------------------------------------*/ int32 OS_TaskCreate_Impl(const OS_object_token_t *token, uint32 flags); +/*---------------------------------------------------------------- + Function: OS_TaskDetach_Impl + + Purpose: Sets the thread so that the OS resources associated with the task + will be released when the thread exits itself + + Returns: OS_SUCCESS on success, or relevant error code + ------------------------------------------------------------------*/ +int32 OS_TaskDetach_Impl(const OS_object_token_t *token); + /*---------------------------------------------------------------- Function: OS_TaskDelete_Impl diff --git a/src/os/shared/src/osapi-clock.c b/src/os/shared/src/osapi-clock.c index 09dbf110d..1aec8bfc8 100644 --- a/src/os/shared/src/osapi-clock.c +++ b/src/os/shared/src/osapi-clock.c @@ -65,7 +65,7 @@ int32 OS_GetLocalTime(OS_time_t *time_struct) * See description in API and header file for detail * *-----------------------------------------------------------------*/ -int32 OS_SetLocalTime(OS_time_t *time_struct) +int32 OS_SetLocalTime(const OS_time_t *time_struct) { /* Check inputs */ OS_CHECK_POINTER(time_struct); diff --git a/src/os/shared/src/osapi-common.c b/src/os/shared/src/osapi-common.c index c3b7fb0b5..62a5a433b 100644 --- a/src/os/shared/src/osapi-common.c +++ b/src/os/shared/src/osapi-common.c @@ -337,7 +337,18 @@ void OS_DeleteAllObjects(void) { ObjectCount = 0; ++TryCount; + + /* Delete timers and tasks first, as they could be actively using other object types */ + OS_ForEachObjectOfType(OS_OBJECT_TYPE_OS_TIMECB, OS_OBJECT_CREATOR_ANY, + OS_CleanUpObject, &ObjectCount); + OS_ForEachObjectOfType(OS_OBJECT_TYPE_OS_TIMEBASE, OS_OBJECT_CREATOR_ANY, + OS_CleanUpObject, &ObjectCount); + OS_ForEachObjectOfType(OS_OBJECT_TYPE_OS_TASK, OS_OBJECT_CREATOR_ANY, + OS_CleanUpObject, &ObjectCount); + + /* Then try to delete all other remaining objects of any type */ OS_ForEachObject(OS_OBJECT_CREATOR_ANY, OS_CleanUpObject, &ObjectCount); + if (ObjectCount == 0 || TryCount > 4) { break; diff --git a/src/os/shared/src/osapi-file.c b/src/os/shared/src/osapi-file.c index 8947398a6..1db28e3da 100644 --- a/src/os/shared/src/osapi-file.c +++ b/src/os/shared/src/osapi-file.c @@ -68,6 +68,16 @@ enum OS_stream_internal_record_t OS_stream_table[OS_MAX_NUM_OPEN_FILES]; +/*---------------------------------------------------------------- + * + * Helper function to close a file from an iterator + * + *-----------------------------------------------------------------*/ +int32 OS_FileIteratorClose(osal_id_t filedes, void *arg) +{ + return OS_close(filedes); +} + /**************************************************************************************** FILE API ***************************************************************************************/ @@ -669,7 +679,7 @@ int32 OS_CloseFileByName(const char *Filename) if (stream->socket_domain == OS_SocketDomain_INVALID && (strcmp(stream->stream_name, Filename) == 0)) { /* call OS_close() on the entry referred to by the iterator */ - close_code = OS_ObjectIdIteratorProcessEntry(&iter, OS_close); + close_code = OS_ObjectIdIteratorProcessEntry(&iter, OS_FileIteratorClose); if (return_code == OS_FS_ERR_PATH_INVALID || close_code != OS_SUCCESS) { @@ -705,7 +715,7 @@ int32 OS_CloseAllFiles(void) while (OS_ObjectIdIteratorGetNext(&iter)) { /* call OS_close() on the entry referred to by the iterator */ - close_code = OS_ObjectIdIteratorProcessEntry(&iter, OS_close); + close_code = OS_ObjectIdIteratorProcessEntry(&iter, OS_FileIteratorClose); if (close_code != OS_SUCCESS) { return_code = close_code; diff --git a/src/os/shared/src/osapi-filesys.c b/src/os/shared/src/osapi-filesys.c index bc8156307..135e4ca77 100644 --- a/src/os/shared/src/osapi-filesys.c +++ b/src/os/shared/src/osapi-filesys.c @@ -63,6 +63,21 @@ OS_filesys_internal_record_t OS_filesys_table[LOCAL_NUM_OBJECTS]; */ const char OS_FILESYS_RAMDISK_VOLNAME_PREFIX[] = "RAM"; +/*---------------------------------------------------------------- + * + * Function: OS_FileSysFilterFree + * + * Purpose: Local helper routine, not part of OSAL API. + * Iterator function to match only the free/open entries + * + * Returns: true if the entry is free, false if it is in use + * + *-----------------------------------------------------------------*/ +bool OS_FileSysFilterFree(void *ref, const OS_object_token_t *token, const OS_common_record_t *obj) +{ + return !OS_ObjectIdDefined(obj->active_id); +} + /*---------------------------------------------------------------- * * Function: OS_FileSys_FindVirtMountPoint @@ -601,6 +616,37 @@ int32 OS_fsBytesFree(const char *name, uint64 *bytes_free) } /* end OS_fsBytesFree */ +/*---------------------------------------------------------------- + * + * Function: OS_FileSysStatVolume + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +int32 OS_FileSysStatVolume(const char *name, OS_statvfs_t *statbuf) +{ + int32 return_code; + OS_object_token_t token; + + /* Check parameters */ + OS_CHECK_PATHNAME(name); + OS_CHECK_POINTER(statbuf); + + return_code = OS_ObjectIdGetBySearch(OS_LOCK_MODE_GLOBAL, LOCAL_OBJID_TYPE, OS_FileSys_FindVirtMountPoint, + (void *)name, &token); + + if (return_code == OS_SUCCESS) + { + return_code = OS_FileSysStatVolume_Impl(&token, statbuf); + + OS_ObjectIdRelease(&token); + } + + return return_code; + +} /* end OS_FileSysStatVolume */ + /*---------------------------------------------------------------- * * Function: OS_chkfs @@ -688,7 +734,7 @@ int32 OS_FS_GetPhysDriveName(char *PhysDriveName, const char *MountPoint) *-----------------------------------------------------------------*/ int32 OS_GetFsInfo(os_fsinfo_t *filesys_info) { - osal_index_t idx; + OS_object_iter_t iter; /* Check parameters */ OS_CHECK_POINTER(filesys_info); @@ -698,29 +744,19 @@ int32 OS_GetFsInfo(os_fsinfo_t *filesys_info) filesys_info->MaxFds = OS_MAX_NUM_OPEN_FILES; filesys_info->MaxVolumes = OS_MAX_FILE_SYSTEMS; - OS_Lock_Global(OS_OBJECT_TYPE_OS_STREAM); - - for (idx = 0; idx < OS_MAX_NUM_OPEN_FILES; idx++) + OS_ObjectIdIteratorInit(OS_FileSysFilterFree, NULL, OS_OBJECT_TYPE_OS_STREAM, &iter); + while (OS_ObjectIdIteratorGetNext(&iter)) { - if (!OS_ObjectIdDefined(OS_global_stream_table[idx].active_id)) - { - filesys_info->FreeFds++; - } + ++filesys_info->FreeFds; } + OS_ObjectIdIteratorDestroy(&iter); - OS_Unlock_Global(OS_OBJECT_TYPE_OS_STREAM); - - OS_Lock_Global(OS_OBJECT_TYPE_OS_FILESYS); - - for (idx = 0; idx < OS_MAX_FILE_SYSTEMS; idx++) + OS_ObjectIdIteratorInit(OS_FileSysFilterFree, NULL, OS_OBJECT_TYPE_OS_FILESYS, &iter); + while (OS_ObjectIdIteratorGetNext(&iter)) { - if (!OS_ObjectIdDefined(OS_global_filesys_table[idx].active_id)) - { - filesys_info->FreeVolumes++; - } + ++filesys_info->FreeVolumes; } - - OS_Unlock_Global(OS_OBJECT_TYPE_OS_FILESYS); + OS_ObjectIdIteratorDestroy(&iter); return (OS_SUCCESS); } /* end OS_GetFsInfo */ diff --git a/src/os/shared/src/osapi-idmap.c b/src/os/shared/src/osapi-idmap.c index 69f89aa0b..a8fb26c4b 100644 --- a/src/os/shared/src/osapi-idmap.c +++ b/src/os/shared/src/osapi-idmap.c @@ -56,6 +56,13 @@ #include "os-shared-idmap.h" #include "os-shared-task.h" +/* + * A fixed nonzero value to put into the upper 8 bits + * of lock keys. + */ +#define OS_LOCK_KEY_FIXED_VALUE 0x4D000000 +#define OS_LOCK_KEY_INVALID ((osal_key_t) {0}) + typedef enum { OS_TASK_BASE = 0, @@ -73,6 +80,18 @@ typedef enum OS_MAX_TOTAL_RECORDS = OS_CONSOLE_BASE + OS_MAX_CONSOLES } OS_ObjectIndex_t; +/* + * A structure containing the user-specified + * details of a "foreach" iteration request + */ +typedef struct +{ + osal_id_t creator_id; + OS_ArgCallback_t user_callback; + void * user_arg; +} OS_creator_filter_t; + + /* * Global ID storage tables */ @@ -85,8 +104,12 @@ typedef struct /* Keep track of the last successfully-issued object ID of each type */ osal_id_t last_id_issued; - /* The last task to lock/own this global table */ - osal_id_t table_owner; + /* The number of individual transactions (lock/unlock cycles) on this type */ + uint32 transaction_count; + + /* The key required to unlock this table */ + osal_key_t owner_key; + } OS_objtype_state_t; OS_objtype_state_t OS_objtype_state[OS_OBJECT_TYPE_USER]; @@ -210,6 +233,44 @@ uint32 OS_GetBaseForObjectType(osal_objtype_t idtype) * (not used outside of this unit) **************************************************************/ +/*---------------------------------------------------------------- + * + * Function: OS_ForEachFilterCreator + * + * Purpose: Local helper routine, not part of OSAL API. + * Determine if the object is a match for "foreach" operations + * + *-----------------------------------------------------------------*/ +bool OS_ForEachFilterCreator(void *ref, const OS_object_token_t *token, const OS_common_record_t *obj) +{ + OS_creator_filter_t *filter = ref; + + /* + * Check if the obj_id is both valid and matches + * the specified creator_id + */ + return (OS_ObjectIdIsValid(obj->active_id) && (OS_ObjectIdEqual(filter->creator_id, OS_OBJECT_CREATOR_ANY) || + OS_ObjectIdEqual(obj->creator, filter->creator_id))); +} + +/*---------------------------------------------------------------- + * + * Function: OS_ForEachDoCallback + * + * Purpose: Local helper routine, not part of OSAL API. + * Invoke the user-specified callback routine + * + *-----------------------------------------------------------------*/ +int32 OS_ForEachDoCallback(osal_id_t obj_id, void *ref) +{ + OS_creator_filter_t *filter = ref; + + /* Just invoke the user callback */ + filter->user_callback(obj_id, filter->user_arg); + return OS_SUCCESS; +} + + /*---------------------------------------------------------------- * * Function: OS_ObjectIdGlobalFromToken @@ -279,20 +340,24 @@ int32 OS_ObjectIdTransactionInit(OS_lock_mode_t lock_mode, osal_objtype_t idtype return OS_ERR_INCORRECT_OBJ_STATE; } - if (idtype >= OS_OBJECT_TYPE_USER) + /* + * Transactions cannot be started on an object type for which + * there are no actual objects + */ + if (OS_GetMaxForObjectType(idtype) == 0) { return OS_ERR_INCORRECT_OBJ_TYPE; } - if (lock_mode != OS_LOCK_MODE_NONE) - { - OS_Lock_Global(idtype); - } - token->lock_mode = lock_mode; token->obj_type = idtype; token->obj_idx = OSAL_INDEX_C(-1); + if (lock_mode != OS_LOCK_MODE_NONE) + { + OS_Lock_Global(token); + } + return OS_SUCCESS; } /* end OS_ObjectIdTransactionInit */ @@ -309,7 +374,7 @@ void OS_ObjectIdTransactionCancel(OS_object_token_t *token) { if (token->lock_mode != OS_LOCK_MODE_NONE) { - OS_Unlock_Global(token->obj_type); + OS_Unlock_Global(token); token->lock_mode = OS_LOCK_MODE_NONE; } } @@ -354,74 +419,87 @@ void OS_ObjectIdTransactionCancel(OS_object_token_t *token) *-----------------------------------------------------------------*/ int32 OS_ObjectIdConvertToken(OS_object_token_t *token) { - int32 return_code = OS_ERROR; - uint32 exclusive_bits = 0; - uint32 attempts = 0; + int32 return_code = OS_ERROR; + uint32 attempts = 0; + OS_common_record_t *obj; + osal_id_t expected_id; - OS_common_record_t *obj = OS_ObjectIdGlobalFromToken(token); + obj = OS_ObjectIdGlobalFromToken(token); + expected_id = OS_ObjectIdFromToken(token); + + /* + * Upon entry the ID from the token must be valid + */ + if (!OS_ObjectIdIsValid(expected_id)) + { + return OS_ERR_INCORRECT_OBJ_STATE; + } + + /* + * If lock mode is RESERVED, then the ID in the record should + * already be set to OS_OBJECT_ID_RESERVED. This is for very + * specific use cases where a secondary task needs to access an + * object during its creation/deletion. + * + * For all typical modes the ID in the record should be equal + * to the token ID. + */ + if (token->lock_mode == OS_LOCK_MODE_RESERVED) + { + expected_id = OS_OBJECT_ID_RESERVED; + } while (true) { /* Validate the integrity of the ID. As the "active_id" is a single * integer, we can do this check regardless of whether global is locked or not. */ - if (!OS_ObjectIdEqual(obj->active_id, OS_ObjectIdFromToken(token))) - { - /* The ID does not match, so unlock and return error. - * This basically means the ID was stale or otherwise no longer invalid */ - return_code = OS_ERR_INVALID_ID; - break; - } - - /* - * The REFCOUNT and EXCLUSIVE lock modes require additional - * conditions on before they can be successful. - */ - if (token->lock_mode == OS_LOCK_MODE_REFCOUNT) - { - /* As long as no exclusive request is pending, we can increment the - * refcount and good to go. */ - if ((obj->flags & OS_OBJECT_EXCL_REQ_FLAG) == 0) - { - ++obj->refcount; - return_code = OS_SUCCESS; - break; - } - } - else if (token->lock_mode == OS_LOCK_MODE_EXCLUSIVE) + if (OS_ObjectIdEqual(obj->active_id, expected_id)) { /* - * Set the exclusive request flag -- this will prevent anyone else from - * incrementing the refcount while we are waiting. However we can only - * do this if there are no OTHER exclusive requests. + * Got an ID match... */ - if (exclusive_bits != 0 || (obj->flags & OS_OBJECT_EXCL_REQ_FLAG) == 0) + if (token->lock_mode == OS_LOCK_MODE_EXCLUSIVE) { /* - * As long as nothing is referencing this object, we are good to go. - * The global table will be left in a locked state in this case. + * For EXCLUSIVE mode, overwrite the ID to be RESERVED now -- this + * makes any future ID checks or lock attempts in other tasks fail to match. + */ + if (!OS_ObjectIdEqual(expected_id, OS_OBJECT_ID_RESERVED)) + { + expected_id = OS_OBJECT_ID_RESERVED; + obj->active_id = expected_id; + } + + /* + * Also confirm that reference count is zero + * If not zero, will need to wait for other tasks to release. */ if (obj->refcount == 0) { return_code = OS_SUCCESS; break; } - - exclusive_bits = OS_OBJECT_EXCL_REQ_FLAG; - obj->flags |= exclusive_bits; + } + else + { + /* + * Nothing else to test for this lock type + */ + return_code = OS_SUCCESS; + break; } } - else + else if (token->lock_mode == OS_LOCK_MODE_NONE || !OS_ObjectIdEqual(obj->active_id, OS_OBJECT_ID_RESERVED)) { - /* No fanciness required - move on. */ - return_code = OS_SUCCESS; + /* Not an ID match and not RESERVED - fail out */ + return_code = OS_ERR_INVALID_ID; break; } /* * If we get this far, it means there is contention for access to the object. - * a) we want to increment refcount but an exclusive is pending - * b) we want exclusive but refcount is nonzero - * c) we want exclusive but another exclusive is pending + * a) we want to some type of lock but the ID is currently RESERVED + * b) the refcount is too high - need to wait for release * * In this case we will UNLOCK the global object again so that the holder * can relinquish it. We'll try again a few times before giving up hope. @@ -436,7 +514,7 @@ int32 OS_ObjectIdConvertToken(OS_object_token_t *token) /* * Call the impl layer to wait for some sort of change to occur. */ - OS_WaitForStateChange(token->obj_type, attempts); + OS_WaitForStateChange(token, attempts); } /* @@ -447,20 +525,36 @@ int32 OS_ObjectIdConvertToken(OS_object_token_t *token) */ if (token->lock_mode != OS_LOCK_MODE_NONE) { - /* - * In case any exclusive bits were set locally, unset them now - * before the lock is (maybe) released. - */ - obj->flags &= ~exclusive_bits; + if (return_code == OS_SUCCESS) + { + /* always increment the refcount, which means a task is actively + * using or modifying this record. */ + ++obj->refcount; - /* - * On a successful operation, the global is unlocked if it is a REFCOUNT - * style lock. For other styles (GLOBAL or EXCLUSIVE) the global lock - * should be maintained and returned to the caller. - */ - if (return_code == OS_SUCCESS && token->lock_mode == OS_LOCK_MODE_REFCOUNT) + /* + * On a successful operation, the global is unlocked if it is + * a REFCOUNT or EXCLUSIVE lock. Note for EXCLUSIVE, because the ID + * was overwritten to OS_OBJECT_ID_RESERVED, other tasks will not be + * able to access the object because the ID will not match, so the + * table can be unlocked while the remainder of the create/delete process + * continues. + * + * For OS_LOCK_MODE_GLOBAL the global lock should be maintained and + * returned to the caller. + */ + if (token->lock_mode == OS_LOCK_MODE_REFCOUNT || token->lock_mode == OS_LOCK_MODE_EXCLUSIVE) + { + OS_Unlock_Global(token); + } + } + else if (token->lock_mode == OS_LOCK_MODE_EXCLUSIVE && OS_ObjectIdEqual(expected_id, OS_OBJECT_ID_RESERVED)) { - OS_Unlock_Global(token->obj_type); + /* + * On failure, if the active_id was overwritten, then set + * it back to the original value which is in the token. + * (note it had to match initially before overwrite) + */ + obj->active_id = OS_ObjectIdFromToken(token); } } @@ -617,59 +711,62 @@ int32 OS_ObjectIdFindNextFree(OS_object_token_t *token) Purpose: Locks the global table identified by "idtype" ------------------------------------------------------------------*/ -void OS_Lock_Global(osal_objtype_t idtype) +void OS_Lock_Global(OS_object_token_t *token) { - int32 return_code; osal_id_t self_task_id; OS_objtype_state_t *objtype; - if (idtype < OS_OBJECT_TYPE_USER) + if (token->obj_type < OS_OBJECT_TYPE_USER && token->lock_mode != OS_LOCK_MODE_NONE) { - objtype = &OS_objtype_state[idtype]; + objtype = &OS_objtype_state[token->obj_type]; self_task_id = OS_TaskGetId_Impl(); - return_code = OS_Lock_Global_Impl(idtype); - if (return_code == OS_SUCCESS) + OS_Lock_Global_Impl(token->obj_type); + + /* + * Track ownership of this table. It should only be owned by one + * task at a time, and this aids in recovery if the owning task is + * deleted or experiences an exception causing it to not be freed. + * + * This is done after successfully locking, so this has exclusive access + * to the state object. + */ + if (!OS_ObjectIdIsValid(self_task_id)) { /* - * Track ownership of this table. It should only be owned by one - * task at a time, and this aids in recovery if the owning task is - * deleted or experiences an exception causing it to not be freed. - * - * This is done after successfully locking, so this has exclusive access - * to the state object. + * This just means the calling context is not an OSAL-created task. + * This is not necessarily an error, but it should be tracked. + * Also note that the root/initial task also does not have an ID. */ - if (!OS_ObjectIdDefined(self_task_id)) - { - /* - * This just means the calling context is not an OSAL-created task. - * This is not necessarily an error, but it should be tracked. - * Also note that the root/initial task also does not have an ID. - */ - self_task_id = OS_OBJECT_ID_RESERVED; /* nonzero, but also won't alias a known task */ - } + self_task_id = OS_OBJECT_ID_RESERVED; /* nonzero, but also won't alias a known task */ + } - if (OS_ObjectIdDefined(objtype->table_owner)) - { - /* this is almost certainly a bug */ - OS_DEBUG("ERROR: global %u acquired by task 0x%lx when already owned by task 0x%lx\n", - (unsigned int)idtype, OS_ObjectIdToInteger(self_task_id), - OS_ObjectIdToInteger(objtype->table_owner)); - } - else - { - objtype->table_owner = self_task_id; - } + /* + * The key value is computed with fixed/nonzero flag bits combined + * with the lower 24 bits of the task ID xor'ed with transaction id. + * This makes it different for every operation, and different depending + * on what task is calling the function. + */ + token->lock_key.key_value = OS_LOCK_KEY_FIXED_VALUE | + ((OS_ObjectIdToInteger(self_task_id) ^ objtype->transaction_count) & 0xFFFFFF); + + ++objtype->transaction_count; + + if (objtype->owner_key.key_value != 0) + { + /* this is almost certainly a bug */ + OS_DEBUG("ERROR: global %u acquired by task 0x%lx when already assigned key 0x%lx\n", (unsigned int)token->obj_type, + OS_ObjectIdToInteger(self_task_id), (unsigned long)objtype->owner_key.key_value); + } + else + { + objtype->owner_key = token->lock_key; } } else { - return_code = OS_ERR_INCORRECT_OBJ_TYPE; - } - - if (return_code != OS_SUCCESS) - { - OS_DEBUG("ERROR: unable to lock global %u, error=%d\n", (unsigned int)idtype, (int)return_code); + OS_DEBUG("ERROR: cannot lock global %u for mode %u\n", + (unsigned int)token->obj_type, (unsigned int)token->lock_mode); } } @@ -678,16 +775,13 @@ void OS_Lock_Global(osal_objtype_t idtype) Purpose: Unlocks the global table identified by "idtype" ------------------------------------------------------------------*/ -void OS_Unlock_Global(osal_objtype_t idtype) +void OS_Unlock_Global(OS_object_token_t *token) { - int32 return_code; - osal_id_t self_task_id; OS_objtype_state_t *objtype; - if (idtype < OS_OBJECT_TYPE_USER) + if (token->obj_type < OS_OBJECT_TYPE_USER && token->lock_mode != OS_LOCK_MODE_NONE) { - objtype = &OS_objtype_state[idtype]; - self_task_id = OS_TaskGetId_Impl(); + objtype = &OS_objtype_state[token->obj_type]; /* * Un-track ownership of this table. It should only be owned by one @@ -697,37 +791,23 @@ void OS_Unlock_Global(osal_objtype_t idtype) * This is done before unlocking, while this has exclusive access * to the state object. */ - if (!OS_ObjectIdDefined(self_task_id)) - { - /* - * This just means the calling context is not an OSAL-created task. - * This is not necessarily an error, but it should be tracked. - * Also note that the root/initial task also does not have an ID. - */ - self_task_id = OS_OBJECT_ID_RESERVED; /* nonzero, but also won't alias a known task */ - } - - if (!OS_ObjectIdEqual(objtype->table_owner, self_task_id)) + if ((objtype->owner_key.key_value & 0xFF000000) != OS_LOCK_KEY_FIXED_VALUE || + objtype->owner_key.key_value != token->lock_key.key_value) { /* this is almost certainly a bug */ - OS_DEBUG("ERROR: global %u released by task 0x%lx when owned by task 0x%lx\n", (unsigned int)idtype, - OS_ObjectIdToInteger(self_task_id), OS_ObjectIdToInteger(objtype->table_owner)); - } - else - { - objtype->table_owner = OS_OBJECT_ID_UNDEFINED; + OS_DEBUG("ERROR: global %u released using mismatched key=0x%lx expected=0x%lx\n", (unsigned int)token->obj_type, + (unsigned long)token->lock_key.key_value, (unsigned long)objtype->owner_key.key_value); } - return_code = OS_Unlock_Global_Impl(idtype); + objtype->owner_key = OS_LOCK_KEY_INVALID; + token->lock_key = OS_LOCK_KEY_INVALID; + + OS_Unlock_Global_Impl(token->obj_type); } else { - return_code = OS_ERR_INCORRECT_OBJ_TYPE; - } - - if (return_code != OS_SUCCESS) - { - OS_DEBUG("ERROR: unable to unlock global %u, error=%d\n", (unsigned int)idtype, (int)return_code); + OS_DEBUG("ERROR: cannot unlock global %u for mode %u\n", + (unsigned int)token->obj_type, (unsigned int)token->lock_mode); } } @@ -738,33 +818,40 @@ void OS_Unlock_Global(osal_objtype_t idtype) * Purpose: Local helper routine, not part of OSAL API. * Waits for a change in the global table identified by "idtype" * + * NOTE: this must be called while the table is _LOCKED_ + * The "OS_WaitForStateChange_Impl" function should unlock + relock + * *-----------------------------------------------------------------*/ -void OS_WaitForStateChange(osal_objtype_t idtype, uint32 attempts) +void OS_WaitForStateChange(OS_object_token_t *token, uint32 attempts) { - osal_id_t saved_owner_id; + osal_key_t saved_unlock_key; OS_objtype_state_t *objtype; - if (idtype < OS_OBJECT_TYPE_USER) - { - objtype = &OS_objtype_state[idtype]; - saved_owner_id = objtype->table_owner; + /* + * This needs to release the lock, to allow other + * tasks to make a change to the table. But to avoid + * ownership warnings the key must also be temporarily + * cleared too, and restored after waiting. + */ - /* temporarily release the table */ - objtype->table_owner = OS_OBJECT_ID_UNDEFINED; + objtype = &OS_objtype_state[token->obj_type]; + saved_unlock_key = objtype->owner_key; - /* - * The implementation layer takes care of the actual unlock + wait. - * This permits use of condition variables where these two actions - * are done atomically. - */ - OS_WaitForStateChange_Impl(idtype, attempts); + /* temporarily release the table */ + objtype->owner_key = OS_LOCK_KEY_INVALID; - /* - * After return, this task owns the table again - */ - /* cppcheck-suppress redundantAssignment */ - objtype->table_owner = saved_owner_id; - } + /* + * The implementation layer takes care of the actual unlock + wait. + * This permits use of condition variables where these two actions + * are done atomically. + */ + OS_WaitForStateChange_Impl(token->obj_type, attempts); + + /* + * After return, this task owns the table again + */ + /* cppcheck-suppress redundantAssignment */ + objtype->owner_key = saved_unlock_key; } /*---------------------------------------------------------------- @@ -824,7 +911,7 @@ int32 OS_ObjectIdFinalizeNew(int32 operation_status, OS_object_token_t *token, o } /* end OS_ObjectIdFinalizeNew(, &token, ) */ /*---------------------------------------------------------------- - Function: OS_ObjectIdFinalizeDelete(, &token) + Function: OS_ObjectIdFinalizeDelete Purpose: Helper routine, not part of OSAL public API. See description in prototype @@ -888,7 +975,7 @@ int32 OS_ObjectIdGetBySearch(OS_lock_mode_t lock_mode, osal_objtype_t idtype, OS */ return_code = OS_ObjectIdConvertToken(token); } - else if (lock_mode != OS_LOCK_MODE_NONE) + else { OS_ObjectIdTransactionCancel(token); } @@ -1029,14 +1116,14 @@ void OS_ObjectIdTransactionFinish(OS_object_token_t *token, osal_id_t *final_id) record = OS_ObjectIdGlobalFromToken(token); /* re-acquire global table lock to adjust refcount */ - if (token->lock_mode == OS_LOCK_MODE_REFCOUNT) + if (token->lock_mode == OS_LOCK_MODE_EXCLUSIVE || token->lock_mode == OS_LOCK_MODE_REFCOUNT) { - OS_Lock_Global(token->obj_type); + OS_Lock_Global(token); + } - if (record->refcount > 0) - { - --record->refcount; - } + if (record->refcount > 0) + { + --record->refcount; } /* @@ -1051,9 +1138,18 @@ void OS_ObjectIdTransactionFinish(OS_object_token_t *token, osal_id_t *final_id) { record->active_id = *final_id; } + else if (token->lock_mode == OS_LOCK_MODE_EXCLUSIVE) + { + /* + * If the lock type was EXCLUSIVE, it means that the ID in the record + * was reset to OS_OBJECT_ID_RESERVED. This must restore the original + * object ID from the token. + */ + record->active_id = token->obj_id; + } /* always unlock (this also covers OS_LOCK_MODE_GLOBAL case) */ - OS_Unlock_Global(token->obj_type); + OS_Unlock_Global(token); /* * Setting to "NONE" indicates that this token has been @@ -1148,16 +1244,28 @@ int32 OS_ObjectIdAllocateNew(osal_objtype_t idtype, const char *name, OS_object_ return_code = OS_ObjectIdFindNextFree(token); } + /* If allocation failed, abort the operation now - no ID was allocated. + * After this point, if a future step fails, the allocated ID must be + * released. */ + if (return_code != OS_SUCCESS) + { + OS_ObjectIdTransactionCancel(token); + return return_code; + } + if (return_code == OS_SUCCESS) { return_code = OS_NotifyEvent(OS_EVENT_RESOURCE_ALLOCATED, token->obj_id, NULL); } - /* If allocation failed for any reason, unlock the global. - * otherwise the global should stay locked so remaining initialization can be done */ + if (return_code == OS_SUCCESS) + { + return_code = OS_ObjectIdConvertToken(token); + } + if (return_code != OS_SUCCESS) { - OS_ObjectIdTransactionCancel(token); + return_code = OS_ObjectIdFinalizeNew(return_code, token, NULL); } return return_code; @@ -1264,7 +1372,7 @@ void OS_ObjectIdIteratorDestroy(OS_object_iter_t *iter) Purpose: Call a handler function on an iterator object ID ------------------------------------------------------------------*/ -int32 OS_ObjectIdIteratorProcessEntry(OS_object_iter_t *iter, int32 (*func)(osal_id_t)) +int32 OS_ObjectIdIteratorProcessEntry(OS_object_iter_t *iter, int32 (*func)(osal_id_t, void *)) { int32 status; @@ -1272,9 +1380,9 @@ int32 OS_ObjectIdIteratorProcessEntry(OS_object_iter_t *iter, int32 (*func)(osal * This needs to temporarily unlock the global, * call the handler function, then re-lock. */ - OS_Unlock_Global(iter->token.obj_type); - status = func(iter->token.obj_id); - OS_Lock_Global(iter->token.obj_type); + OS_Unlock_Global(&iter->token); + status = func(OS_ObjectIdFromToken(&iter->token), iter->arg); + OS_Lock_Global(&iter->token); return status; } @@ -1325,55 +1433,23 @@ void OS_ForEachObject(osal_id_t creator_id, OS_ArgCallback_t callback_ptr, void * See description in API and header file for detail * *-----------------------------------------------------------------*/ -void OS_ForEachObjectOfType(osal_objtype_t idtype, osal_id_t creator_id, OS_ArgCallback_t callback_ptr, - void *callback_arg) +void OS_ForEachObjectOfType(osal_objtype_t idtype, osal_id_t creator_id, OS_ArgCallback_t callback_ptr, void *callback_arg) { - osal_index_t obj_index; - uint32 obj_max; - osal_id_t obj_id; + OS_object_iter_t iter; + OS_creator_filter_t filter; + + filter.creator_id = creator_id; + filter.user_callback = callback_ptr; + filter.user_arg = callback_arg; - obj_max = OS_GetMaxForObjectType(idtype); - if (obj_max > 0) + if (OS_ObjectIdIteratorInit(OS_ForEachFilterCreator, &filter, idtype, &iter) == OS_SUCCESS) { - obj_index = OS_GetBaseForObjectType(idtype); - OS_Lock_Global(idtype); - while (obj_max > 0) + while (OS_ObjectIdIteratorGetNext(&iter)) { - /* - * Check if the obj_id is both valid and matches - * the specified creator_id - */ - obj_id = OS_common_table[obj_index].active_id; - if (OS_ObjectIdDefined(obj_id) && !OS_ObjectIdEqual(creator_id, OS_OBJECT_CREATOR_ANY) && - !OS_ObjectIdEqual(OS_common_table[obj_index].creator, creator_id)) - { - /* valid object but not a creator match - - * skip the callback for this object */ - obj_id = OS_OBJECT_ID_UNDEFINED; - } - - if (OS_ObjectIdDefined(obj_id)) - { - /* - * Invoke Callback for the object, which must be done - * while the global table is unlocked. - * - * Note this means by the time the callback is done, - * the object could have been deleted by another task. - * - * But this must not invoke a callback with a locked table, - * as the callback function might call other OSAL functions, - * which could deadlock. - */ - OS_Unlock_Global(idtype); - (*callback_ptr)(obj_id, callback_arg); - OS_Lock_Global(idtype); - } - - ++obj_index; - --obj_max; + OS_ObjectIdIteratorProcessEntry(&iter, OS_ForEachDoCallback); } - OS_Unlock_Global(idtype); + + OS_ObjectIdIteratorDestroy(&iter); } } /* end OS_ForEachObjectOfType */ @@ -1464,6 +1540,9 @@ int32 OS_ObjectIdToArrayIndex(osal_objtype_t idtype, osal_id_t object_id, osal_i osal_objtype_t actual_type; int32 return_code; + /* Check Parameters */ + OS_CHECK_POINTER(ArrayIndex); + obj_index = OS_ObjectIdToSerialNumber_Impl(object_id); actual_type = OS_ObjectIdToType_Impl(object_id); diff --git a/src/os/shared/src/osapi-module.c b/src/os/shared/src/osapi-module.c index e5673ab51..362334115 100644 --- a/src/os/shared/src/osapi-module.c +++ b/src/os/shared/src/osapi-module.c @@ -452,6 +452,7 @@ int32 OS_SymbolTableDump(const char *filename, size_t SizeLimit) { int32 return_code; char translated_path[OS_MAX_LOCAL_PATH_LEN]; + OS_object_token_t token; /* ** Check parameters @@ -476,11 +477,15 @@ int32 OS_SymbolTableDump(const char *filename, size_t SizeLimit) * underlying implementation may safely use globals for * state storage. */ - OS_Lock_Global(LOCAL_OBJID_TYPE); + return_code = OS_ObjectIdTransactionInit(OS_LOCK_MODE_GLOBAL, LOCAL_OBJID_TYPE, &token); + if (return_code != OS_SUCCESS) + { + return (return_code); + } return_code = OS_SymbolTableDump_Impl(translated_path, SizeLimit); - OS_Unlock_Global(LOCAL_OBJID_TYPE); + OS_ObjectIdTransactionCancel(&token); return (return_code); diff --git a/src/os/shared/src/osapi-sockets.c b/src/os/shared/src/osapi-sockets.c index 1aad07df0..f610b8660 100644 --- a/src/os/shared/src/osapi-sockets.c +++ b/src/os/shared/src/osapi-sockets.c @@ -174,7 +174,7 @@ int32 OS_SocketBind(osal_id_t sock_id, const OS_SockAddr_t *Addr) /* Check Parameters */ OS_CHECK_POINTER(Addr); - return_code = OS_ObjectIdGetById(OS_LOCK_MODE_GLOBAL, LOCAL_OBJID_TYPE, sock_id, &token); + return_code = OS_ObjectIdGetById(OS_LOCK_MODE_EXCLUSIVE, LOCAL_OBJID_TYPE, sock_id, &token); if (return_code == OS_SUCCESS) { record = OS_OBJECT_TABLE_GET(OS_global_stream_table, token); @@ -185,7 +185,7 @@ int32 OS_SocketBind(osal_id_t sock_id, const OS_SockAddr_t *Addr) /* Not a socket */ return_code = OS_ERR_INCORRECT_OBJ_TYPE; } - else if (record->refcount != 0 || (stream->stream_state & (OS_STREAM_STATE_BOUND | OS_STREAM_STATE_CONNECTED)) != 0) + else if ((stream->stream_state & (OS_STREAM_STATE_BOUND | OS_STREAM_STATE_CONNECTED)) != 0) { /* Socket must be neither bound nor connected */ return_code = OS_ERR_INCORRECT_OBJ_STATE; @@ -276,47 +276,25 @@ int32 OS_SocketAccept(osal_id_t sock_id, osal_id_t *connsock_id, OS_SockAddr_t * conn->socket_domain = sock->socket_domain; conn->socket_type = sock->socket_type; - /* bumps up the refcount by 1 before finalizing, - * to avoid having to re-acquire (should be cleaned up) */ - ++conn_record->refcount; - - return_code = OS_ObjectIdFinalizeNew(return_code, &conn_token, connsock_id); - } - } - } - - if (return_code == OS_SUCCESS) - { - OS_SocketAddrInit_Impl(Addr, sock->socket_domain); + OS_SocketAddrInit_Impl(Addr, sock->socket_domain); - /* The actual accept impl is done without global table lock, only refcount lock */ - return_code = OS_SocketAccept_Impl(&sock_token, &conn_token, Addr, timeout); - } + return_code = OS_SocketAccept_Impl(&sock_token, &conn_token, Addr, timeout); - if (conn_record != NULL) - { - OS_Lock_Global(LOCAL_OBJID_TYPE); + if (return_code == OS_SUCCESS) + { + /* Generate an entry name based on the remote address */ + OS_CreateSocketName(&conn_token, Addr, sock_record->name_entry); + conn_record->name_entry = conn->stream_name; + conn->stream_state |= OS_STREAM_STATE_CONNECTED; + } - if (return_code == OS_SUCCESS) - { - /* Generate an entry name based on the remote address */ - OS_CreateSocketName(&conn_token, Addr, sock_record->name_entry); - conn_record->name_entry = conn->stream_name; - conn->stream_state |= OS_STREAM_STATE_CONNECTED; - } - else - { - /* Clear the connrecord */ - conn_record->active_id = OS_OBJECT_ID_UNDEFINED; + return_code = OS_ObjectIdFinalizeNew(return_code, &conn_token, connsock_id); + } } - /* Decrement both ref counters that were increased earlier */ - --conn_record->refcount; - OS_Unlock_Global(LOCAL_OBJID_TYPE); + OS_ObjectIdRelease(&sock_token); } - OS_ObjectIdRelease(&sock_token); - return return_code; } /* end OS_SocketAccept */ @@ -331,17 +309,15 @@ int32 OS_SocketAccept(osal_id_t sock_id, osal_id_t *connsock_id, OS_SockAddr_t * int32 OS_SocketConnect(osal_id_t sock_id, const OS_SockAddr_t *Addr, int32 Timeout) { OS_stream_internal_record_t *stream; - OS_common_record_t * record; OS_object_token_t token; int32 return_code; /* Check Parameters */ OS_CHECK_POINTER(Addr); - return_code = OS_ObjectIdGetById(OS_LOCK_MODE_GLOBAL, LOCAL_OBJID_TYPE, sock_id, &token); + return_code = OS_ObjectIdGetById(OS_LOCK_MODE_EXCLUSIVE, LOCAL_OBJID_TYPE, sock_id, &token); if (return_code == OS_SUCCESS) { - record = OS_OBJECT_TABLE_GET(OS_global_stream_table, token); stream = OS_OBJECT_TABLE_GET(OS_stream_table, token); if (stream->socket_domain == OS_SocketDomain_INVALID) @@ -355,25 +331,17 @@ int32 OS_SocketConnect(osal_id_t sock_id, const OS_SockAddr_t *Addr, int32 Timeo } else { - ++record->refcount; + return_code = OS_SocketConnect_Impl(&token, Addr, Timeout); + + if (return_code == OS_SUCCESS) + { + stream->stream_state |= OS_STREAM_STATE_CONNECTED | OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; + } } OS_ObjectIdRelease(&token); } - if (return_code == OS_SUCCESS) - { - return_code = OS_SocketConnect_Impl(&token, Addr, Timeout); - - OS_Lock_Global(LOCAL_OBJID_TYPE); - if (return_code == OS_SUCCESS) - { - stream->stream_state |= OS_STREAM_STATE_CONNECTED | OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; - } - --record->refcount; - OS_Unlock_Global(LOCAL_OBJID_TYPE); - } - return return_code; } /* end OS_SocketConnect */ @@ -437,6 +405,7 @@ int32 OS_SocketSendTo(osal_id_t sock_id, const void *buffer, size_t buflen, cons /* Check Parameters */ OS_CHECK_POINTER(buffer); OS_CHECK_SIZE(buflen); + OS_CHECK_POINTER(RemoteAddr); return_code = OS_ObjectIdGetById(OS_LOCK_MODE_REFCOUNT, LOCAL_OBJID_TYPE, sock_id, &token); if (return_code == OS_SUCCESS) diff --git a/src/os/shared/src/osapi-task.c b/src/os/shared/src/osapi-task.c index eff849d30..b46db2677 100644 --- a/src/os/shared/src/osapi-task.c +++ b/src/os/shared/src/osapi-task.c @@ -265,6 +265,8 @@ void OS_TaskExit() task_id = OS_TaskGetId_Impl(); if (OS_ObjectIdGetById(OS_LOCK_MODE_GLOBAL, LOCAL_OBJID_TYPE, task_id, &token) == OS_SUCCESS) { + OS_TaskDetach_Impl(&token); + /* Complete the operation via the common routine */ OS_ObjectIdFinalizeDelete(OS_SUCCESS, &token); } diff --git a/src/os/shared/src/osapi-timebase.c b/src/os/shared/src/osapi-timebase.c index 8ed4537cc..affca25fb 100644 --- a/src/os/shared/src/osapi-timebase.c +++ b/src/os/shared/src/osapi-timebase.c @@ -347,6 +347,8 @@ int32 OS_TimeBaseGetFreeRun(osal_id_t timebase_id, uint32 *freerun_val) OS_timebase_internal_record_t *timebase; /* Check parameters */ + OS_CHECK_POINTER(freerun_val); + return_code = OS_ObjectIdGetById(OS_LOCK_MODE_NONE, LOCAL_OBJID_TYPE, timebase_id, &token); if (return_code == OS_SUCCESS) { diff --git a/src/os/vxworks/CMakeLists.txt b/src/os/vxworks/CMakeLists.txt index 9d1cc84d7..912f3e74c 100644 --- a/src/os/vxworks/CMakeLists.txt +++ b/src/os/vxworks/CMakeLists.txt @@ -33,6 +33,7 @@ set(VXWORKS_IMPL_SRCLIST ../portable/os-impl-bsd-select.c ../portable/os-impl-posix-io.c ../portable/os-impl-posix-files.c + ../portable/os-impl-posix-dirs.c ) if (OSAL_CONFIG_INCLUDE_SHELL) @@ -45,15 +46,6 @@ else () ) endif () -if (CMAKE_SYSTEM_VERSION VERSION_GREATER_EQUAL 7.0) - list(APPEND VXWORKS_IMPL_SRCLIST - ../portable/os-impl-posix-dirs.c - ) -else () - list(APPEND VXWORKS_IMPL_SRCLIST - src/os-impl-dirs.c - ) -endif () # If some form of module loading is configured, # then build the module loader if (OSAL_CONFIG_INCLUDE_DYNAMIC_LOADER) @@ -86,3 +78,8 @@ add_library(osal_vxworks_impl OBJECT ${VXWORKS_BASE_SRCLIST} ${VXWORKS_IMPL_SRCLIST} ) + +if (CMAKE_SYSTEM_VERSION VERSION_LESS 7.0) + target_compile_definitions(osal_vxworks_impl PRIVATE OSAL_VXWORKS6_COMPATIBILITY) +endif () + diff --git a/src/os/vxworks/inc/os-impl-dirs.h b/src/os/vxworks/inc/os-impl-dirs.h index 43029aaa1..9dc4447f7 100644 --- a/src/os/vxworks/inc/os-impl-dirs.h +++ b/src/os/vxworks/inc/os-impl-dirs.h @@ -31,8 +31,20 @@ #include "osconfig.h" #include #include +#include #include +/* + * In VxWorks 6.x the system mkdir() function only has a path argument + * In VxWorks 7 it is now POSIX compilant and adds a mode argument + * + * This macro simply discards the second argument, allowing code to use + * mkdir() in a consistent, POSIX compliant fashion. + */ +#ifdef OSAL_VXWORKS6_COMPATIBILITY +#define mkdir(path,mode) mkdir(path) +#endif + typedef struct { DIR *dp; diff --git a/src/os/vxworks/inc/os-impl-idmap.h b/src/os/vxworks/inc/os-impl-idmap.h new file mode 100644 index 000000000..a8e47a580 --- /dev/null +++ b/src/os/vxworks/inc/os-impl-idmap.h @@ -0,0 +1,44 @@ +/* + * NASA Docket No. GSC-18,370-1, and identified as "Operating System Abstraction Layer" + * + * Copyright (c) 2019 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 os-impl-idmap.h + * \ingroup vxworks + * \author joseph.p.hickey@nasa.gov + * + */ + +#ifndef OS_IMPL_IDMAP_H +#define OS_IMPL_IDMAP_H + +#include "osconfig.h" +#include "osapi-idmap.h" +#include + +typedef struct +{ + void *const mem; + SEM_ID vxid; +} OS_impl_objtype_lock_t; + +/* Tables where the lock state information is stored */ +extern OS_impl_objtype_lock_t *const OS_impl_objtype_lock_table[OS_OBJECT_TYPE_USER]; + +#endif /* OS_IMPL_IDMAP_H */ diff --git a/src/os/vxworks/inc/os-vxworks.h b/src/os/vxworks/inc/os-vxworks.h index e497fee88..4d9e1eefd 100644 --- a/src/os/vxworks/inc/os-vxworks.h +++ b/src/os/vxworks/inc/os-vxworks.h @@ -51,30 +51,10 @@ TYPEDEFS ****************************************************************************************/ -typedef struct -{ - void *const mem; - SEM_ID vxid; -} VxWorks_GlobalMutex_t; - -/* - * Union to facilitate passing an osal_id_t through - * a function/api designed to take an "int" - * - * This relies on sizeof(int) >= sizeof(osal_id_t) - */ -typedef union -{ - osal_id_t id; - int arg; -} VxWorks_ID_Buffer_t; - /**************************************************************************************** GLOBAL DATA ****************************************************************************************/ -extern VxWorks_GlobalMutex_t VX_MUTEX_TABLE[]; - /**************************************************************************************** VXWORKS IMPLEMENTATION FUNCTION PROTOTYPES ****************************************************************************************/ diff --git a/src/os/vxworks/src/os-impl-dirs.c b/src/os/vxworks/src/os-impl-dirs.c deleted file mode 100644 index 4f774e216..000000000 --- a/src/os/vxworks/src/os-impl-dirs.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * NASA Docket No. GSC-18,370-1, and identified as "Operating System Abstraction Layer" - * - * Copyright (c) 2019 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 os-impl-dirs.c - * \ingroup vxworks - * \author joseph.p.hickey@nasa.gov - * - */ - -/**************************************************************************************** - INCLUDE FILES -****************************************************************************************/ - -#include "os-vxworks.h" -#include "os-impl-dirs.h" -#include "os-shared-dir.h" -#include "os-shared-idmap.h" - -/*---------------------------------------------------------------- - * - * Function: OS_DirCreate_Impl - * - * Purpose: Implemented per internal OSAL API - * See prototype for argument/return detail - * - *-----------------------------------------------------------------*/ -int32 OS_DirCreate_Impl(const char *local_path, uint32 access) -{ - int32 return_code; - - if (mkdir(local_path) != OK) - { - return_code = OS_ERROR; - } - else - { - return_code = OS_SUCCESS; - } - - return return_code; -} /* end OS_DirCreate_Impl */ - -/*---------------------------------------------------------------- - * - * Function: OS_DirOpen_Impl - * - * Purpose: Implemented per internal OSAL API - * See prototype for argument/return detail - * - *-----------------------------------------------------------------*/ -int32 OS_DirOpen_Impl(const OS_object_token_t *token, const char *local_path) -{ - OS_impl_dir_internal_record_t *impl; - - impl = OS_OBJECT_TABLE_GET(OS_impl_dir_table, *token); - - impl->dp = opendir(local_path); - if (impl->dp == NULL) - { - return OS_ERROR; - } - return OS_SUCCESS; -} /* end OS_DirOpen_Impl */ - -/*---------------------------------------------------------------- - * - * Function: OS_DirClose_Impl - * - * Purpose: Implemented per internal OSAL API - * See prototype for argument/return detail - * - *-----------------------------------------------------------------*/ -int32 OS_DirClose_Impl(const OS_object_token_t *token) -{ - OS_impl_dir_internal_record_t *impl; - - impl = OS_OBJECT_TABLE_GET(OS_impl_dir_table, *token); - - closedir(impl->dp); - impl->dp = NULL; - return OS_SUCCESS; -} /* end OS_DirClose_Impl */ - -/*---------------------------------------------------------------- - * - * Function: OS_DirRead_Impl - * - * Purpose: Implemented per internal OSAL API - * See prototype for argument/return detail - * - *-----------------------------------------------------------------*/ -int32 OS_DirRead_Impl(const OS_object_token_t *token, os_dirent_t *dirent) -{ - struct dirent * de; - OS_impl_dir_internal_record_t *impl; - - impl = OS_OBJECT_TABLE_GET(OS_impl_dir_table, *token); - - /* NOTE - the readdir() call is non-reentrant .... - * However, this is performed while the global dir table lock is taken. - * Therefore this ensures that only one such call can occur at any given time. - * - * Static analysis tools may warn about this because they do not know - * this function is externally serialized via the global lock. - */ - /* cppcheck-suppress readdirCalled */ - /* cppcheck-suppress nonreentrantFunctionsreaddir */ - de = readdir(impl->dp); - if (de == NULL) - { - return OS_ERROR; - } - - strncpy(dirent->FileName, de->d_name, sizeof(dirent->FileName) - 1); - dirent->FileName[sizeof(dirent->FileName) - 1] = 0; - - return OS_SUCCESS; -} /* end OS_DirRead_Impl */ - -/*---------------------------------------------------------------- - * - * Function: OS_DirRewind_Impl - * - * Purpose: Implemented per internal OSAL API - * See prototype for argument/return detail - * - *-----------------------------------------------------------------*/ -int32 OS_DirRewind_Impl(const OS_object_token_t *token) -{ - OS_impl_dir_internal_record_t *impl; - - impl = OS_OBJECT_TABLE_GET(OS_impl_dir_table, *token); - - rewinddir(impl->dp); - return OS_SUCCESS; -} /* end OS_DirRewind_Impl */ - -/*---------------------------------------------------------------- - * - * Function: OS_DirRemove_Impl - * - * Purpose: Implemented per internal OSAL API - * See prototype for argument/return detail - * - *-----------------------------------------------------------------*/ -int32 OS_DirRemove_Impl(const char *local_path) -{ - if (rmdir(local_path) < 0) - { - return OS_ERROR; - } - - return OS_SUCCESS; -} /* end OS_DirRemove_Impl */ diff --git a/src/os/vxworks/src/os-impl-filesys.c b/src/os/vxworks/src/os-impl-filesys.c index 5a7080c6e..5352e8563 100644 --- a/src/os/vxworks/src/os-impl-filesys.c +++ b/src/os/vxworks/src/os-impl-filesys.c @@ -32,6 +32,7 @@ #include "os-vxworks.h" #include "os-impl-filesys.h" +#include "os-impl-dirs.h" #include "os-shared-filesys.h" #include "os-shared-idmap.h" @@ -295,22 +296,62 @@ int32 OS_FileSysMountVolume_Impl(const OS_object_token_t *token) OS_filesys_internal_record_t *local; int32 status; int fd; + struct stat stat_buf; local = OS_OBJECT_TABLE_GET(OS_filesys_table, *token); /* - * Calling open() on the physical device path - * mounts the device. + * For FS-based mounts, these are just a map to a some other + * directory in the filesystem. + * + * If it does exist then make sure it is actually a directory. + * If it does not exist then attempt to create it. */ - fd = open(local->system_mountpt, O_RDONLY, 0644); - if (fd < 0) + if (local->fstype == OS_FILESYS_TYPE_FS_BASED) { - status = OS_ERROR; + if (stat(local->system_mountpt, &stat_buf) == 0) + { + if (S_ISDIR(stat_buf.st_mode)) + { + /* mount point exists */ + status = OS_SUCCESS; + } + else + { + OS_DEBUG("%s is not a directory\n", local->system_mountpt); + status = OS_FS_ERR_PATH_INVALID; + } + } + else + { + if (mkdir(local->system_mountpt, 0775) == 0) + { + /* directory created OK */ + status = OS_SUCCESS; + } + else + { + OS_DEBUG("mkdir(%s): errno=%d\n", local->system_mountpt, errnoGet()); + status = OS_FS_ERR_DRIVE_NOT_CREATED; + } + } } else { - status = OS_SUCCESS; - close(fd); + /* + * For all other (non-FS_BASED) filesystem types, + * Calling open() on the physical device path mounts the device. + */ + fd = open(local->system_mountpt, O_RDONLY, 0644); + if (fd < 0) + { + status = OS_ERROR; + } + else + { + status = OS_SUCCESS; + close(fd); + } } return status; @@ -333,26 +374,34 @@ int32 OS_FileSysUnmountVolume_Impl(const OS_object_token_t *token) local = OS_OBJECT_TABLE_GET(OS_filesys_table, *token); - /* - ** vxWorks uses an ioctl to unmount - */ - fd = open(local->system_mountpt, O_RDONLY, 0644); - if (fd < 0) + if (local->fstype == OS_FILESYS_TYPE_FS_BASED) { - status = OS_ERROR; + /* unmount is a no-op on FS-based mounts - it is just a directory map */ + status = OS_SUCCESS; } else { - if (ioctl(fd, FIOUNMOUNT, 0) < 0) + /* + ** vxWorks uses an ioctl to unmount + */ + fd = open(local->system_mountpt, O_RDONLY, 0644); + if (fd < 0) { status = OS_ERROR; } else { - status = OS_SUCCESS; - } + if (ioctl(fd, FIOUNMOUNT, 0) < 0) + { + status = OS_ERROR; + } + else + { + status = OS_SUCCESS; + } - close(fd); + close(fd); + } } return status; diff --git a/src/os/vxworks/src/os-impl-idmap.c b/src/os/vxworks/src/os-impl-idmap.c index 4ec8d728d..503d8f7f5 100644 --- a/src/os/vxworks/src/os-impl-idmap.c +++ b/src/os/vxworks/src/os-impl-idmap.c @@ -29,12 +29,15 @@ ****************************************************************************************/ #include "os-vxworks.h" +#include "os-impl-idmap.h" #include "os-shared-idmap.h" +#include #include #include #include #include +#include /**************************************************************************************** DEFINES @@ -55,27 +58,72 @@ VX_MUTEX_SEMAPHORE(OS_timebase_table_mut_mem); VX_MUTEX_SEMAPHORE(OS_timecb_table_mut_mem); VX_MUTEX_SEMAPHORE(OS_module_table_mut_mem); VX_MUTEX_SEMAPHORE(OS_filesys_table_mut_mem); -VX_MUTEX_SEMAPHORE(OS_console_mut_mem); - -VxWorks_GlobalMutex_t VX_MUTEX_TABLE[] = { - [OS_OBJECT_TYPE_UNDEFINED] = {NULL}, - [OS_OBJECT_TYPE_OS_TASK] = {.mem = OS_task_table_mut_mem}, - [OS_OBJECT_TYPE_OS_QUEUE] = {.mem = OS_queue_table_mut_mem}, - [OS_OBJECT_TYPE_OS_COUNTSEM] = {.mem = OS_count_sem_table_mut_mem}, - [OS_OBJECT_TYPE_OS_BINSEM] = {.mem = OS_bin_sem_table_mut_mem}, - [OS_OBJECT_TYPE_OS_MUTEX] = {.mem = OS_mutex_table_mut_mem}, - [OS_OBJECT_TYPE_OS_STREAM] = {.mem = OS_stream_table_mut_mem}, - [OS_OBJECT_TYPE_OS_DIR] = {.mem = OS_dir_table_mut_mem}, - [OS_OBJECT_TYPE_OS_TIMEBASE] = {.mem = OS_timebase_table_mut_mem}, - [OS_OBJECT_TYPE_OS_TIMECB] = {.mem = OS_timecb_table_mut_mem}, - [OS_OBJECT_TYPE_OS_MODULE] = {.mem = OS_module_table_mut_mem}, - [OS_OBJECT_TYPE_OS_FILESYS] = {.mem = OS_filesys_table_mut_mem}, - [OS_OBJECT_TYPE_OS_CONSOLE] = {.mem = OS_console_mut_mem}, +VX_MUTEX_SEMAPHORE(OS_console_table_mut_mem); + +static OS_impl_objtype_lock_t OS_task_table_lock = +{ + .mem = OS_task_table_mut_mem +}; +static OS_impl_objtype_lock_t OS_queue_table_lock = +{ + .mem = OS_queue_table_mut_mem +}; +static OS_impl_objtype_lock_t OS_bin_sem_table_lock = +{ + .mem = OS_bin_sem_table_mut_mem +}; +static OS_impl_objtype_lock_t OS_mutex_table_lock = +{ + .mem = OS_mutex_table_mut_mem +}; +static OS_impl_objtype_lock_t OS_count_sem_table_lock = +{ + .mem = OS_count_sem_table_mut_mem +}; +static OS_impl_objtype_lock_t OS_stream_table_lock = +{ + .mem = OS_stream_table_mut_mem +}; +static OS_impl_objtype_lock_t OS_dir_table_lock = +{ + .mem = OS_dir_table_mut_mem +}; +static OS_impl_objtype_lock_t OS_timebase_table_lock = +{ + .mem = OS_timebase_table_mut_mem +}; +static OS_impl_objtype_lock_t OS_timecb_table_lock = +{ + .mem = OS_timecb_table_mut_mem +}; +static OS_impl_objtype_lock_t OS_module_table_lock = +{ + .mem = OS_module_table_mut_mem +}; +static OS_impl_objtype_lock_t OS_filesys_table_lock = +{ + .mem = OS_filesys_table_mut_mem +}; +static OS_impl_objtype_lock_t OS_console_table_lock = +{ + .mem = OS_console_table_mut_mem }; -enum +OS_impl_objtype_lock_t * const OS_impl_objtype_lock_table[OS_OBJECT_TYPE_USER] = { - VX_MUTEX_TABLE_SIZE = (sizeof(VX_MUTEX_TABLE) / sizeof(VX_MUTEX_TABLE[0])) + [OS_OBJECT_TYPE_UNDEFINED] = NULL, + [OS_OBJECT_TYPE_OS_TASK] = &OS_task_table_lock, + [OS_OBJECT_TYPE_OS_QUEUE] = &OS_queue_table_lock, + [OS_OBJECT_TYPE_OS_COUNTSEM] = &OS_count_sem_table_lock, + [OS_OBJECT_TYPE_OS_BINSEM] = &OS_bin_sem_table_lock, + [OS_OBJECT_TYPE_OS_MUTEX] = &OS_mutex_table_lock, + [OS_OBJECT_TYPE_OS_STREAM] = &OS_stream_table_lock, + [OS_OBJECT_TYPE_OS_DIR] = &OS_dir_table_lock, + [OS_OBJECT_TYPE_OS_TIMEBASE] = &OS_timebase_table_lock, + [OS_OBJECT_TYPE_OS_TIMECB] = &OS_timecb_table_lock, + [OS_OBJECT_TYPE_OS_MODULE] = &OS_module_table_lock, + [OS_OBJECT_TYPE_OS_FILESYS] = &OS_filesys_table_lock, + [OS_OBJECT_TYPE_OS_CONSOLE] = &OS_console_table_lock }; /*---------------------------------------------------------------- @@ -86,28 +134,17 @@ enum * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_Lock_Global_Impl(osal_objtype_t idtype) +void OS_Lock_Global_Impl(osal_objtype_t idtype) { - VxWorks_GlobalMutex_t *mut; + OS_impl_objtype_lock_t *impl; - if (idtype >= VX_MUTEX_TABLE_SIZE) - { - return OS_ERROR; - } - - mut = &VX_MUTEX_TABLE[idtype]; - if (mut->vxid == (SEM_ID)0) - { - return OS_ERROR; - } + impl = OS_impl_objtype_lock_table[idtype]; - if (semTake(mut->vxid, WAIT_FOREVER) != OK) + if (semTake(impl->vxid, WAIT_FOREVER) != OK) { OS_DEBUG("semTake() - vxWorks errno %d\n", errno); - return OS_ERROR; } - return OS_SUCCESS; } /* end OS_Lock_Global_Impl */ /*---------------------------------------------------------------- @@ -118,29 +155,45 @@ int32 OS_Lock_Global_Impl(osal_objtype_t idtype) * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_Unlock_Global_Impl(osal_objtype_t idtype) +void OS_Unlock_Global_Impl(osal_objtype_t idtype) { - VxWorks_GlobalMutex_t *mut; + OS_impl_objtype_lock_t *impl; - if (idtype >= VX_MUTEX_TABLE_SIZE) + impl = OS_impl_objtype_lock_table[idtype]; + + if (semGive(impl->vxid) != OK) { - return OS_ERROR; + OS_DEBUG("semGive() - vxWorks errno %d\n", errno); } - mut = &VX_MUTEX_TABLE[idtype]; - if (mut->vxid == (SEM_ID)0) +} /* end OS_Unlock_Global_Impl */ + +/*---------------------------------------------------------------- + * + * Function: OS_WaitForStateChange_Impl + * + * Purpose: Implemented per internal OSAL API + * See prototype for argument/return detail + * + *-----------------------------------------------------------------*/ +void OS_WaitForStateChange_Impl(osal_objtype_t idtype, uint32 attempts) +{ + int wait_ticks; + + if (attempts <= 10) { - return OS_ERROR; + wait_ticks = attempts * attempts; } - - if (semGive(mut->vxid) != OK) + else { - OS_DEBUG("semGive() - vxWorks errno %d\n", errno); - return OS_ERROR; + wait_ticks = 100; } - return OS_SUCCESS; -} /* end OS_Unlock_Global_Impl */ + OS_Unlock_Global_Impl(idtype); + taskDelay(wait_ticks); + OS_Lock_Global_Impl(idtype); +} + /**************************************************************************************** INITIALIZATION FUNCTION @@ -156,24 +209,26 @@ int32 OS_Unlock_Global_Impl(osal_objtype_t idtype) *-----------------------------------------------------------------*/ int32 OS_VxWorks_TableMutex_Init(osal_objtype_t idtype) { - int32 return_code = OS_SUCCESS; + OS_impl_objtype_lock_t *impl; SEM_ID semid; + impl = OS_impl_objtype_lock_table[idtype]; + if (impl == NULL) + { + return OS_SUCCESS; + } + /* Initialize the table mutex for the given idtype */ - if (idtype < VX_MUTEX_TABLE_SIZE && VX_MUTEX_TABLE[idtype].mem != NULL) + semid = semMInitialize(impl->mem, SEM_Q_PRIORITY | SEM_INVERSION_SAFE); + + if (semid == (SEM_ID)0) { - semid = semMInitialize(VX_MUTEX_TABLE[idtype].mem, SEM_Q_PRIORITY | SEM_INVERSION_SAFE); - - if (semid == (SEM_ID)0) - { - OS_DEBUG("Error: semMInitialize() failed - vxWorks errno %d\n", errno); - return_code = OS_ERROR; - } - else - { - VX_MUTEX_TABLE[idtype].vxid = semid; - } + OS_DEBUG("Error: semMInitialize() failed - vxWorks errno %d\n", errno); + return OS_ERROR; } - return (return_code); + impl->vxid = semid; + + return OS_SUCCESS; + } /* end OS_VxWorks_TableMutex_Init */ diff --git a/src/os/vxworks/src/os-impl-tasks.c b/src/os/vxworks/src/os-impl-tasks.c index ecb50db59..060454817 100644 --- a/src/os/vxworks/src/os-impl-tasks.c +++ b/src/os/vxworks/src/os-impl-tasks.c @@ -287,6 +287,20 @@ int32 OS_TaskDelete_Impl(const OS_object_token_t *token) } /* end OS_TaskDelete_Impl */ +/*---------------------------------------------------------------- + * + * Function: OS_TaskDetach_Impl + * + * Purpose: Implemented per internal OSAL API + * See prototype for argument/return detail + * + *-----------------------------------------------------------------*/ +int32 OS_TaskDetach_Impl(const OS_object_token_t *token) +{ + /* No-op on VxWorks */ + return OS_SUCCESS; +} + /*---------------------------------------------------------------- * * Function: OS_TaskExit_Impl @@ -400,16 +414,16 @@ int32 OS_TaskRegister_Impl(osal_id_t global_task_id) *-----------------------------------------------------------------*/ osal_id_t OS_TaskGetId_Impl(void) { - OS_impl_task_internal_record_t *lrec; - size_t idx; - osal_id_t id; + void *lrec; + size_t idx; + osal_id_t id; id = OS_OBJECT_ID_UNDEFINED; - lrec = (OS_impl_task_internal_record_t *)taskTcb(taskIdSelf()); + lrec = taskTcb(taskIdSelf()); if (lrec != NULL) { - idx = lrec - &OS_impl_task_table[0]; + idx = (OS_impl_task_internal_record_t *)lrec - &OS_impl_task_table[0]; if (idx < OS_MAX_TASKS) { id = OS_global_task_table[idx].active_id; diff --git a/src/os/vxworks/src/os-impl-timebase.c b/src/os/vxworks/src/os-impl-timebase.c index bcaf5abce..887bf64b8 100644 --- a/src/os/vxworks/src/os-impl-timebase.c +++ b/src/os/vxworks/src/os-impl-timebase.c @@ -218,8 +218,10 @@ void OS_VxWorks_RegisterTimer(osal_id_t obj_id) OS_object_token_t token; struct sigevent evp; int status; + int32 retcode; - if (OS_ObjectIdGetById(OS_LOCK_MODE_NONE, OS_OBJECT_TYPE_OS_TIMEBASE, obj_id, &token) == OS_SUCCESS) + retcode = OS_ObjectIdGetById(OS_LOCK_MODE_RESERVED, OS_OBJECT_TYPE_OS_TIMEBASE, obj_id, &token); + if (retcode == OS_SUCCESS) { local = OS_OBJECT_TABLE_GET(OS_impl_timebase_table, token); @@ -248,7 +250,13 @@ void OS_VxWorks_RegisterTimer(osal_id_t obj_id) { local->timer_state = OS_TimerRegState_SUCCESS; } + + OS_ObjectIdRelease(&token); } + else + { + OS_DEBUG("OS_VxWorks_RegisterTimer() bad ID, code=%d\n", (int)retcode); + } } /* end OS_VxWorks_RegisterTimer */ /**************************************************************************************** @@ -264,11 +272,11 @@ void OS_VxWorks_RegisterTimer(osal_id_t obj_id) *-----------------------------------------------------------------*/ int OS_VxWorks_TimeBaseTask(int arg) { - VxWorks_ID_Buffer_t id; + osal_id_t obj_id; - id.arg = arg; - OS_VxWorks_RegisterTimer(id.id); - OS_TimeBase_CallbackThread(id.id); + obj_id = OS_ObjectIdFromInteger(arg); + OS_VxWorks_RegisterTimer(obj_id); + OS_TimeBase_CallbackThread(obj_id); return 0; } /* end OS_VxWorks_TimeBaseTask */ @@ -344,7 +352,6 @@ int32 OS_TimeBaseCreate_Impl(const OS_object_token_t *token) sigset_t inuse; osal_index_t idx; uint32 i; - VxWorks_ID_Buffer_t idbuf; return_code = OS_SUCCESS; @@ -379,7 +386,7 @@ int32 OS_TimeBaseCreate_Impl(const OS_object_token_t *token) for (idx = 0; idx < OS_MAX_TIMEBASES; ++idx) { - if (OS_ObjectIdDefined(OS_global_timebase_table[idx].active_id) && + if (OS_ObjectIdIsValid(OS_global_timebase_table[idx].active_id) && OS_impl_timebase_table[idx].assigned_signal > 0) { /* mark signal as in-use */ @@ -453,11 +460,11 @@ int32 OS_TimeBaseCreate_Impl(const OS_object_token_t *token) */ if (return_code == OS_SUCCESS) { - idbuf.id = OS_ObjectIdFromToken(token); local->handler_task = taskSpawn(timebase->timebase_name, OSAL_TIMEBASE_TASK_PRIORITY, /* priority */ OSAL_TIMEBASE_TASK_OPTION_WORD, /* task option word */ - OSAL_TIMEBASE_TASK_STACK_SIZE, /* size (bytes) of stack needed */ - (FUNCPTR)OS_VxWorks_TimeBaseTask, idbuf.arg, /* 1st arg is ID */ + OSAL_TIMEBASE_TASK_STACK_SIZE, /* size (bytes) of stack needed */ + (FUNCPTR)OS_VxWorks_TimeBaseTask, /* Timebase helper task entry point */ + OS_ObjectIdToInteger(OS_ObjectIdFromToken(token)), /* 1st arg is ID */ 0, 0, 0, 0, 0, 0, 0, 0, 0); /* check if taskSpawn failed */ diff --git a/src/tests/file-api-test/file-api-test.c b/src/tests/file-api-test/file-api-test.c index 1fc6b84a5..2ff84524f 100644 --- a/src/tests/file-api-test/file-api-test.c +++ b/src/tests/file-api-test/file-api-test.c @@ -424,18 +424,19 @@ void TestReadWriteLseek(void) ---------------------------------------------------------------------------------------*/ void TestMkRmDirFreeBytes(void) { - int32 status; - char filename1[OS_MAX_PATH_LEN]; - char filename2[OS_MAX_PATH_LEN]; - char dir1[OS_MAX_PATH_LEN]; - char dir2[OS_MAX_PATH_LEN]; - char buffer1[OS_MAX_PATH_LEN]; - char buffer2[OS_MAX_PATH_LEN]; - char copybuffer1[OS_MAX_PATH_LEN]; - char copybuffer2[OS_MAX_PATH_LEN]; - osal_id_t fd1; - osal_id_t fd2; - size_t size; + int32 status; + char filename1[OS_MAX_PATH_LEN]; + char filename2[OS_MAX_PATH_LEN]; + char dir1[OS_MAX_PATH_LEN]; + char dir2[OS_MAX_PATH_LEN]; + char buffer1[OS_MAX_PATH_LEN]; + char buffer2[OS_MAX_PATH_LEN]; + char copybuffer1[OS_MAX_PATH_LEN]; + char copybuffer2[OS_MAX_PATH_LEN]; + osal_id_t fd1; + osal_id_t fd2; + size_t size; + OS_statvfs_t statbuf; /* make the directory names for testing, as well as the filenames and the buffers * to put in the files */ @@ -450,8 +451,9 @@ void TestMkRmDirFreeBytes(void) /* NOTE: The blocks free call is not necessarily implemented on all filesystems. * So the response of OS_ERR_NOT_IMPLEMENTED is acceptable. */ - status = OS_fsBlocksFree("/drive0"); - UtAssert_True(status == OS_ERR_NOT_IMPLEMENTED || status >= OS_SUCCESS, "Checking Free Blocks: %d", (int)status); + status = OS_FileSysStatVolume("/drive0", &statbuf); + UtAssert_True(status == OS_ERR_NOT_IMPLEMENTED || status == OS_SUCCESS, "Checking Free Blocks: status=%d blocks=%lu", + (int)status, (unsigned long)statbuf.blocks_free); /* make the two directories */ status = OS_mkdir(dir1, 0); @@ -486,8 +488,9 @@ void TestMkRmDirFreeBytes(void) memset(buffer1, 0, sizeof(buffer1)); memset(buffer2, 0, sizeof(buffer2)); - status = OS_fsBlocksFree("/drive0"); - UtAssert_True(status == OS_ERR_NOT_IMPLEMENTED || status >= OS_SUCCESS, "Checking Free Blocks: %d", (int)status); + status = OS_FileSysStatVolume("/drive0", &statbuf); + UtAssert_True(status == OS_ERR_NOT_IMPLEMENTED || status == OS_SUCCESS, "Checking Free Blocks: status=%d blocks=%lu", + (int)status, (unsigned long)statbuf.blocks_free); /* read back out of the files what we wrote into them */ size = strlen(copybuffer1); @@ -526,8 +529,9 @@ void TestMkRmDirFreeBytes(void) status = OS_rmdir(dir2); UtAssert_True(status == OS_SUCCESS, "status after rmdir 2 = %d", (int)status); - status = OS_fsBlocksFree("/drive0"); - UtAssert_True(status == OS_ERR_NOT_IMPLEMENTED || status >= OS_SUCCESS, "Checking Free Blocks: %d", (int)status); + status = OS_FileSysStatVolume("/drive0", &statbuf); + UtAssert_True(status == OS_ERR_NOT_IMPLEMENTED || status == OS_SUCCESS, "Checking Free Blocks: status=%d blocks=%lu", + (int)status, (unsigned long)statbuf.blocks_free); } /*--------------------------------------------------------------------------------------- diff --git a/src/tests/osal-core-test/osal-core-test.c b/src/tests/osal-core-test/osal-core-test.c index 70f4dbb50..bef1e07d4 100644 --- a/src/tests/osal-core-test/osal-core-test.c +++ b/src/tests/osal-core-test/osal-core-test.c @@ -714,7 +714,7 @@ void TestGenericQueries(void) UtAssert_StrCmp(ResourceName, "q 0", "Output value correct"); status = OS_GetResourceName(OS_OBJECT_ID_UNDEFINED, ResourceName, sizeof(ResourceName)); - UtAssert_True(status == OS_ERR_INVALID_ID, "OS_GetResourceName (%lx,%ld) == OS_ERR_INVALID_ID", + UtAssert_True(status == OS_ERR_INCORRECT_OBJ_TYPE, "OS_GetResourceName (%lx,%ld) == OS_ERR_INCORRECT_OBJ_TYPE", OS_ObjectIdToInteger(OS_OBJECT_ID_UNDEFINED), (long)status); status = OS_GetResourceName(bin_0, ResourceName, OSAL_SIZE_C(1)); diff --git a/src/tests/select-test/select-test.c b/src/tests/select-test/select-test.c index bcdef177a..7f4d97048 100644 --- a/src/tests/select-test/select-test.c +++ b/src/tests/select-test/select-test.c @@ -49,7 +49,6 @@ OS_SockAddr_t s2_addr; OS_SockAddr_t c_addr; OS_SockAddr_t c2_addr; osal_id_t bin_sem_id; -osal_id_t bin_sem_id2; /* *************************************** MAIN ************************************** */ @@ -67,24 +66,16 @@ void BinSemSetup(void) { uint32 status; OS_bin_sem_prop_t bin_sem_prop; - OS_bin_sem_prop_t bin_sem_prop2; /* * Create the binary semaphore * BinSem1 is used to control when the server can accept connections - * BinSem2 is used to make sure all sub task finish before the main task does. */ status = OS_BinSemCreate(&bin_sem_id, "BinSem1", 0, 0); UtAssert_True(status == OS_SUCCESS, "BinSem1 create Id=%lx Rc=%d", OS_ObjectIdToInteger(bin_sem_id), (int)status); status = OS_BinSemGetInfo(bin_sem_id, &bin_sem_prop); UtAssert_True(status == OS_SUCCESS, "BinSem1 value=%d Rc=%d", (int)bin_sem_prop.value, (int)status); - - status = OS_BinSemCreate(&bin_sem_id2, "BinSem2", 0, 0); - UtAssert_True(status == OS_SUCCESS, "BinSem2 create Id=%lx Rc=%d", OS_ObjectIdToInteger(bin_sem_id2), (int)status); - - status = OS_BinSemGetInfo(bin_sem_id2, &bin_sem_prop2); - UtAssert_True(status == OS_SUCCESS, "BinSem2 value=%d Rc=%d", (int)bin_sem_prop2.value, (int)status); } void Setup_Server(void) @@ -167,9 +158,6 @@ void Server_Fn(void) status = OS_close(connsock_id); UtAssert_True(status == OS_SUCCESS, "status after close connsock_id = %d", (int)status); - - status = OS_BinSemGive(bin_sem_id2); - UtAssert_True(status == OS_SUCCESS, "BinSem2 Server 1 give Rc=%d", (int)status); } /* end Server_Fn */ void Setup_Server2(void) @@ -267,24 +255,17 @@ void Setup_Multi(void) void Teardown_Single(void) { - uint32 status; - - OS_close(c_socket_id); - status = OS_BinSemTake(bin_sem_id2); - UtAssert_True(status == OS_SUCCESS, "BinSem2 Teardown single take Rc=%d", (int)status); - - OS_BinSemDelete(bin_sem_id); - OS_BinSemDelete(bin_sem_id2); + OS_close(c_socket_id); + OS_BinSemDelete(bin_sem_id); } void Teardown_Multi(void) -{ - uint32 status; - - status = OS_BinSemGive(bin_sem_id); - UtAssert_True(status == OS_SUCCESS, "BinSem1 Teardown multi give Rc=%d", (int)status); +{ + //Server 1 is intentionaly left waiting so we close it out here. + OS_close(s_socket_id); + OS_TaskDelete(s_task_id); - OS_close(c2_socket_id); + OS_close(c2_socket_id); Teardown_Single(); } @@ -303,7 +284,7 @@ void TestSelectSingleRead(void) */ /* Create a server task/thread */ - int32 status = OS_TaskCreate(&s_task_id, "Server", Server_Fn, OSAL_TASK_STACK_ALLOCATE, OSAL_SIZE_C(16384), + int32 status = OS_TaskCreate(&s_task_id, "ServerSingleRead", Server_Fn, OSAL_TASK_STACK_ALLOCATE, OSAL_SIZE_C(16384), OSAL_PRIORITY_C(50), 0); UtAssert_True(status == OS_SUCCESS, "OS_TaskCreate() (%ld) == OS_SUCCESS", (long)status); @@ -353,7 +334,7 @@ void TestSelectMultipleRead(void) */ /* Create a server task/thread */ - status = OS_TaskCreate(&s_task_id, "Server", Server_Fn, OSAL_TASK_STACK_ALLOCATE, OSAL_SIZE_C(16384), + status = OS_TaskCreate(&s_task_id, "ServerMultiRead", Server_Fn, OSAL_TASK_STACK_ALLOCATE, OSAL_SIZE_C(16384), OSAL_PRIORITY_C(50), 0); UtAssert_True(status == OS_SUCCESS, "OS_TaskCreate() (%ld) == OS_SUCCESS", (long)status); @@ -361,7 +342,7 @@ void TestSelectMultipleRead(void) actual = OS_SocketConnect(c_socket_id, &s_addr, 10); UtAssert_True(actual == expected, "OS_SocketConnect() (%ld) == OS_SUCCESS", (long)actual); - status = OS_TaskCreate(&s2_task_id, "Server2", Server_Fn2, OSAL_TASK_STACK_ALLOCATE, OSAL_SIZE_C(16384), + status = OS_TaskCreate(&s2_task_id, "ServerMultiRead2", Server_Fn2, OSAL_TASK_STACK_ALLOCATE, OSAL_SIZE_C(16384), OSAL_PRIORITY_C(50), 0); UtAssert_True(status == OS_SUCCESS, "OS_TaskCreate() (%ld) == OS_SUCCESS", (long)status); @@ -402,7 +383,7 @@ void TestSelectSingleWrite(void) */ /* Create a server task/thread */ - int32 status = OS_TaskCreate(&s_task_id, "Server", Server_Fn, OSAL_TASK_STACK_ALLOCATE, OSAL_SIZE_C(16384), + int32 status = OS_TaskCreate(&s_task_id, "ServerSingleWrite", Server_Fn, OSAL_TASK_STACK_ALLOCATE, OSAL_SIZE_C(16384), OSAL_PRIORITY_C(50), 0); UtAssert_True(status == OS_SUCCESS, "OS_TaskCreate() (%ld) == OS_SUCCESS", (long)status); @@ -470,7 +451,7 @@ void TestSelectMultipleWrite(void) */ /* Create a server task/thread */ - status = OS_TaskCreate(&s_task_id, "Server", Server_Fn, OSAL_TASK_STACK_ALLOCATE, OSAL_SIZE_C(16384), + status = OS_TaskCreate(&s_task_id, "ServerMultiWrite", Server_Fn, OSAL_TASK_STACK_ALLOCATE, OSAL_SIZE_C(16384), OSAL_PRIORITY_C(50), 0); UtAssert_True(status == OS_SUCCESS, "OS_TaskCreate() (%ld) == OS_SUCCESS", (long)status); @@ -478,7 +459,7 @@ void TestSelectMultipleWrite(void) actual = OS_SocketConnect(c_socket_id, &s_addr, 10); UtAssert_True(actual == expected, "OS_SocketConnect() (%ld) == OS_SUCCESS", (long)actual); - status = OS_TaskCreate(&s2_task_id, "Server2", Server_Fn2, OSAL_TASK_STACK_ALLOCATE, OSAL_SIZE_C(16384), + status = OS_TaskCreate(&s2_task_id, "ServerMultiWrite2", Server_Fn2, OSAL_TASK_STACK_ALLOCATE, OSAL_SIZE_C(16384), OSAL_PRIORITY_C(50), 0); UtAssert_True(status == OS_SUCCESS, "OS_TaskCreate() (%ld) == OS_SUCCESS", (long)status); 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 2ec048fd4..5ff9541b4 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 @@ -130,7 +130,7 @@ void TestTimerAddApi(void) OS_GetLocalTime(&EndTime); - for (i = NUMBER_OF_TIMERS-1; i >= 0; --i) + for (i = NUMBER_OF_TIMERS - 1; i >= 0; --i) { TimerStatus[i] = OS_TimerDelete(TimerID[i]); } @@ -144,15 +144,7 @@ void TestTimerAddApi(void) /* * Time limited test */ - microsecs = 1000000 * (EndTime.seconds - StartTime.seconds); - if (EndTime.microsecs < StartTime.microsecs) - { - microsecs -= StartTime.microsecs - EndTime.microsecs; - } - else - { - microsecs += EndTime.microsecs - StartTime.microsecs; - } + microsecs = OS_TimeGetTotalMicroseconds(OS_TimeSubtract(EndTime, StartTime)); /* Make sure the ratio of the timers are OK */ for (i = 0; i < NUMBER_OF_TIMERS; i++) diff --git a/src/tests/timer-test/timer-test.c b/src/tests/timer-test/timer-test.c index 4d86367d1..79ed1a43c 100644 --- a/src/tests/timer-test/timer-test.c +++ b/src/tests/timer-test/timer-test.c @@ -189,15 +189,7 @@ void TimerTestCheck(void) /* * Time limited test - check and exit */ - microsecs = 1000000 * (EndTime.seconds - StartTime.seconds); - if (EndTime.microsecs < StartTime.microsecs) - { - microsecs -= StartTime.microsecs - EndTime.microsecs; - } - else - { - microsecs += EndTime.microsecs - StartTime.microsecs; - } + microsecs = OS_TimeGetTotalMicroseconds(OS_TimeSubtract(EndTime, StartTime)); /* Make sure the ratio of the timers are OK */ for (i = 0; i < NUMBER_OF_TIMERS && i < OS_MAX_TIMERS; i++) diff --git a/src/unit-test-coverage/vxworks/src/coveragetest-dirs.c b/src/unit-test-coverage/portable/src/coveragetest-posix-dirs.c similarity index 72% rename from src/unit-test-coverage/vxworks/src/coveragetest-dirs.c rename to src/unit-test-coverage/portable/src/coveragetest-posix-dirs.c index 9fc7c3f4f..371e3b254 100644 --- a/src/unit-test-coverage/vxworks/src/coveragetest-dirs.c +++ b/src/unit-test-coverage/portable/src/coveragetest-posix-dirs.c @@ -19,19 +19,17 @@ */ /** - * \file coveragetest-dirs.c - * \ingroup vxworks + * \file coveragetest-posix-dirs.c * \author joseph.p.hickey@nasa.gov * */ -#include "os-vxworks-coveragetest.h" -#include "ut-adaptor-dirs.h" +#include "os-portable-coveragetest.h" #include "os-shared-dir.h" +#include "os-shared-idmap.h" #include -#include #include #include #include @@ -42,10 +40,10 @@ void Test_OS_DirCreate_Impl(void) * Test Case For: * int32 OS_DirCreate_Impl(const char *local_path, uint32 access) */ - OSAPI_TEST_FUNCTION_RC(OS_DirCreate_Impl("dir", 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_DirCreate_Impl, ("dir", 0), OS_SUCCESS); UT_SetDefaultReturnValue(UT_KEY(OCS_mkdir), -1); - OSAPI_TEST_FUNCTION_RC(OS_DirCreate_Impl("dir", 0), OS_ERROR); + OSAPI_TEST_FUNCTION_RC(OS_DirCreate_Impl, ("dir", 0), OS_ERROR); } void Test_OS_DirOpen_Impl(void) @@ -54,11 +52,13 @@ void Test_OS_DirOpen_Impl(void) * Test Case For: * int32 OS_DirOpen_Impl(uint32 local_id, const char *local_path) */ - OS_object_token_t token = UT_TOKEN_0; + OS_object_token_t token; - OSAPI_TEST_FUNCTION_RC(OS_DirOpen_Impl(&token, "dir"), OS_SUCCESS); + memset(&token, 0, sizeof(token)); + + OSAPI_TEST_FUNCTION_RC(OS_DirOpen_Impl, (&token, "dir"), OS_SUCCESS); UT_SetDefaultReturnValue(UT_KEY(OCS_opendir), -1); - OSAPI_TEST_FUNCTION_RC(OS_DirOpen_Impl(&token, "dir"), OS_ERROR); + OSAPI_TEST_FUNCTION_RC(OS_DirOpen_Impl, (&token, "dir"), OS_ERROR); } void Test_OS_DirClose_Impl(void) @@ -67,9 +67,11 @@ void Test_OS_DirClose_Impl(void) * Test Case For: * int32 OS_DirClose_Impl(uint32 local_id) */ - OS_object_token_t token = UT_TOKEN_0; + OS_object_token_t token; + + memset(&token, 0, sizeof(token)); - OSAPI_TEST_FUNCTION_RC(OS_DirClose_Impl(&token), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_DirClose_Impl, (&token), OS_SUCCESS); } void Test_OS_DirRead_Impl(void) @@ -79,12 +81,14 @@ void Test_OS_DirRead_Impl(void) * int32 OS_DirRead_Impl(uint32 local_id, os_dirent_t *dirent) */ os_dirent_t dirent_buff; - OS_object_token_t token = UT_TOKEN_0; + OS_object_token_t token; - OSAPI_TEST_FUNCTION_RC(OS_DirRead_Impl(&token, &dirent_buff), OS_SUCCESS); + memset(&token, 0, sizeof(token)); + + OSAPI_TEST_FUNCTION_RC(OS_DirRead_Impl, (&token, &dirent_buff), OS_SUCCESS); UT_SetDefaultReturnValue(UT_KEY(OCS_readdir), -1); - OSAPI_TEST_FUNCTION_RC(OS_DirRead_Impl(&token, &dirent_buff), OS_ERROR); + OSAPI_TEST_FUNCTION_RC(OS_DirRead_Impl, (&token, &dirent_buff), OS_ERROR); } void Test_OS_DirRewind_Impl(void) @@ -93,9 +97,11 @@ void Test_OS_DirRewind_Impl(void) * Test Case For: * int32 OS_DirRewind_Impl(uint32 local_id) */ - OS_object_token_t token = UT_TOKEN_0; + OS_object_token_t token; + + memset(&token, 0, sizeof(token)); - OSAPI_TEST_FUNCTION_RC(OS_DirRewind_Impl(&token), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_DirRewind_Impl, (&token), OS_SUCCESS); } void Test_OS_DirRemove_Impl(void) @@ -104,10 +110,10 @@ void Test_OS_DirRemove_Impl(void) * Test Case For: * int32 OS_DirRemove_Impl(const char *local_path) */ - OSAPI_TEST_FUNCTION_RC(OS_DirRemove_Impl("dir"), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_DirRemove_Impl, ("dir"), OS_SUCCESS); UT_SetDefaultReturnValue(UT_KEY(OCS_rmdir), -1); - OSAPI_TEST_FUNCTION_RC(OS_DirRemove_Impl("dir"), OS_ERROR); + OSAPI_TEST_FUNCTION_RC(OS_DirRemove_Impl, ("dir"), OS_ERROR); } /* ------------------- End of test cases --------------------------------------*/ diff --git a/src/unit-test-coverage/portable/src/coveragetest-posix-files.c b/src/unit-test-coverage/portable/src/coveragetest-posix-files.c index f6bb0788e..51ef4581e 100644 --- a/src/unit-test-coverage/portable/src/coveragetest-posix-files.c +++ b/src/unit-test-coverage/portable/src/coveragetest-posix-files.c @@ -35,6 +35,7 @@ #include #include #include +#include void Test_OS_FileOpen_Impl(void) { @@ -81,6 +82,9 @@ void Test_OS_FileStat_Impl(void) RefStat.st_mode = ~((OCS_mode_t)0); RefStat.st_size = 1234; RefStat.st_mtime = 5678; + /* Also set the full resolution timespec */ + RefStat.st_mtim.tv_sec = 5678; + RefStat.st_mtim.tv_nsec = 3456; UT_SetDataBuffer(UT_KEY(OCS_stat), &RefStat, sizeof(RefStat), false); OSAPI_TEST_FUNCTION_RC(OS_FileStat_Impl, ("local", &FileStats), OS_SUCCESS); @@ -90,7 +94,7 @@ void Test_OS_FileStat_Impl(void) UtAssert_True(OS_FILESTAT_READ(FileStats), "File Read Bit set"); UtAssert_True(OS_FILESTAT_ISDIR(FileStats), "Directory Bit set"); UtAssert_True(OS_FILESTAT_SIZE(FileStats) == 1234, "Size match"); - UtAssert_True(OS_FILESTAT_TIME(FileStats) == 5678, "Time match"); + UtAssert_True(OS_FILESTAT_TIME(FileStats) == 5678, "Time match (seconds)"); } void Test_OS_FileChmod_Impl(void) @@ -114,6 +118,10 @@ void Test_OS_FileChmod_Impl(void) /* failure mode 2 (fchmod) */ UT_SetDefaultReturnValue(UT_KEY(OCS_fchmod), -1); OSAPI_TEST_FUNCTION_RC(OS_FileChmod_Impl, ("local", OS_READ_WRITE), OS_ERROR); + + /* non implemented error, e.g. such as DOS Filesystem with no perms */ + OCS_errno = OCS_ENOTSUP; + OSAPI_TEST_FUNCTION_RC(OS_FileChmod_Impl, ("local", OS_READ_WRITE), OS_ERR_NOT_IMPLEMENTED); UT_ClearForceFail(UT_KEY(OCS_fchmod)); /* all permission bits with uid/gid match */ @@ -122,6 +130,9 @@ void Test_OS_FileChmod_Impl(void) RefStat.st_mode = ~((OCS_mode_t)0); RefStat.st_size = 1234; RefStat.st_mtime = 5678; + /* Also set the full resolution timespec */ + RefStat.st_mtim.tv_sec = 5678; + RefStat.st_mtim.tv_nsec = 3456; UT_SetDataBuffer(UT_KEY(OCS_fstat), &RefStat, sizeof(RefStat), false); /* nominal 1 - full permissions with file owned by own uid/gid */ diff --git a/src/unit-test-coverage/portable/src/coveragetest-posix-gettime.c b/src/unit-test-coverage/portable/src/coveragetest-posix-gettime.c index 8dc31a951..e69cb830a 100644 --- a/src/unit-test-coverage/portable/src/coveragetest-posix-gettime.c +++ b/src/unit-test-coverage/portable/src/coveragetest-posix-gettime.c @@ -35,9 +35,8 @@ void Test_OS_GetLocalTime_Impl(void) * Test Case For: * int32 OS_GetLocalTime_Impl(OS_time_t *time_struct) */ - OS_time_t timeval; - timeval.seconds = 1; - timeval.microsecs = 1; + OS_time_t timeval = {0}; + OSAPI_TEST_FUNCTION_RC(OS_GetLocalTime_Impl, (&timeval), OS_SUCCESS); UT_SetDefaultReturnValue(UT_KEY(OCS_clock_gettime), -1); @@ -50,9 +49,8 @@ void Test_OS_SetLocalTime_Impl(void) * Test Case For: * int32 OS_SetLocalTime_Impl(const OS_time_t *time_struct) */ - OS_time_t timeval; - timeval.seconds = 1; - timeval.microsecs = 1; + OS_time_t timeval = {0}; + OSAPI_TEST_FUNCTION_RC(OS_SetLocalTime_Impl, (&timeval), OS_SUCCESS); UT_SetDefaultReturnValue(UT_KEY(OCS_clock_settime), -1); diff --git a/src/unit-test-coverage/shared/src/coveragetest-clock.c b/src/unit-test-coverage/shared/src/coveragetest-clock.c index 1e7b9b538..20959c987 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-clock.c +++ b/src/unit-test-coverage/shared/src/coveragetest-clock.c @@ -61,6 +61,107 @@ void Test_OS_SetLocalTime(void) UtAssert_True(actual == expected, "OS_SetLocalTime() (%ld) == OS_INVALID_POINTER", (long)actual); } +void Test_OS_TimeAccessConversions(void) +{ + /* + * Test cases for the various time access and conversion functions: + * + * int64 OS_TimeGetTotalSeconds(OS_time_t tm) + * int64 OS_TimeGetTotalMilliseconds(OS_time_t tm) + * int64 OS_TimeGetTotalMicroseconds(OS_time_t tm) + * int64 OS_TimeGetTotalNanoseconds(OS_time_t tm) + * + * uint32 OS_TimeGetSubsecondsPart(OS_time_t tm) + * uint32 OS_TimeGetMillisecondsPart(OS_time_t tm) + * uint32 OS_TimeGetMicrosecondsPart(OS_time_t tm) + * uint32 OS_TimeGetNanosecondsPart(OS_time_t tm) + * + * OS_time_t OS_TimeAssembleFromMilliseconds(int64 seconds, uint32 milliseconds) + * OS_time_t OS_TimeAssembleFromMicroseconds(int64 seconds, uint32 microseconds) + * OS_time_t OS_TimeAssembleFromNanoseconds(int64 seconds, uint32 nanoseconds) + * OS_time_t OS_TimeAssembleFromSubseconds(int64 seconds, uint32 subseconds) + * + * OS_time_t OS_TimeAdd(OS_time_t time1, OS_time_t time2) + * OS_time_t OS_TimeSubtract(OS_time_t time1, OS_time_t time2) + */ + OS_time_t t1; + OS_time_t t2; + OS_time_t t3; + OS_time_t t4; + + /* To base-2 32-bit fixed point: 0.234567890 s * 0x100000000 ~= 0x3c0ca428 */ + t1 = OS_TimeAssembleFromNanoseconds(1,234567890); + + /* From base-2 32-bit fixed point: 0x87654321 / 0x100000000 ~= 0.528888888 s */ + t2 = OS_TimeAssembleFromSubseconds(2,0x87654321); + + /* To base-2 32-bit fixed point: 0.045678 s * 0x100000000 ~= 0x0bb18dad */ + t3 = OS_TimeAssembleFromMicroseconds(0,45678); + + /* To base-2 32-bit fixed point: 0.901 s * 0x100000000 ~= 0xe6a7ef9e */ + t4 = OS_TimeAssembleFromMilliseconds(1,901); + + /* These functions only return the total (whole + fraction) in the requested units */ + UtAssert_UINT32_EQ(OS_TimeGetTotalSeconds(t1), 1); + UtAssert_UINT32_EQ(OS_TimeGetTotalSeconds(t2), 2); + UtAssert_UINT32_EQ(OS_TimeGetTotalSeconds(t3), 0); + UtAssert_UINT32_EQ(OS_TimeGetTotalSeconds(t4), 1); + + UtAssert_UINT32_EQ(OS_TimeGetTotalMilliseconds(t1), 1234); + UtAssert_UINT32_EQ(OS_TimeGetTotalMilliseconds(t2), 2528); + UtAssert_UINT32_EQ(OS_TimeGetTotalMilliseconds(t3), 45); + UtAssert_UINT32_EQ(OS_TimeGetTotalMilliseconds(t4), 1901); + + UtAssert_UINT32_EQ(OS_TimeGetTotalMicroseconds(t1), 1234567); + UtAssert_UINT32_EQ(OS_TimeGetTotalMicroseconds(t2), 2528888); + UtAssert_UINT32_EQ(OS_TimeGetTotalMicroseconds(t3), 45678); + UtAssert_UINT32_EQ(OS_TimeGetTotalMicroseconds(t4), 1901000); + + /* Note: Nanoseconds/Subseconds may not be exact due to limitations of OS_time_t resolution */ + UtAssert_UINT32_EQ(OS_TimeGetTotalNanoseconds(t1), 1234567000); + UtAssert_UINT32_EQ(OS_TimeGetTotalNanoseconds(t2), 2528888000); + UtAssert_UINT32_EQ(OS_TimeGetTotalNanoseconds(t3), 45678000); + UtAssert_UINT32_EQ(OS_TimeGetTotalNanoseconds(t4), 1901000000); + + /* These functions only return the fractional part, not the whole part */ + UtAssert_UINT32_EQ(OS_TimeGetSubsecondsPart(t1), 0x3c0c953a); + UtAssert_UINT32_EQ(OS_TimeGetSubsecondsPart(t2), 0x87653438); + UtAssert_UINT32_EQ(OS_TimeGetSubsecondsPart(t3), 0x0bb18dad); + UtAssert_UINT32_EQ(OS_TimeGetSubsecondsPart(t4), 0xe6a7ef9e); + + UtAssert_UINT32_EQ(OS_TimeGetMillisecondsPart(t1), 234); + UtAssert_UINT32_EQ(OS_TimeGetMillisecondsPart(t2), 528); + UtAssert_UINT32_EQ(OS_TimeGetMillisecondsPart(t3), 45); + UtAssert_UINT32_EQ(OS_TimeGetMillisecondsPart(t4), 901); + + UtAssert_UINT32_EQ(OS_TimeGetMicrosecondsPart(t1), 234567); + UtAssert_UINT32_EQ(OS_TimeGetMicrosecondsPart(t2), 528888); + UtAssert_UINT32_EQ(OS_TimeGetMicrosecondsPart(t3), 45678); + UtAssert_UINT32_EQ(OS_TimeGetMicrosecondsPart(t4), 901000); + + UtAssert_UINT32_EQ(OS_TimeGetNanosecondsPart(t1), 234567000); + UtAssert_UINT32_EQ(OS_TimeGetNanosecondsPart(t2), 528888000); + UtAssert_UINT32_EQ(OS_TimeGetNanosecondsPart(t3), 45678000); + UtAssert_UINT32_EQ(OS_TimeGetNanosecondsPart(t4), 901000000); + + /* Simple Add/Subtract */ + t3 = OS_TimeAdd(t1, t2); + UtAssert_UINT32_EQ(OS_TimeGetTotalMilliseconds(t3), 3763); + t4 = OS_TimeSubtract(t3, t2); + UtAssert_UINT32_EQ(OS_TimeGetTotalMilliseconds(t4), 1234); + + /* Add/Subtract that will require carry */ + t1 = OS_TimeAssembleFromNanoseconds(3,777777777); + t2 = OS_TimeAssembleFromNanoseconds(4,888888888); + + t3 = OS_TimeAdd(t1, t2); + UtAssert_UINT32_EQ(OS_TimeGetTotalMilliseconds(t3), 8666); + t4 = OS_TimeSubtract(t3, t2); + UtAssert_UINT32_EQ(OS_TimeGetTotalMilliseconds(t4), 3777); +} + + + /* Osapi_Test_Setup * * Purpose: @@ -86,4 +187,5 @@ void UtTest_Setup(void) { ADD_TEST(OS_GetLocalTime); ADD_TEST(OS_SetLocalTime); + ADD_TEST(OS_TimeAccessConversions); } diff --git a/src/unit-test-coverage/shared/src/coveragetest-filesys.c b/src/unit-test-coverage/shared/src/coveragetest-filesys.c index eb744b0f3..6d3c7191b 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-filesys.c +++ b/src/unit-test-coverage/shared/src/coveragetest-filesys.c @@ -328,6 +328,57 @@ void Test_OS_fsBytesFree(void) UtAssert_True(actual == expected, "OS_fsBytesFree() (%ld) == OS_FS_ERR_PATH_INVALID", (long)actual); } +void Test_OS_FileSysStatVolume(void) +{ + /* + * Test Case For: + * int32 OS_FileSysStatVolume(const char *name, OS_statvfs_t *statbuf) + */ + + OS_statvfs_t statbuf; + OS_statvfs_t statref; + int32 expected; + int32 actual; + + statref.block_size = OSAL_SIZE_C(1024); + statref.blocks_free = OSAL_BLOCKCOUNT_C(1111); + statref.total_blocks = OSAL_BLOCKCOUNT_C(2222); + UT_SetDataBuffer(UT_KEY(OS_FileSysStatVolume_Impl), &statref, sizeof(statref), false); + OS_filesys_table[1].flags = OS_FILESYS_FLAG_IS_READY | OS_FILESYS_FLAG_IS_MOUNTED_SYSTEM | + OS_FILESYS_FLAG_IS_MOUNTED_VIRTUAL; + + expected = OS_SUCCESS; + actual = OS_FileSysStatVolume("/cf", &statbuf); + UtAssert_True(actual == expected, "OS_FileSysStatVolume() (%ld) == OS_SUCCESS", (long)actual); + + UtAssert_True(statbuf.block_size == statref.block_size, "blocks_size (%lu) == %lu", (unsigned long)statbuf.block_size, + (unsigned long)statref.block_size); + UtAssert_True(statbuf.total_blocks == statref.total_blocks, "total_blocks (%lu) == %lu", + (unsigned long)statbuf.total_blocks, (unsigned long)statref.total_blocks); + UtAssert_True(statbuf.blocks_free == statref.blocks_free, "blocks_free (%lu) == %lu", (unsigned long)statbuf.blocks_free, + (unsigned long)statref.blocks_free); + + /* validate error checking */ + expected = OS_INVALID_POINTER; + actual = OS_FileSysStatVolume(NULL, &statbuf); + UtAssert_True(actual == expected, "OS_FileSysStatVolume() (%ld) == OS_INVALID_POINTER", (long)actual); + actual = OS_FileSysStatVolume("/cf", NULL); + UtAssert_True(actual == expected, "OS_FileSysStatVolume() (%ld) == OS_INVALID_POINTER", (long)actual); + + /* Test Fail due to no matching VolTab entry */ + UT_SetDefaultReturnValue(UT_KEY(OS_ObjectIdGetBySearch), OS_ERR_NAME_NOT_FOUND); + expected = OS_ERR_NAME_NOT_FOUND; + actual = OS_FileSysStatVolume("/cf", &statbuf); + UtAssert_True(actual == expected, "OS_FileSysStatVolume() (%ld) == OS_ERR_NAME_NOT_FOUND", (long)actual); + UT_ResetState(UT_KEY(OS_ObjectIdGetBySearch)); + + /* Verify pass through of impl error */ + UT_SetDefaultReturnValue(UT_KEY(OS_FileSysStatVolume_Impl), OS_ERR_OPERATION_NOT_SUPPORTED); + expected = OS_ERR_OPERATION_NOT_SUPPORTED; + actual = OS_FileSysStatVolume("/cf", &statbuf); + UtAssert_True(actual == expected, "OS_FileSysStatVolume() (%ld) == OS_ERR_OPERATION_NOT_SUPPORTED", (long)actual); +} + void Test_OS_chkfs(void) { /* @@ -404,6 +455,10 @@ void Test_OS_GetFsInfo(void) int32 actual = ~OS_SUCCESS; os_fsinfo_t filesys_info; + UT_SetDefaultReturnValue(UT_KEY(OS_ObjectIdIteratorGetNext), 1); + UT_SetDeferredRetcode(UT_KEY(OS_ObjectIdIteratorGetNext), 3, 0); + UT_SetDeferredRetcode(UT_KEY(OS_ObjectIdIteratorGetNext), 4, 0); + actual = OS_GetFsInfo(&filesys_info); UtAssert_True(actual == expected, "OS_FileSysInfo() (%ld) == OS_SUCCESS", (long)actual); @@ -414,11 +469,11 @@ void Test_OS_GetFsInfo(void) "filesys_info.MaxVolumes (%lu) == OS_MAX_FILE_SYSTEMS", (unsigned long)filesys_info.MaxVolumes); /* since there are no open files, the free fd count should match the max */ - UtAssert_True(filesys_info.FreeFds == OS_MAX_NUM_OPEN_FILES, "filesys_info.FreeFds (%lu) == OS_MAX_NUM_OPEN_FILES", + UtAssert_True(filesys_info.FreeFds == 2, "filesys_info.FreeFds (%lu) == 2", (unsigned long)filesys_info.FreeFds); - UtAssert_True(filesys_info.FreeVolumes == OS_MAX_FILE_SYSTEMS, - "filesys_info.FreeVolumes (%lu) == OS_MAX_FILE_SYSTEMS", (unsigned long)filesys_info.FreeVolumes); + UtAssert_True(filesys_info.FreeVolumes == 3, "filesys_info.FreeVolumes (%lu) == 3", + (unsigned long)filesys_info.FreeVolumes); expected = OS_INVALID_POINTER; actual = OS_GetFsInfo(NULL); @@ -577,4 +632,5 @@ void UtTest_Setup(void) ADD_TEST(OS_GetFsInfo); ADD_TEST(OS_TranslatePath); ADD_TEST(OS_FileSys_FindVirtMountPoint); + ADD_TEST(OS_FileSysStatVolume); } diff --git a/src/unit-test-coverage/shared/src/coveragetest-idmap.c b/src/unit-test-coverage/shared/src/coveragetest-idmap.c index ea06f17c4..6f7a4db4f 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-idmap.c +++ b/src/unit-test-coverage/shared/src/coveragetest-idmap.c @@ -66,6 +66,13 @@ static void ObjTypeCounter(osal_id_t object_id, void *arg) } } +static int32 TestIterator(osal_id_t object_id, void *arg) +{ + uint32 *c = arg; + ++(*c); + return UT_DEFAULT_IMPL(TestIterator); +} + void Test_OS_ObjectIdInit(void) { /* @@ -85,21 +92,53 @@ void Test_OS_LockUnlockGlobal(void) * void OS_Lock_Global(uint32 idtype) * void OS_Unlock_Global(uint32 idtype) */ + OS_object_token_t token; + + memset(&token, 0, sizeof(token)); + + token.obj_type = OS_OBJECT_TYPE_OS_COUNTSEM; + token.lock_mode = OS_LOCK_MODE_GLOBAL; /* * As these have no return codes, these tests * exist to get coverage of the paths. */ - OS_Lock_Global(OS_OBJECT_TYPE_OS_COUNTSEM); - OS_Unlock_Global(OS_OBJECT_TYPE_OS_COUNTSEM); - OS_Lock_Global(0); - OS_Unlock_Global(0); - OS_Lock_Global(55555); - OS_Unlock_Global(55555); + OS_Lock_Global(&token); + OS_Unlock_Global(&token); + + token.obj_type = OS_OBJECT_TYPE_UNDEFINED; + + OS_Lock_Global(&token); + OS_Unlock_Global(&token); + + token.obj_type = 55555; + + OS_Lock_Global(&token); + OS_Unlock_Global(&token); UT_SetDefaultReturnValue(UT_KEY(OS_TaskGetId), 0); - OS_Lock_Global(OS_OBJECT_TYPE_OS_BINSEM); - OS_Unlock_Global(OS_OBJECT_TYPE_OS_BINSEM); + token.obj_type = OS_OBJECT_TYPE_OS_BINSEM; + + OS_Lock_Global(&token); + OS_Unlock_Global(&token); + + UT_ResetState(UT_KEY(OS_TaskGetId)); + + /* + * Execute paths where the incorrect patten is followed, + * such as unlocking from a different task than the lock. + * These trigger OS_DEBUG messages, if compiled in. + * + * Start by locking twice in a row + */ + OS_Lock_Global(&token); + OS_Lock_Global(&token); + + /* + * Next unlock with wrong/corrupt/bad key + */ + token.lock_key.key_value ^= 0x11111111; + OS_Unlock_Global(&token); } void Test_OS_ObjectIdConvertToken(void) @@ -121,6 +160,9 @@ void Test_OS_ObjectIdConvertToken(void) OS_ObjectIdAllocateNew(OS_OBJECT_TYPE_OS_TASK, "ut", &token); objid = token.obj_id; + /* The prep function should have unlocked once */ + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 1); + record = OS_OBJECT_TABLE_GET(OS_global_task_table, token); record->refcount = 5; record->active_id = objid; @@ -137,6 +179,9 @@ void Test_OS_ObjectIdConvertToken(void) UtAssert_True(actual == expected, "OS_ObjectIdConvertLock() (%ld) == OS_ERR_INVALID_ID (%ld)", (long)actual, (long)expected); + /* Global should not be released */ + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 1); + /* * Use mode OS_LOCK_MODE_NONE with matching ID * This should return success. @@ -149,9 +194,12 @@ void Test_OS_ObjectIdConvertToken(void) UtAssert_True(actual == expected, "OS_ObjectIdConvertLock(NONE) (%ld) == OS_SUCCESS (%ld)", (long)actual, (long)expected); + /* Global should not be released */ + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 1); + /* * Use mode OS_LOCK_MODE_GLOBAL with matching ID - * This should return success, not change refcount + * This should return success and update refcount */ token.lock_mode = OS_LOCK_MODE_GLOBAL; token.obj_id = objid; @@ -160,7 +208,10 @@ void Test_OS_ObjectIdConvertToken(void) UtAssert_True(actual == expected, "OS_ObjectIdConvertLock(GLOBAL) (%ld) == OS_SUCCESS (%ld)", (long)actual, (long)expected); - UtAssert_UINT32_EQ(record->refcount, 5); + UtAssert_UINT32_EQ(record->refcount, 6); + + /* Global should not be released */ + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 1); /* * Use mode OS_LOCK_MODE_REFCOUNT with matching ID @@ -173,8 +224,23 @@ void Test_OS_ObjectIdConvertToken(void) UtAssert_True(actual == expected, "OS_ObjectIdConvertLock(REFCOUNT) (%ld) == OS_SUCCESS (%ld)", (long)actual, (long)expected); - UtAssert_UINT32_EQ(record->refcount, 6); + UtAssert_UINT32_EQ(record->refcount, 7); + + /* Global should be released */ + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 2); + + /* + * Use mode OS_LOCK_MODE_RESERVED with non-reserved ID. + */ + token.lock_mode = OS_LOCK_MODE_RESERVED; + token.obj_id = objid; + actual = OS_ObjectIdConvertToken(&token); + expected = OS_ERR_INVALID_ID; + UtAssert_True(actual == expected, "OS_ObjectIdConvertLock(RESERVED) (%ld) == OS_ERR_INVALID_ID (%ld)", + (long)actual, (long)expected); + /* Global should not be released */ + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 2); /* * Use mode OS_LOCK_MODE_EXCLUSIVE with matching ID and other refs. * This should return OS_ERR_OBJECT_IN_USE. @@ -189,18 +255,40 @@ void Test_OS_ObjectIdConvertToken(void) /* should have delayed 4 times, on the 5th try it returns error */ UtAssert_STUB_COUNT(OS_WaitForStateChange_Impl, 4); + /* Global should not be released */ + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 2); + /* It should also have preserved the original ID */ UtAssert_True(OS_ObjectIdEqual(record->active_id, objid), "OS_ObjectIdConvertLock(EXCLUSIVE) objid restored"); /* * Use mode OS_LOCK_MODE_EXCLUSIVE with matching ID and no other refs. - * This should return success. + * This should return success and set the active_id to OS_OBJECT_ID_RESERVED. */ record->refcount = 0; actual = OS_ObjectIdConvertToken(&token); expected = OS_SUCCESS; UtAssert_True(actual == expected, "OS_ObjectIdConvertLock(EXCLUSIVE) (%ld) == OS_SUCCESS (%ld)", (long)actual, (long)expected); + UtAssert_True(OS_ObjectIdEqual(record->active_id, OS_OBJECT_ID_RESERVED), + "OS_ObjectIdConvertLock(EXCLUSIVE) objid reserved"); + + /* Global should be released */ + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 3); + + /* + * Use mode OS_LOCK_MODE_RESERVED with reserved ID. + * This should return OS_SUCCESS. + */ + token.lock_mode = OS_LOCK_MODE_RESERVED; + token.obj_id = objid; + actual = OS_ObjectIdConvertToken(&token); + expected = OS_SUCCESS; + UtAssert_True(actual == expected, "OS_ObjectIdConvertLock(RESERVED) (%ld) == OS_SUCCESS (%ld)", + (long)actual, (long)expected); + + /* Global should not be released */ + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 3); } void Test_OS_ObjectIdGetBySearch(void) @@ -323,6 +411,10 @@ void Test_OS_ObjectIdToArrayIndex(void) expected = OS_ERR_INVALID_ID; actual = OS_ObjectIdToArrayIndex(0xFFFF, UT_OBJID_OTHER, &local_idx); UtAssert_True(actual == expected, "OS_ObjectIdToArrayIndex() (%ld) == OS_ERR_INVALID_ID", (long)actual); + + expected = OS_INVALID_POINTER; + actual = OS_ObjectIdToArrayIndex(OS_OBJECT_TYPE_OS_TASK, objid, NULL); + UtAssert_True(actual == expected, "OS_ObjectIdToArrayIndex() (%ld) == OS_INVALID_POINTER", (long)actual); } void Test_OS_ObjectIdFindByName(void) @@ -602,6 +694,15 @@ void Test_OS_ObjectIdAllocateNew(void) actual = OS_ObjectIdAllocateNew(OS_OBJECT_TYPE_OS_TASK, "UT_alloc", &token); UtAssert_True(actual == expected, "OS_ObjectIdAllocate() (%ld) == OS_ERR_NAME_TAKEN", (long)actual); + /* + * Although an object with that name exists, it isn't fully created yet. + * OS_ObjectIdAllocateNew() should leave the object record in a state where + * attempts to get object ID by name should fail. + */ + expected = OS_ERR_INCORRECT_OBJ_STATE; + 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); @@ -611,6 +712,18 @@ void Test_OS_ObjectIdAllocateNew(void) expected = OS_ERR_INCORRECT_OBJ_TYPE; actual = OS_ObjectIdAllocateNew(0xFFFF, "UT_alloc", &token); UtAssert_True(actual == expected, "OS_ObjectIdAllocate() (%ld) == OS_ERR_INCORRECT_OBJ_TYPE", (long)actual); + + /* + * Test late-stage failure path - + * If object was allocated successfully to the point that a table index was assigned, + * but then failed later, it should call FinalizeNew with the error code so the table + * entry can be cleaned up (effect is the same as if the underlying impl failed). + */ + UT_SetDefaultReturnValue(UT_KEY(OS_NotifyEvent), OS_ERR_INVALID_SIZE); + expected = OS_ERR_INVALID_SIZE; + actual = OS_ObjectIdAllocateNew(OS_OBJECT_TYPE_OS_TASK, "UT_alloc2", &token); + UtAssert_True(actual == expected, "OS_ObjectIdAllocateNew() (%ld) == OS_ERR_INVALID_SIZE", (long)actual); + } void Test_OS_ConvertToArrayIndex(void) @@ -638,6 +751,193 @@ void Test_OS_ConvertToArrayIndex(void) UtAssert_True(actual == expected, "OS_ConvertToArrayIndex() (%ld) == OS_ERR_INVALID_ID", (long)actual); } +void Test_OS_ObjectIdTransaction(void) +{ + /* + * Test Case For: + * int32 OS_ObjectIdTransactionInit(OS_lock_mode_t lock_mode, osal_objtype_t idtype, OS_object_token_t *token); + * void OS_ObjectIdTransactionCancel(OS_object_token_t *token); + * void OS_ObjectIdTransactionFinish(OS_object_token_t *token, osal_id_t *final_id); + * void OS_ObjectIdTransferToken(OS_object_token_t *token_from, OS_object_token_t *token_to); + */ + + OS_object_token_t token; + OS_object_token_t token2; + osal_id_t objid; + OS_common_record_t *record; + + memset(&token, 0xAA, sizeof(token)); + memset(&OS_SharedGlobalVars, 0, sizeof(OS_SharedGlobalVars)); + + /* With OS_SharedGlobalVars uninitialized (0) it should prevent transactions */ + OSAPI_TEST_FUNCTION_RC(OS_ObjectIdTransactionInit(OS_LOCK_MODE_GLOBAL, OS_OBJECT_TYPE_OS_BINSEM, &token), OS_ERROR); + UtAssert_UINT32_EQ(token.lock_mode, OS_LOCK_MODE_NONE); + UtAssert_STUB_COUNT(OS_Lock_Global_Impl, 0); + + /* shutdown will prevent transactions */ + OS_SharedGlobalVars.Initialized = true; + OS_SharedGlobalVars.ShutdownFlag = 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); + UtAssert_UINT32_EQ(token.obj_type, OS_OBJECT_TYPE_UNDEFINED); + UtAssert_STUB_COUNT(OS_Lock_Global_Impl, 0); + + /* except for exclusive (delete) transactions, which should succeed */ + OSAPI_TEST_FUNCTION_RC(OS_ObjectIdTransactionInit(OS_LOCK_MODE_EXCLUSIVE, OS_OBJECT_TYPE_OS_BINSEM, &token), OS_SUCCESS); + UtAssert_UINT32_EQ(token.lock_mode, OS_LOCK_MODE_EXCLUSIVE); + UtAssert_UINT32_EQ(token.obj_idx, -1); + UtAssert_STUB_COUNT(OS_Lock_Global_Impl, 1); + + /* cancel should unlock */ + OS_ObjectIdTransactionCancel(&token); + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 1); + + /* other cases for normal operating mode */ + OS_SharedGlobalVars.ShutdownFlag = 0; + 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); + UtAssert_UINT32_EQ(token.obj_type, OS_OBJECT_TYPE_OS_COUNTSEM); + UtAssert_STUB_COUNT(OS_Lock_Global_Impl, 2); + + /* bad object type */ + OSAPI_TEST_FUNCTION_RC(OS_ObjectIdTransactionInit(OS_LOCK_MODE_GLOBAL, OS_OBJECT_TYPE_UNDEFINED, &token), OS_ERR_INCORRECT_OBJ_TYPE); + UtAssert_UINT32_EQ(token.lock_mode, OS_LOCK_MODE_NONE); + UtAssert_UINT32_EQ(token.obj_type, OS_OBJECT_TYPE_UNDEFINED); + UtAssert_STUB_COUNT(OS_Lock_Global_Impl, 2); + + /* normal finish (sets ID from passed in value) */ + objid = UT_OBJID_1; + token.obj_id = UT_OBJID_2; + token.obj_idx = UT_INDEX_2; + token.obj_type = OS_OBJECT_TYPE_OS_TASK; + token.lock_mode = OS_LOCK_MODE_GLOBAL; + record = OS_ObjectIdGlobalFromToken(&token); + record->refcount = 1; + + OS_ObjectIdTransactionFinish(&token, &objid); + UtAssert_STUB_COUNT(OS_Lock_Global_Impl, 2); + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 2); + OSAPI_TEST_OBJID(record->active_id, ==, objid); + UtAssert_UINT32_EQ(record->refcount, 0); + + /* exclusive lock finish (restores ID from token) */ + record->refcount = 1; + record->active_id = OS_OBJECT_ID_RESERVED; + token.lock_mode = OS_LOCK_MODE_EXCLUSIVE; + OS_ObjectIdTransactionFinish(&token, NULL); + UtAssert_STUB_COUNT(OS_Lock_Global_Impl, 3); + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 3); + OSAPI_TEST_OBJID(record->active_id, ==, token.obj_id); + UtAssert_UINT32_EQ(record->refcount, 0); + + /* refcount finish (no change to ID) */ + token.lock_mode = OS_LOCK_MODE_REFCOUNT; + record->refcount = 1; + record->active_id = UT_OBJID_1; + OS_ObjectIdTransactionFinish(&token, NULL); + UtAssert_STUB_COUNT(OS_Lock_Global_Impl, 4); + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 4); + OSAPI_TEST_OBJID(record->active_id, ==, UT_OBJID_1); + UtAssert_UINT32_EQ(record->refcount, 0); + + /* other finish with refcount already 0 */ + token.lock_mode = OS_LOCK_MODE_GLOBAL; + OS_ObjectIdTransactionFinish(&token, NULL); + UtAssert_STUB_COUNT(OS_Lock_Global_Impl, 4); + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 5); + OSAPI_TEST_OBJID(record->active_id, ==, UT_OBJID_1); + UtAssert_UINT32_EQ(record->refcount, 0); + + /* test transferring a refcount token */ + memset(&token2, 0xBB, sizeof(token2)); + token.obj_id = UT_OBJID_2; + token.obj_idx = UT_INDEX_2; + token.obj_type = OS_OBJECT_TYPE_OS_TASK; + token.lock_mode = OS_LOCK_MODE_GLOBAL; + + OS_ObjectIdTransferToken(&token, &token2); + + /* actual lock_mode should only be on token2 now */ + UtAssert_UINT32_EQ(token.lock_mode, OS_LOCK_MODE_NONE); + UtAssert_UINT32_EQ(token2.lock_mode, OS_LOCK_MODE_GLOBAL); + + /* other fields should stay the same */ + UtAssert_UINT32_EQ(token.obj_idx, token2.obj_idx); + UtAssert_UINT32_EQ(token.obj_type, token2.obj_type); + OSAPI_TEST_OBJID(token.obj_id, ==, token2.obj_id); +} + +void Test_OS_ObjectIdFinalize(void) +{ + /* + * Test Case For: + * int32 OS_ObjectIdFinalizeNew(int32 operation_status, OS_object_token_t *token, osal_id_t *outid); + * int32 OS_ObjectIdFinalizeDelete(int32 operation_status, OS_object_token_t *token); + */ + int32 expected; + int32 actual; + OS_object_token_t token; + osal_id_t objid; + OS_common_record_t *record; + + memset(&token, 0, sizeof(token)); + + objid = UT_OBJID_1; + token.obj_id = UT_OBJID_2; + token.obj_idx = UT_INDEX_2; + token.obj_type = OS_OBJECT_TYPE_OS_TASK; + token.lock_mode = OS_LOCK_MODE_EXCLUSIVE; + + record = OS_ObjectIdGlobalFromToken(&token); + + /* if creation fails, RC should be passed through and ID set to UNDEFINED */ + token.lock_mode = OS_LOCK_MODE_EXCLUSIVE; + record->active_id = OS_OBJECT_ID_RESERVED; + expected = OS_ERR_INVALID_ID; + actual = OS_ObjectIdFinalizeNew(OS_ERR_INVALID_ID, &token, &objid); + UtAssert_True(actual == expected, "OS_ObjectIdFinalizeNew() rc passthru (%ld) == OS_ERR_INVALID_ID (%ld)", (long)actual, (long)expected); + OSAPI_TEST_OBJID(objid, ==, OS_OBJECT_ID_UNDEFINED); + OSAPI_TEST_OBJID(record->active_id, ==, OS_OBJECT_ID_UNDEFINED); + UtAssert_UINT32_EQ(token.lock_mode, OS_LOCK_MODE_NONE); + + /* if creation succeeds, RC should be passed through and ID set to token value */ + token.lock_mode = OS_LOCK_MODE_EXCLUSIVE; + record->active_id = OS_OBJECT_ID_RESERVED; + expected = OS_SUCCESS; + actual = OS_ObjectIdFinalizeNew(OS_SUCCESS, &token, &objid); + UtAssert_True(actual == expected, "OS_ObjectIdFinalizeNew() rc passthru (%ld) == OS_SUCCESS (%ld)", (long)actual, (long)expected); + OSAPI_TEST_OBJID(objid, ==, token.obj_id); + OSAPI_TEST_OBJID(record->active_id, ==, token.obj_id); + UtAssert_UINT32_EQ(token.lock_mode, OS_LOCK_MODE_NONE); + + /* verify passing NULL for out ID for path coverage */ + token.lock_mode = OS_LOCK_MODE_EXCLUSIVE; + record->active_id = OS_OBJECT_ID_RESERVED; + expected = OS_SUCCESS; + actual = OS_ObjectIdFinalizeNew(OS_SUCCESS, &token, NULL); + UtAssert_True(actual == expected, "OS_ObjectIdFinalizeNew() rc passthru (%ld) == OS_SUCCESS (%ld)", (long)actual, (long)expected); + OSAPI_TEST_OBJID(record->active_id, ==, token.obj_id); + UtAssert_UINT32_EQ(token.lock_mode, OS_LOCK_MODE_NONE); + + /* if delete succeeds, RC should be passed through and ID set to UNDEFINED */ + token.lock_mode = OS_LOCK_MODE_EXCLUSIVE; + record->active_id = OS_OBJECT_ID_RESERVED; + expected = OS_SUCCESS; + actual = OS_ObjectIdFinalizeDelete(OS_SUCCESS, &token); + UtAssert_True(actual == expected, "OS_ObjectIdFinalizeDelete() rc passthru (%ld) == OS_SUCCESS (%ld)", (long)actual, (long)expected); + OSAPI_TEST_OBJID(record->active_id, ==, OS_OBJECT_ID_UNDEFINED); + UtAssert_UINT32_EQ(token.lock_mode, OS_LOCK_MODE_NONE); + + /* if delete fails, RC should be passed through and ID set to the token value */ + token.lock_mode = OS_LOCK_MODE_EXCLUSIVE; + record->active_id = OS_OBJECT_ID_RESERVED; + expected = OS_ERR_INVALID_ID; + actual = OS_ObjectIdFinalizeDelete(OS_ERR_INVALID_ID, &token); + UtAssert_True(actual == expected, "OS_ObjectIdFinalizeDelete() rc passthru (%ld) == OS_ERR_INVALID_ID (%ld)", (long)actual, (long)expected); + OSAPI_TEST_OBJID(record->active_id, ==, token.obj_id); + UtAssert_UINT32_EQ(token.lock_mode, OS_LOCK_MODE_NONE); +} + void Test_OS_ForEachObject(void) { /* @@ -725,6 +1025,47 @@ void Test_OS_GetResourceName(void) UtAssert_True(actual == expected, "OS_GetResourceName() (%ld) == OS_INVALID_POINTER", (long)actual); } +void Test_OS_ObjectIdIterator(void) +{ + /* + * Test Case For: + * int32 OS_ObjectIdIteratorInit(OS_ObjectMatchFunc_t matchfunc, void *matcharg, osal_objtype_t objtype, + OS_object_iter_t *iter); + * bool OS_ObjectFilterActive(void *ref, const OS_object_token_t *token, const OS_common_record_t *obj); + * int32 OS_ObjectIdIterateActive(osal_objtype_t objtype, OS_object_iter_t *iter); + * bool OS_ObjectIdIteratorGetNext(OS_object_iter_t *iter); + * void OS_ObjectIdIteratorDestroy(OS_object_iter_t *iter); + * int32 OS_ObjectIdIteratorProcessEntry(OS_object_iter_t *iter, int32 (*func)(osal_id_t, void *)); + */ + OS_object_iter_t iter; + OS_common_record_t rec; + uint32 testarg; + + OSAPI_TEST_FUNCTION_RC(OS_ObjectIdIteratorInit(NULL, NULL, OS_OBJECT_TYPE_UNDEFINED, &iter), OS_ERR_INCORRECT_OBJ_TYPE); + OSAPI_TEST_FUNCTION_RC(OS_ObjectIdIterateActive(OS_OBJECT_TYPE_OS_TASK, &iter), OS_SUCCESS); + UtAssert_STUB_COUNT(OS_Lock_Global_Impl, 1); + + memset(&rec, 0, sizeof(rec)); + UtAssert_True(!OS_ObjectFilterActive(NULL, NULL, &rec), "OS_ObjectFilterActive() empty record"); + + rec.active_id = UT_OBJID_1; + UtAssert_True(OS_ObjectFilterActive(NULL, NULL, &rec), "OS_ObjectFilterActive() non-empty record"); + + /* OS_ObjectIdIteratorProcessEntry unlocks and re-locks */ + testarg = 4; + iter.arg = &testarg; + OS_ObjectIdIteratorProcessEntry(&iter, TestIterator); + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 1); + UtAssert_STUB_COUNT(OS_Lock_Global_Impl, 2); + + + /* OS_ObjectIdIteratorDestroy is just a passthrough to OS_ObjectIdTransactionCancel, + * but need to call for coverage */ + OS_ObjectIdIteratorDestroy(&iter); + UtAssert_STUB_COUNT(OS_Unlock_Global_Impl, 2); + +} + /* Osapi_Test_Setup * * Purpose: @@ -764,7 +1105,9 @@ void UtTest_Setup(void) ADD_TEST(OS_ObjectIdToArrayIndex); ADD_TEST(OS_ObjectIdFindByName); ADD_TEST(OS_ObjectIdGetById); + ADD_TEST(OS_ObjectIdTransaction); ADD_TEST(OS_ObjectIdAllocateNew); + ADD_TEST(OS_ObjectIdFinalize); ADD_TEST(OS_ObjectIdConvertToken); ADD_TEST(OS_ObjectIdGetBySearch); ADD_TEST(OS_ConvertToArrayIndex); @@ -772,4 +1115,5 @@ void UtTest_Setup(void) ADD_TEST(OS_GetMaxForObjectType); ADD_TEST(OS_GetBaseForObjectType); ADD_TEST(OS_GetResourceName); + ADD_TEST(OS_ObjectIdIterator); } diff --git a/src/unit-test-coverage/shared/src/coveragetest-sockets.c b/src/unit-test-coverage/shared/src/coveragetest-sockets.c index 938032578..3e807bbe9 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-sockets.c +++ b/src/unit-test-coverage/shared/src/coveragetest-sockets.c @@ -335,9 +335,17 @@ void Test_OS_SocketSendTo(void) UtAssert_True(actual == expected, "OS_SocketSendTo() (%ld) == OS_SUCCESS", (long)actual); expected = OS_INVALID_POINTER; - actual = OS_SocketSendTo(UT_OBJID_1, NULL, OSAL_SIZE_C(0), NULL); + actual = OS_SocketSendTo(UT_OBJID_1, NULL, sizeof(Buf), &Addr); UtAssert_True(actual == expected, "OS_SocketSendTo(NULL) (%ld) == OS_INVALID_POINTER", (long)actual); + expected = OS_INVALID_POINTER; + actual = OS_SocketSendTo(UT_OBJID_1, &Buf, sizeof(Buf), NULL); + UtAssert_True(actual == expected, "OS_SocketSendTo(NULL) (%ld) == OS_INVALID_POINTER", (long)actual); + + expected = OS_ERR_INVALID_SIZE; + actual = OS_SocketSendTo(UT_OBJID_1, &Buf, OSAL_SIZE_C(0), &Addr); + UtAssert_True(actual == expected, "OS_SocketSendTo(0) (%ld) == OS_ERR_INVALID_SIZE", (long)actual); + /* * Should fail if not a datagram socket */ diff --git a/src/unit-test-coverage/shared/src/coveragetest-timebase.c b/src/unit-test-coverage/shared/src/coveragetest-timebase.c index fc1675c5d..a1e142590 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-timebase.c +++ b/src/unit-test-coverage/shared/src/coveragetest-timebase.c @@ -234,6 +234,10 @@ void Test_OS_TimeBaseGetFreeRun(void) int32 actual = OS_TimeBaseGetFreeRun(UT_OBJID_1, &freerun); UtAssert_True(actual == expected, "OS_TimeBaseGetFreeRun() (%ld) == OS_SUCCESS", (long)actual); + + expected = OS_INVALID_POINTER; + actual = OS_TimeBaseGetFreeRun(UT_OBJID_1, NULL); + UtAssert_True(actual == expected, "OS_TimeBaseGetFreeRun() (%ld) == OS_INVALID_POINTER", (long)actual); } void Test_OS_TimeBase_CallbackThread(void) diff --git a/src/unit-test-coverage/ut-stubs/inc/OCS_errno.h b/src/unit-test-coverage/ut-stubs/inc/OCS_errno.h index 8d7d89b93..290ed09fe 100644 --- a/src/unit-test-coverage/ut-stubs/inc/OCS_errno.h +++ b/src/unit-test-coverage/ut-stubs/inc/OCS_errno.h @@ -30,10 +30,14 @@ /* POSIX-specific errnos */ #define OCS_EINTR 0x1801 #define OCS_EAGAIN 0x1802 +#define OCS_EEXIST 0x180a #define OCS_EINVAL 0x1803 #define OCS_EMSGSIZE 0x1804 #define OCS_ETIMEDOUT 0x1805 #define OCS_ESPIPE 0x1806 +#define OCS_ENOTSUP 0x1807 +#define OCS_ENOSYS 0x1808 +#define OCS_EROFS 0x1809 /* ----------------------------------------- */ /* types normally defined in errno.h */ diff --git a/src/unit-test-coverage/ut-stubs/inc/OCS_fcntl.h b/src/unit-test-coverage/ut-stubs/inc/OCS_fcntl.h index 96bc3cdb1..48408b35c 100644 --- a/src/unit-test-coverage/ut-stubs/inc/OCS_fcntl.h +++ b/src/unit-test-coverage/ut-stubs/inc/OCS_fcntl.h @@ -38,6 +38,10 @@ * * These are exposed to apps through fcntl.h and sys/stat.h */ +#define OCS_S_IRWXO 0x1110 +#define OCS_S_IRWXG 0x2220 +#define OCS_S_IRWXU 0x4440 + #define OCS_S_IXOTH 0x1000 #define OCS_S_IXGRP 0x2000 #define OCS_S_IXUSR 0x4000 diff --git a/src/unit-test-coverage/ut-stubs/inc/OCS_stat.h b/src/unit-test-coverage/ut-stubs/inc/OCS_stat.h index 841af324a..79c52ae17 100644 --- a/src/unit-test-coverage/ut-stubs/inc/OCS_stat.h +++ b/src/unit-test-coverage/ut-stubs/inc/OCS_stat.h @@ -24,6 +24,7 @@ #include #include +#include /* ----------------------------------------- */ /* constants normally defined in sys/stat.h */ @@ -39,11 +40,12 @@ struct OCS_stat { - OCS_mode_t st_mode; - OCS_off_t st_size; - OCS_time_t st_mtime; - OCS_uid_t st_uid; - OCS_gid_t st_gid; + OCS_mode_t st_mode; + OCS_off_t st_size; + OCS_time_t st_mtime; + struct OCS_timespec st_mtim; + OCS_uid_t st_uid; + OCS_gid_t st_gid; }; /* ----------------------------------------- */ diff --git a/src/unit-test-coverage/ut-stubs/override_inc/errno.h b/src/unit-test-coverage/ut-stubs/override_inc/errno.h index 636ac2a34..91ff72ad6 100644 --- a/src/unit-test-coverage/ut-stubs/override_inc/errno.h +++ b/src/unit-test-coverage/ut-stubs/override_inc/errno.h @@ -30,9 +30,13 @@ #define EINTR OCS_EINTR #define EAGAIN OCS_EAGAIN #define EINVAL OCS_EINVAL +#define EEXIST OCS_EEXIST #define EMSGSIZE OCS_EMSGSIZE #define ETIMEDOUT OCS_ETIMEDOUT #define ESPIPE OCS_ESPIPE +#define ENOTSUP OCS_ENOTSUP +#define ENOSYS OCS_ENOSYS +#define EROFS OCS_EROFS #define errno OCS_errno diff --git a/src/unit-test-coverage/ut-stubs/override_inc/fcntl.h b/src/unit-test-coverage/ut-stubs/override_inc/fcntl.h index 8b0f2f289..50b359062 100644 --- a/src/unit-test-coverage/ut-stubs/override_inc/fcntl.h +++ b/src/unit-test-coverage/ut-stubs/override_inc/fcntl.h @@ -27,6 +27,9 @@ /* ----------------------------------------- */ /* mappings for declarations in fcntl.h */ /* ----------------------------------------- */ +#define S_IRWXU OCS_S_IRWXU +#define S_IRWXG OCS_S_IRWXG +#define S_IRWXO OCS_S_IRWXO #define S_IXOTH OCS_S_IXOTH #define S_IXGRP OCS_S_IXGRP #define S_IXUSR OCS_S_IXUSR diff --git a/src/unit-test-coverage/ut-stubs/src/osapi-idmap-impl-stubs.c b/src/unit-test-coverage/ut-stubs/src/osapi-idmap-impl-stubs.c index 93440c93d..7bff71d1e 100644 --- a/src/unit-test-coverage/ut-stubs/src/osapi-idmap-impl-stubs.c +++ b/src/unit-test-coverage/ut-stubs/src/osapi-idmap-impl-stubs.c @@ -38,5 +38,11 @@ * Table locking and unlocking for global objects can be done at the shared code * layer but the actual implementation is OS-specific */ -UT_DEFAULT_STUB(OS_Lock_Global_Impl, (osal_objtype_t idtype)) -UT_DEFAULT_STUB(OS_Unlock_Global_Impl, (osal_objtype_t idtype)) +void OS_Lock_Global_Impl(osal_objtype_t idtype) +{ + UT_DEFAULT_IMPL(OS_Lock_Global_Impl); +} +void OS_Unlock_Global_Impl(osal_objtype_t idtype) +{ + UT_DEFAULT_IMPL(OS_Unlock_Global_Impl); +} diff --git a/src/unit-test-coverage/ut-stubs/src/osapi-task-impl-stubs.c b/src/unit-test-coverage/ut-stubs/src/osapi-task-impl-stubs.c index 963d79173..fd3dd43d2 100644 --- a/src/unit-test-coverage/ut-stubs/src/osapi-task-impl-stubs.c +++ b/src/unit-test-coverage/ut-stubs/src/osapi-task-impl-stubs.c @@ -39,6 +39,7 @@ ** Task API */ UT_DEFAULT_STUB(OS_TaskMatch_Impl, (const OS_object_token_t *token)) +UT_DEFAULT_STUB(OS_TaskDetach_Impl, (const OS_object_token_t *token)) UT_DEFAULT_STUB(OS_TaskCreate_Impl, (const OS_object_token_t *token, uint32 flags)) UT_DEFAULT_STUB(OS_TaskDelete_Impl, (const OS_object_token_t *token)) void OS_TaskExit_Impl(void) diff --git a/src/unit-test-coverage/vxworks/CMakeLists.txt b/src/unit-test-coverage/vxworks/CMakeLists.txt index afcf47eb1..5bc877276 100644 --- a/src/unit-test-coverage/vxworks/CMakeLists.txt +++ b/src/unit-test-coverage/vxworks/CMakeLists.txt @@ -5,7 +5,6 @@ set(VXWORKS_MODULE_LIST common console countsem - dirs dirs-globals files filesys @@ -25,6 +24,7 @@ set(VXWORKS_PORTABLE_BLOCK_LIST posix-gettime posix-io posix-files + posix-dirs console-bsp bsd-select diff --git a/src/unit-test-coverage/vxworks/adaptors/src/ut-adaptor-idmap.c b/src/unit-test-coverage/vxworks/adaptors/src/ut-adaptor-idmap.c index 272937652..f436f8146 100644 --- a/src/unit-test-coverage/vxworks/adaptors/src/ut-adaptor-idmap.c +++ b/src/unit-test-coverage/vxworks/adaptors/src/ut-adaptor-idmap.c @@ -30,6 +30,7 @@ #include #include +#include "os-impl-idmap.h" #include "ut-adaptor-idmap.h" int32 UT_Call_OS_VxWorks_TableMutex_Init(osal_objtype_t idtype) @@ -39,5 +40,5 @@ int32 UT_Call_OS_VxWorks_TableMutex_Init(osal_objtype_t idtype) void UT_IdMapTest_SetImplTableMutex(osal_objtype_t idtype, OCS_SEM_ID vxid) { - VX_MUTEX_TABLE[idtype].vxid = vxid; + OS_impl_objtype_lock_table[idtype]->vxid = vxid; } diff --git a/src/unit-test-coverage/vxworks/src/coveragetest-filesys.c b/src/unit-test-coverage/vxworks/src/coveragetest-filesys.c index 52c2c69cf..de2998415 100644 --- a/src/unit-test-coverage/vxworks/src/coveragetest-filesys.c +++ b/src/unit-test-coverage/vxworks/src/coveragetest-filesys.c @@ -130,12 +130,38 @@ void Test_OS_FileSysMountVolume_Impl(void) * int32 OS_FileSysMountVolume_Impl (uint32 filesys_id) */ OS_object_token_t token = UT_TOKEN_0; + struct OCS_stat statbuf; + + memset(&OS_filesys_table[0], 0, sizeof(OS_filesys_table[0])); + OS_filesys_table[0].fstype = OS_FILESYS_TYPE_NORMAL_DISK; + strcpy(OS_filesys_table[0].system_mountpt, "/ut"); OSAPI_TEST_FUNCTION_RC(OS_FileSysMountVolume_Impl(&token), OS_SUCCESS); UT_SetDefaultReturnValue(UT_KEY(OCS_open), -1); OSAPI_TEST_FUNCTION_RC(OS_FileSysMountVolume_Impl(&token), OS_ERROR); UT_ClearForceFail(UT_KEY(OCS_open)); + + /* Additional cases for the FS_BASED handling */ + OS_filesys_table[0].fstype = OS_FILESYS_TYPE_FS_BASED; + + /* Mount dir does not exist but can be created */ + UT_SetDefaultReturnValue(UT_KEY(OCS_stat), -1); + OSAPI_TEST_FUNCTION_RC(OS_FileSysMountVolume_Impl(&token), OS_SUCCESS); + + /* Mount dir does not exist and cannot be created */ + UT_SetDeferredRetcode(UT_KEY(OCS_mkdir), 1, -1); + OSAPI_TEST_FUNCTION_RC(OS_FileSysMountVolume_Impl(&token), OS_FS_ERR_DRIVE_NOT_CREATED); + + /* Mount dir does exist but not a directory */ + UT_ClearForceFail(UT_KEY(OCS_stat)); + OSAPI_TEST_FUNCTION_RC(OS_FileSysMountVolume_Impl(&token), OS_FS_ERR_PATH_INVALID); + + /* Mount dir does exist and is a directory */ + memset(&statbuf, 0, sizeof(statbuf)); + statbuf.st_mode = OCS_S_IFDIR; + UT_SetDataBuffer(UT_KEY(OCS_stat), &statbuf, sizeof(statbuf), false); + OSAPI_TEST_FUNCTION_RC(OS_FileSysMountVolume_Impl(&token), OS_SUCCESS); } void Test_OS_FileSysUnmountVolume_Impl(void) @@ -145,6 +171,10 @@ void Test_OS_FileSysUnmountVolume_Impl(void) */ OS_object_token_t token = UT_TOKEN_0; + memset(&OS_filesys_table[0], 0, sizeof(OS_filesys_table[0])); + OS_filesys_table[0].fstype = OS_FILESYS_TYPE_NORMAL_DISK; + strcpy(OS_filesys_table[0].system_mountpt, "/ut"); + OSAPI_TEST_FUNCTION_RC(OS_FileSysUnmountVolume_Impl(&token), OS_SUCCESS); UT_SetDefaultReturnValue(UT_KEY(OCS_open), -1); @@ -154,6 +184,10 @@ void Test_OS_FileSysUnmountVolume_Impl(void) UT_SetDefaultReturnValue(UT_KEY(OCS_ioctl), -1); OSAPI_TEST_FUNCTION_RC(OS_FileSysUnmountVolume_Impl(&token), OS_ERROR); UT_ClearForceFail(UT_KEY(OCS_ioctl)); + + /* Additional cases for the FS_BASED handling (no op on unmount) */ + OS_filesys_table[0].fstype = OS_FILESYS_TYPE_FS_BASED; + OSAPI_TEST_FUNCTION_RC(OS_FileSysUnmountVolume_Impl(&token), OS_SUCCESS); } void Test_OS_FileSysStatVolume_Impl(void) diff --git a/src/unit-test-coverage/vxworks/src/coveragetest-idmap.c b/src/unit-test-coverage/vxworks/src/coveragetest-idmap.c index 89f140b4c..e97635900 100644 --- a/src/unit-test-coverage/vxworks/src/coveragetest-idmap.c +++ b/src/unit-test-coverage/vxworks/src/coveragetest-idmap.c @@ -41,22 +41,13 @@ void Test_OS_Lock_Global_Impl(void) * Test Case For: * int32 OS_Lock_Global_Impl(uint32 idtype) */ - OSAPI_TEST_FUNCTION_RC(OS_Lock_Global_Impl(10000), OS_ERROR); - - /* - * Confirm that if vxid is 0/NULL that the function returns error - * and does not call semTake. - */ - UT_IdMapTest_SetImplTableMutex(OS_OBJECT_TYPE_OS_TASK, (OCS_SEM_ID)0); - OSAPI_TEST_FUNCTION_RC(OS_Lock_Global_Impl(OS_OBJECT_TYPE_OS_TASK), OS_ERROR); - UtAssert_True(UT_GetStubCount(UT_KEY(OCS_semTake)) == 0, "semTake() NOT called"); UT_IdMapTest_SetImplTableMutex(OS_OBJECT_TYPE_OS_TASK, &TestGlobalSem); - OSAPI_TEST_FUNCTION_RC(OS_Lock_Global_Impl(OS_OBJECT_TYPE_OS_TASK), OS_SUCCESS); + OS_Lock_Global_Impl(OS_OBJECT_TYPE_OS_TASK); UtAssert_True(UT_GetStubCount(UT_KEY(OCS_semTake)) == 1, "semTake() called"); UT_SetDefaultReturnValue(UT_KEY(OCS_semTake), -1); - OSAPI_TEST_FUNCTION_RC(OS_Lock_Global_Impl(OS_OBJECT_TYPE_OS_TASK), OS_ERROR); + OS_Lock_Global_Impl(OS_OBJECT_TYPE_OS_TASK); /* for coverage of error path */ } void Test_OS_Unlock_Global_Impl(void) @@ -65,11 +56,13 @@ void Test_OS_Unlock_Global_Impl(void) * Test Case For: * int32 OS_Unlock_Global_Impl(uint32 idtype) */ - OSAPI_TEST_FUNCTION_RC(OS_Unlock_Global_Impl(10000), OS_ERROR); - OSAPI_TEST_FUNCTION_RC(OS_Unlock_Global_Impl(0), OS_ERROR); - OSAPI_TEST_FUNCTION_RC(OS_Unlock_Global_Impl(OS_OBJECT_TYPE_OS_TASK), OS_SUCCESS); + + UT_IdMapTest_SetImplTableMutex(OS_OBJECT_TYPE_OS_TASK, &TestGlobalSem); + OS_Unlock_Global_Impl(OS_OBJECT_TYPE_OS_TASK); + UtAssert_True(UT_GetStubCount(UT_KEY(OCS_semGive)) == 1, "semTake() called"); + UT_SetDefaultReturnValue(UT_KEY(OCS_semGive), -1); - OSAPI_TEST_FUNCTION_RC(OS_Unlock_Global_Impl(OS_OBJECT_TYPE_OS_TASK), OS_ERROR); + OS_Lock_Global_Impl(OS_OBJECT_TYPE_OS_TASK); /* for coverage of error path */ } void Test_OS_API_Impl_Init(void) diff --git a/src/unit-tests/oscore-test/ut_oscore_misc_test.c b/src/unit-tests/oscore-test/ut_oscore_misc_test.c index 5d45d0fc7..cb0527312 100644 --- a/src/unit-tests/oscore-test/ut_oscore_misc_test.c +++ b/src/unit-tests/oscore-test/ut_oscore_misc_test.c @@ -290,8 +290,8 @@ void UT_os_getlocaltime_test() for (i = 0; i < 5; i++) { UtPrintf("OS_GetLocalTime() - #3 Nominal "); - UtPrintf("[Expecting output after API call to increase over time: %ld.%ld]\n", (long)time_struct.seconds, - (long)time_struct.microsecs); + UtPrintf("[Expecting output after API call to increase over time: %ld.%ld]\n", + (long)OS_TimeGetTotalSeconds(time_struct), (long)OS_TimeGetMicrosecondsPart(time_struct)); OS_TaskDelay(20); OS_GetLocalTime(&time_struct); @@ -379,23 +379,21 @@ void UT_os_setlocaltime_test() for (i = 0; i < 5; i++) { UtPrintf("OS_SetLocalTime() - #3 Nominal "); - UtPrintf("[Expecting output before API call to increase over time: %ld.%ld]\n", (long)time_struct.seconds, - (long)time_struct.microsecs); + UtPrintf("[Expecting output before API call to increase over time: %ld.%ld]\n", + (long)OS_TimeGetTotalSeconds(time_struct), (long)OS_TimeGetMicrosecondsPart(time_struct)); OS_TaskDelay(20); OS_GetLocalTime(&time_struct); } } - memset(&time_struct, 0x00, sizeof(time_struct)); - time_struct.seconds = 20000; - time_struct.microsecs = 123; + time_struct = OS_TimeAssembleFromNanoseconds(20000, 123000); res = OS_SetLocalTime(&time_struct); if (res == OS_SUCCESS) { - UtPrintf("OS_SetLocalTime() - #3 Nominal [New time set at %ld.%ld]\n", (long)time_struct.seconds, - (long)time_struct.microsecs); + UtPrintf("OS_SetLocalTime() - #3 Nominal [New time set at %ld.%ld]\n", (long)OS_TimeGetTotalSeconds(time_struct), + (long)OS_TimeGetMicrosecondsPart(time_struct)); res = OS_GetLocalTime(&time_struct); if (res == OS_SUCCESS) @@ -404,7 +402,7 @@ void UT_os_setlocaltime_test() { UtPrintf("OS_SetLocalTime() - #3 Nominal "); UtPrintf("[Expecting output after API call to increase over time: %ld.%ld]\n", - (long)time_struct.seconds, (long)time_struct.microsecs); + (long)OS_TimeGetTotalSeconds(time_struct), (long)OS_TimeGetMicrosecondsPart(time_struct)); OS_TaskDelay(20); OS_GetLocalTime(&time_struct); diff --git a/src/unit-tests/osfilesys-test/ut_osfilesys_diskio_test.c b/src/unit-tests/osfilesys-test/ut_osfilesys_diskio_test.c index ebbc668b8..410e1efbf 100644 --- a/src/unit-tests/osfilesys-test/ut_osfilesys_diskio_test.c +++ b/src/unit-tests/osfilesys-test/ut_osfilesys_diskio_test.c @@ -1271,6 +1271,123 @@ void UT_os_fsbytesfree_test() return; } +/*--------------------------------------------------------------------------------* +** Syntax: int32 OS_fsstatvolume(const char *name) +** Purpose: Returns the number of blocks free in a the file system +** Parameters: *name - a pointer to the name of the drive to check for free blocks +** Returns: OS_INVALID_POINTER if the pointer passed in is NULL +** OS_FS_ERR_PATH_TOO_LONG if the path passed in is too long +** OS_ERROR if the OS call failed +** Number of blocks free in a volume if succeeded +** OS_ERR_NOT_IMPLEMENTED if not implemented +** ----------------------------------------------------- +** Test #0: Not-implemented condition +** 1) Call this routine +** 2) If the returned value is OS_ERR_NOT_IMPLEMENTED, then exit test +** 3) Otherwise, continue. +** ----------------------------------------------------- +** Test #1: Null-pointer-arg condition +** 1) Call this routine with a null pointer as one of the arguments +** 2) Expect the returned value to be +** (a) OS_INVALID_POINTER +** ----------------------------------------------------- +** Test #2: Path-too-long-arg condition +** 1) Call this routine with a path name of length greater than Volume table's +** name as argument +** 2) Expect the returned value to be +** (a) OS_FS_ERR_PATH_TOO_LONG +** ----------------------------------------------------- +** Test #3: OS-call-failure condition +** 1) Setup the test to cause the OS call to fail inside this routine +** 2) Call this routine +** 3) Expect the returned value to be +** (a) OS_ERROR +** ----------------------------------------------------- +** Test#4: Nominal condition +** 1) Make sure no file system has been previously created +** 2) Call OS_mkfs +** 3) Expect the returned value to be +** (a) OS_SUCCESS +** 4) Call OS_mount with device name used in #2 +** 5) Expect the returned value to be +** (a) OS_SUCCESS +** 6) Call this routine with mount-point used in #4 +** 7) Expect the returned value to be +** (a) greater than or equal to 0 +** --------------------------------------------------------------------------------*/ +void UT_os_fsstatvolume_test(void) +{ + const char * testDesc; + OS_statvfs_t statbuf; + + /*-----------------------------------------------------*/ + testDesc = "API not implemented"; + + if (OS_FileSysStatVolume("/cf", &statbuf) == OS_ERR_NOT_IMPLEMENTED) + { + UT_OS_TEST_RESULT(testDesc, UTASSERT_CASETYPE_NA); + goto UT_os_fsstatvolume_test_exit_tag; + } + + /*-----------------------------------------------------*/ + testDesc = "#1a Null-pointer-arg"; + + if (OS_FileSysStatVolume(NULL, &statbuf) == OS_INVALID_POINTER) + UT_OS_TEST_RESULT(testDesc, UTASSERT_CASETYPE_PASS); + else + UT_OS_TEST_RESULT(testDesc, UTASSERT_CASETYPE_FAILURE); + + /*-----------------------------------------------------*/ + testDesc = "#1b Null-pointer-arg"; + + if (OS_FileSysStatVolume("/cf", NULL) == OS_INVALID_POINTER) + UT_OS_TEST_RESULT(testDesc, UTASSERT_CASETYPE_PASS); + else + UT_OS_TEST_RESULT(testDesc, UTASSERT_CASETYPE_FAILURE); + + /*-----------------------------------------------------*/ + testDesc = "#2 Path-too-long-arg"; + + if (OS_FileSysStatVolume(g_fsLongName, &statbuf) == OS_FS_ERR_PATH_TOO_LONG) + UT_OS_TEST_RESULT(testDesc, UTASSERT_CASETYPE_PASS); + else + UT_OS_TEST_RESULT(testDesc, UTASSERT_CASETYPE_FAILURE); + + /*-----------------------------------------------------*/ + testDesc = "#3 OS-call-failure"; + + UT_OS_TEST_RESULT(testDesc, UTASSERT_CASETYPE_INFO); + + /*-----------------------------------------------------*/ + testDesc = "#4 Nominal"; + + if (OS_mkfs(g_fsAddrPtr, g_devNames[4], g_volNames[4], g_blkSize, g_blkCnt) != OS_SUCCESS) + { + testDesc = "#4 Nominal - File-system-create failed"; + UT_OS_TEST_RESULT(testDesc, UTASSERT_CASETYPE_TSF); + goto UT_os_fsstatvolume_test_exit_tag; + } + + if (OS_mount(g_devNames[4], g_mntNames[4]) != OS_SUCCESS) + { + testDesc = "#4 Nominal - File-system-mount failed"; + UT_OS_TEST_RESULT(testDesc, UTASSERT_CASETYPE_TSF); + goto UT_os_fsstatvolume_test_exit_tag; + } + + if (OS_FileSysStatVolume(g_mntNames[4], &statbuf) >= 0) + UT_OS_TEST_RESULT(testDesc, UTASSERT_CASETYPE_PASS); + else + UT_OS_TEST_RESULT(testDesc, UTASSERT_CASETYPE_FAILURE); + + /* Reset test environment */ + OS_unmount(g_mntNames[4]); + OS_rmfs(g_devNames[4]); + +UT_os_fsstatvolume_test_exit_tag: + return; +} + /*================================================================================* ** End of File: ut_osfilesys_diskio_test.c **================================================================================*/ diff --git a/src/unit-tests/osfilesys-test/ut_osfilesys_diskio_test.h b/src/unit-tests/osfilesys-test/ut_osfilesys_diskio_test.h index c6ab2dd2a..f1420c68c 100644 --- a/src/unit-tests/osfilesys-test/ut_osfilesys_diskio_test.h +++ b/src/unit-tests/osfilesys-test/ut_osfilesys_diskio_test.h @@ -71,6 +71,7 @@ void UT_os_checkfs_test(void); void UT_os_fsblocksfree_test(void); void UT_os_fsbytesfree_test(void); +void UT_os_fsstatvolume_test(void); /*--------------------------------------------------------------------------------*/ diff --git a/src/unit-tests/osfilesys-test/ut_osfilesys_test.c b/src/unit-tests/osfilesys-test/ut_osfilesys_test.c index 16a147d97..3850eff52 100644 --- a/src/unit-tests/osfilesys-test/ut_osfilesys_test.c +++ b/src/unit-tests/osfilesys-test/ut_osfilesys_test.c @@ -137,6 +137,7 @@ void UtTest_Setup(void) UtTest_Add(UT_os_checkfs_test, NULL, NULL, "OS_chkfs"); UtTest_Add(UT_os_fsblocksfree_test, NULL, NULL, "OS_fsBlocksFree"); UtTest_Add(UT_os_fsbytesfree_test, NULL, NULL, "OS_fsBytesFree"); + UtTest_Add(UT_os_fsstatvolume_test, NULL, NULL, "OS_FileSysStatVolume"); } /*================================================================================* diff --git a/src/unit-tests/ostimer-test/ut_ostimer_test.c b/src/unit-tests/ostimer-test/ut_ostimer_test.c index 6b6716f37..dcbe25d10 100644 --- a/src/unit-tests/ostimer-test/ut_ostimer_test.c +++ b/src/unit-tests/ostimer-test/ut_ostimer_test.c @@ -78,7 +78,7 @@ void UT_os_timercallback(osal_id_t timerId) static int32 loopCnt = 0, res = 0; static uint32 prevIntervalTime = 0; static uint32 currIntervalTime = 0; - static OS_time_t currTime = {0, 0}, endTime = {0, 0}; + static OS_time_t currTime = {0}, endTime = {0}; if (OS_ObjectIdEqual(timerId, g_timerId)) { @@ -94,7 +94,7 @@ void UT_os_timercallback(osal_id_t timerId) OS_GetLocalTime(&endTime); - currIntervalTime = 1000000 * (endTime.seconds - currTime.seconds) + endTime.microsecs - currTime.microsecs; + currIntervalTime = OS_TimeGetTotalMicroseconds(OS_TimeSubtract(endTime, currTime)); if (currIntervalTime >= prevIntervalTime) deltaTime = currIntervalTime - prevIntervalTime; diff --git a/src/ut-stubs/osapi-utstub-clock.c b/src/ut-stubs/osapi-utstub-clock.c index 37686f582..b13ce4798 100644 --- a/src/ut-stubs/osapi-utstub-clock.c +++ b/src/ut-stubs/osapi-utstub-clock.c @@ -52,9 +52,8 @@ int32 OS_GetLocalTime(OS_time_t *time_struct) if (status == OS_SUCCESS && UT_Stub_CopyToLocal(UT_KEY(OS_GetLocalTime), time_struct, sizeof(*time_struct)) < sizeof(*time_struct)) { - count = UT_GetStubCount(UT_KEY(OS_GetLocalTime)); - time_struct->microsecs = 10000 * (count % 100); - time_struct->seconds = 1 + (count / 100); + count = UT_GetStubCount(UT_KEY(OS_GetLocalTime)); + *time_struct = OS_TimeAssembleFromNanoseconds(1 + (count / 100), 10000000 * (count % 100)); } return status; @@ -66,7 +65,7 @@ int32 OS_GetLocalTime(OS_time_t *time_struct) * Stub function for OS_SetLocalTime() * *****************************************************************************/ -int32 OS_SetLocalTime(OS_time_t *time_struct) +int32 OS_SetLocalTime(const OS_time_t *time_struct) { UT_Stub_RegisterContext(UT_KEY(OS_SetLocalTime), time_struct); diff --git a/src/ut-stubs/osapi-utstub-filesys.c b/src/ut-stubs/osapi-utstub-filesys.c index 02188510c..b696751e5 100644 --- a/src/ut-stubs/osapi-utstub-filesys.c +++ b/src/ut-stubs/osapi-utstub-filesys.c @@ -192,6 +192,28 @@ int32 OS_fsBytesFree(const char *name, uint64 *bytes_free) return status; } +/***************************************************************************** + * + * Stub function for OS_FileSysStatVolume() + * + *****************************************************************************/ +int32 OS_FileSysStatVolume(const char *name, OS_statvfs_t *statbuf) +{ + UT_Stub_RegisterContext(UT_KEY(OS_FileSysStatVolume), name); + UT_Stub_RegisterContext(UT_KEY(OS_FileSysStatVolume), statbuf); + + int32 status; + + status = UT_DEFAULT_IMPL(OS_FileSysStatVolume); + + if (status == OS_SUCCESS && UT_Stub_CopyToLocal(UT_KEY(OS_FileSysStatVolume), statbuf, sizeof(*statbuf)) < sizeof(*statbuf)) + { + memset(statbuf, 0, sizeof(*statbuf)); + } + + return status; +} + /***************************************************************************** * * Stub function for OS_chkfs() diff --git a/src/ut-stubs/osapi-utstub-idmap.c b/src/ut-stubs/osapi-utstub-idmap.c index 3c9972b9b..4b2bd3992 100644 --- a/src/ut-stubs/osapi-utstub-idmap.c +++ b/src/ut-stubs/osapi-utstub-idmap.c @@ -54,11 +54,11 @@ static void UT_TokenCompose(uint32 lock_mode, uint32 indx, UT_ObjType_t objtype, UT_DEFAULT_STUB(OS_ObjectIdInit, (void)) /* Lock/Unlock for global tables */ -void OS_Lock_Global(osal_objtype_t idtype) +void OS_Lock_Global(OS_object_token_t *token) { UT_DEFAULT_IMPL(OS_Lock_Global); } -void OS_Unlock_Global(osal_objtype_t idtype) +void OS_Unlock_Global(OS_object_token_t *token) { UT_DEFAULT_IMPL(OS_Unlock_Global); } @@ -212,6 +212,36 @@ int32 OS_ObjectIdGetBySearch(OS_lock_mode_t lock_mode, osal_objtype_t idtype, OS return Status; } +/***************************************************************************** + * + * Stub function for OS_ObjectIdTransactionInit() + * + *****************************************************************************/ +int32 OS_ObjectIdTransactionInit(OS_lock_mode_t lock_mode, osal_objtype_t idtype, OS_object_token_t *token) +{ + int32 Status; + + Status = UT_DEFAULT_IMPL(OS_ObjectIdTransactionInit); + + if (Status == OS_SUCCESS && + UT_Stub_CopyToLocal(UT_KEY(OS_ObjectIdTransactionInit), token, sizeof(*token)) < sizeof(*token)) + { + memset(&token, 0, sizeof(token)); + } + + return Status; +} + +/***************************************************************************** + * + * Stub function for OS_ObjectIdTransactionCancel() + * + *****************************************************************************/ +void OS_ObjectIdTransactionCancel(OS_object_token_t *token) +{ + UT_DEFAULT_IMPL(OS_ObjectIdTransactionCancel); +} + /***************************************************************************** * * Stub function for OS_ObjectIdFindByName() @@ -573,7 +603,7 @@ void OS_ObjectIdIteratorDestroy(OS_object_iter_t *iter) UT_DEFAULT_IMPL(OS_ObjectIdIteratorDestroy); } -int32 OS_ObjectIdIteratorProcessEntry(OS_object_iter_t *iter, int32 (*func)(osal_id_t)) +int32 OS_ObjectIdIteratorProcessEntry(OS_object_iter_t *iter, int32 (*func)(osal_id_t, void*)) { int32 Status;