Initial contribution

This commit is contained in:
Michiel Beemster 2018-04-10 17:03:59 +02:00
parent 7b5cc4fa59
commit 11d9ce37aa
580 changed files with 155133 additions and 162 deletions

61
src/os/CMakeLists.txt Normal file
View file

@ -0,0 +1,61 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
string(TOLOWER ${CMAKE_SYSTEM_NAME} platform)
# For posix platforms include the files in the posix/ directory.
set (posix_platforms darwin linux)
IF(${platform} IN_LIST posix_platforms)
set(platform posix)
ENDIF()
PREPEND(srcs_platform ${platform} os_platform_errno.c os_platform_heap.c os_platform_init.c os_platform_process.c os_platform_socket.c os_platform_stdlib.c os_platform_sync.c os_platform_thread.c os_platform_time.c)
include (GenerateExportHeader)
PREPEND(srcs_os "${CMAKE_CURRENT_SOURCE_DIR}/src" os_atomics.c os_init.c os_process.c os_report.c os_socket.c os_thread.c os_time.c os_errno.c os_iter.c ${srcs_platform})
add_library(OSAPI ${srcs_os})
configure_file(
"${CMAKE_CURRENT_LIST_DIR}/cmake/os_project.h.in"
"include/os/os_project.h")
generate_export_header(OSAPI EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/exports/os/osapi_export.h")
target_link_libraries(OSAPI INTERFACE Abstraction)
target_include_directories(OSAPI PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/>" "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/exports/>"
"$<INSTALL_INTERFACE:${INSTALL_PREFIX}/include/>" "$<INSTALL_INTERFACE:${INSTALL_PREFIX}/exports/>")
target_sources(OSAPI PRIVATE "include/os/os_project.h")
target_include_directories(OSAPI
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include/>")
# "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>")
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
install(
FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/os/os_public.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/os/os_decl_attributes.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/os/os_decl_attributes_sal.h"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/os"
COMPONENT dev)
# Currently, only windows and posix platforms are supported.
IF(WIN32 AND NOT UNIX)
install(
FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/os/windows/os_platform_public.h"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/os"
COMPONENT dev)
ELSE()
install(
FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/os/posix/os_platform_public.h"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/os"
COMPONENT dev)
ENDIF()

View file

@ -0,0 +1,25 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PROJECT_H
#define OS_PROJECT_H
#define OS_VERSION "@CycloneDDS_VERSION@"
#define OS_VERSION_MAJOR @CycloneDDS_VERSION_MAJOR@
#define OS_VERSION_MINOR @CycloneDDS_VERSION_MINOR@
#define OS_VERSION_PATCH @CycloneDDS_VERSION_PATCH@
#define OS_VERSION_TWEAK @CycloneDDS_VERSION_TWEAK@
#define OS_PROJECT_NAME_NOSPACE_CAPS "@CMAKE_PROJECT_NAME_CAPS@"
#define OS_PROJECT_NAME_NOSPACE_SMALL "@CMAKE_PROJECT_NAME_SMALL@"
#define OS_PROJECT_NAME_NOSPACE "@CMAKE_PROJECT_NAME@"
#define OS_PROJECT_NAME "@CMAKE_PROJECT_NAME@"
#endif /* OS_PROJECT_H */

View file

@ -0,0 +1,66 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_H
#define OS_PLATFORM_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <inttypes.h>
#include <machine/endian.h>
#include <sys/stat.h>
#include <unistd.h>
#define PRIdSIZE "zd"
#define PRIuSIZE "zu"
#define PRIxSIZE "zx"
#if defined (__cplusplus)
extern "C" {
#endif
#define OS_DARWIN 1
#define OS_SOCKET_USE_FCNTL 1
#define OS_SOCKET_USE_IOCTL 0
#define OS_HAS_UCONTEXT_T 1
#define OS_FILESEPCHAR '/'
#define OS_HAS_NO_SET_NAME_PRCTL 1
#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
#define OS_ENDIANNESS OS_LITTLE_ENDIAN
#else
#define OS_ENDIANNESS OS_BIG_ENDIAN
#endif
#ifdef _LP64
#define OS_64BIT
#endif
typedef double os_timeReal;
typedef int os_timeSec;
typedef uid_t os_uid;
typedef gid_t os_gid;
typedef mode_t os_mode_t;
typedef pid_t os_procId;
#define PRIprocId "d"
#include "os/posix/os_platform_socket.h"
#include "os/posix/os_platform_sync.h"
#include "os/posix/os_platform_thread.h"
#include "os/posix/os_platform_stdlib.h"
#include "os/posix/os_platform_process.h"
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,62 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_H
#define OS_PLATFORM_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <inttypes.h>
#include <endian.h>
#include <sys/stat.h>
#include <unistd.h>
#define PRIdSIZE "zd"
#define PRIuSIZE "zu"
#define PRIxSIZE "zx"
#if defined (__cplusplus)
extern "C" {
#endif
#define OS_LINUX 1
#define OS_SOCKET_USE_FCNTL 1
#define OS_SOCKET_USE_IOCTL 0
#define OS_HAS_UCONTEXT_T 1
#define OS_FILESEPCHAR '/'
#define OS_HAS_NO_SET_NAME_PRCTL 1
#define OS_ENDIANNESS OS_LITTLE_ENDIAN
#ifdef _LP64
#define OS_64BIT
#endif
typedef double os_timeReal;
typedef int os_timeSec;
typedef uid_t os_uid;
typedef gid_t os_gid;
typedef mode_t os_mode_t;
typedef pid_t os_procId;
#define PRIprocId "d"
#include "os/posix/os_platform_socket.h"
#include "os/posix/os_platform_sync.h"
#include "os/posix/os_platform_thread.h"
#include "os/posix/os_platform_stdlib.h"
#include "os/posix/os_platform_process.h"
#if defined (__cplusplus)
}
#endif
#endif

65
src/os/include/os/os.h Normal file
View file

@ -0,0 +1,65 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_H
#define OS_H
#include "os/osapi_export.h"
#include "os_public.h"
#if __linux__ == 1
#include "linux/os_platform.h"
#elif defined(__VXWORKS__)
#include "vxworks/os_platform.h"
#elif __sun == 1
#include "solaris/os_platform.h"
#elif defined(__INTEGRITY)
#include "integrity/os_platform.h"
#elif __PikeOS__ == 1
#include "pikeos3/os_platform.h"
#elif defined(__QNX__)
#include "qnx/os_platform.h"
#elif defined(_MSC_VER)
#ifdef _WIN32_WCE
#include "wince/os_platform.h"
#else
#include "windows/os_platform.h"
#endif
#elif defined __APPLE__
#include "darwin/os_platform.h"
#elif defined __CYGWIN__
#include "cygwin/os_platform.h"
#else
#error "Platform missing from os.h list"
#endif
#include "os_defs.h"
#include "os_thread.h"
#include "os_sync.h"
#include "os_time.h"
#include "os_atomics.h"
#include "os_socket.h"
#include "os_heap.h"
#include "os_stdlib.h"
#include "os_report.h"
#include "os_init.h"
#include "os_process.h"
#include "os_errno.h"
#include "os_iter.h"
#define OSPL_VERSION_STR "aap"
#define OSPL_HOST_STR "noot"
#define OSPL_TARGET_STR "mies"
#define OSPL_INNER_REV_STR "wim"
#define OSPL_OUTER_REV_STR "zus"
#endif

View file

@ -0,0 +1,198 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_ATOMICS_H
#define OS_ATOMICS_H
#include <stddef.h>
#include <limits.h>
#include "os/os_defs.h"
#if defined (__cplusplus)
extern "C" {
#endif
/* Note: os_atomics_inlines.c overrules OS_HAVE_INLINE, VDDS_INLINE and
OS_ATOMICS_OMIT_FUNCTIONS */
#if ! OS_HAVE_INLINE && ! defined OS_ATOMICS_OMIT_FUNCTIONS
#define OS_ATOMICS_OMIT_FUNCTIONS 1
#endif
#if ! OS_ATOMIC_SUPPORT && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40100
#include "os/os_atomics_gcc.h"
#endif
#if ! OS_ATOMIC_SUPPORT && defined _WIN32
/* Windows.h causes HUGE problems when included too early, primarily
because you can't include only a subset and later include the rest
*/
#undef OS_HAVE_INLINE
#undef VDDS_INLINE
#define VDDS_INLINE
#include "os_atomics_win32.h"
#endif
#if ! OS_ATOMIC_SUPPORT && defined __sun
#include "os_atomics_solaris.h"
#endif
#if ! OS_ATOMIC_SUPPORT && defined __INTEGRITY
#include "os_atomics_integrity.h"
#endif
#if ! OS_ATOMIC_SUPPORT && defined __VXWORKS__
#include "os_atomics_vxworks.h"
#endif
#if ! OS_ATOMIC_SUPPORT && defined __GNUC__ && defined __i386
#include "os_atomics_gcc_x86.h"
#endif
#if ! OS_ATOMIC_SUPPORT && \
((defined __GNUC__ && defined __ppc) || \
(defined __vxworks && defined __PPC__))
/* VxWorks uses GCC but removed the __GNUC__ macro ... */
#include "os_atomics_gcc_ppc.h"
#endif
#if ! OS_ATOMIC_SUPPORT && defined __GNUC__ && defined __sparc__
#include "os_atomics_gcc_sparc.h"
#endif
#if ! OS_ATOMIC_SUPPORT && defined __GNUC__ && defined __arm__
#include "os_atomics_gcc_arm.h"
#endif
#if ! OS_ATOMIC_SUPPORT
#error "No support for atomic operations on this platform"
#endif
#if ! OS_HAVE_INLINE
/* LD, ST */
OSAPI_EXPORT uint32_t os_atomic_ld32 (const volatile os_atomic_uint32_t *x);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT uint64_t os_atomic_ld64 (const volatile os_atomic_uint64_t *x);
#endif
OSAPI_EXPORT uintptr_t os_atomic_ldptr (const volatile os_atomic_uintptr_t *x);
OSAPI_EXPORT void *os_atomic_ldvoidp (const volatile os_atomic_voidp_t *x);
OSAPI_EXPORT void os_atomic_st32 (volatile os_atomic_uint32_t *x, uint32_t v);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT void os_atomic_st64 (volatile os_atomic_uint64_t *x, uint64_t v);
#endif
OSAPI_EXPORT void os_atomic_stptr (volatile os_atomic_uintptr_t *x, uintptr_t v);
OSAPI_EXPORT void os_atomic_stvoidp (volatile os_atomic_voidp_t *x, void *v);
/* INC */
OSAPI_EXPORT void os_atomic_inc32 (volatile os_atomic_uint32_t *x);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT void os_atomic_inc64 (volatile os_atomic_uint64_t *x);
#endif
OSAPI_EXPORT void os_atomic_incptr (volatile os_atomic_uintptr_t *x);
OSAPI_EXPORT uint32_t os_atomic_inc32_nv (volatile os_atomic_uint32_t *x);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT uint64_t os_atomic_inc64_nv (volatile os_atomic_uint64_t *x);
#endif
OSAPI_EXPORT uintptr_t os_atomic_incptr_nv (volatile os_atomic_uintptr_t *x);
/* DEC */
OSAPI_EXPORT void os_atomic_dec32 (volatile os_atomic_uint32_t *x);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT void os_atomic_dec64 (volatile os_atomic_uint64_t *x);
#endif
OSAPI_EXPORT void os_atomic_decptr (volatile os_atomic_uintptr_t *x);
OSAPI_EXPORT uint32_t os_atomic_dec32_nv (volatile os_atomic_uint32_t *x);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT uint64_t os_atomic_dec64_nv (volatile os_atomic_uint64_t *x);
#endif
OSAPI_EXPORT uintptr_t os_atomic_decptr_nv (volatile os_atomic_uintptr_t *x);
OSAPI_EXPORT uint32_t os_atomic_dec32_ov (volatile os_atomic_uint32_t *x);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT uint64_t os_atomic_dec64_ov (volatile os_atomic_uint64_t *x);
#endif
OSAPI_EXPORT uintptr_t os_atomic_decptr_ov (volatile os_atomic_uintptr_t *x);
/* ADD */
OSAPI_EXPORT void os_atomic_add32 (volatile os_atomic_uint32_t *x, uint32_t v);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT void os_atomic_add64 (volatile os_atomic_uint64_t *x, uint64_t v);
#endif
OSAPI_EXPORT void os_atomic_addptr (volatile os_atomic_uintptr_t *x, uintptr_t v);
OSAPI_EXPORT void os_atomic_addvoidp (volatile os_atomic_voidp_t *x, ptrdiff_t v);
OSAPI_EXPORT uint32_t os_atomic_add32_nv (volatile os_atomic_uint32_t *x, uint32_t v);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT uint64_t os_atomic_add64_nv (volatile os_atomic_uint64_t *x, uint64_t v);
#endif
OSAPI_EXPORT uintptr_t os_atomic_addptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v);
OSAPI_EXPORT void *os_atomic_addvoidp_nv (volatile os_atomic_voidp_t *x, ptrdiff_t v);
/* SUB */
OSAPI_EXPORT void os_atomic_sub32 (volatile os_atomic_uint32_t *x, uint32_t v);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT void os_atomic_sub64 (volatile os_atomic_uint64_t *x, uint64_t v);
#endif
OSAPI_EXPORT void os_atomic_subptr (volatile os_atomic_uintptr_t *x, uintptr_t v);
OSAPI_EXPORT void os_atomic_subvoidp (volatile os_atomic_voidp_t *x, ptrdiff_t v);
OSAPI_EXPORT uint32_t os_atomic_sub32_nv (volatile os_atomic_uint32_t *x, uint32_t v);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT uint64_t os_atomic_sub64_nv (volatile os_atomic_uint64_t *x, uint64_t v);
#endif
OSAPI_EXPORT uintptr_t os_atomic_subptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v);
OSAPI_EXPORT void *os_atomic_subvoidp_nv (volatile os_atomic_voidp_t *x, ptrdiff_t v);
/* AND */
OSAPI_EXPORT void os_atomic_and32 (volatile os_atomic_uint32_t *x, uint32_t v);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT void os_atomic_and64 (volatile os_atomic_uint64_t *x, uint64_t v);
#endif
OSAPI_EXPORT void os_atomic_andptr (volatile os_atomic_uintptr_t *x, uintptr_t v);
OSAPI_EXPORT uint32_t os_atomic_and32_ov (volatile os_atomic_uint32_t *x, uint32_t v);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT uint64_t os_atomic_and64_ov (volatile os_atomic_uint64_t *x, uint64_t v);
#endif
OSAPI_EXPORT uintptr_t os_atomic_andptr_ov (volatile os_atomic_uintptr_t *x, uintptr_t v);
OSAPI_EXPORT uint32_t os_atomic_and32_nv (volatile os_atomic_uint32_t *x, uint32_t v);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT uint64_t os_atomic_and64_nv (volatile os_atomic_uint64_t *x, uint64_t v);
#endif
OSAPI_EXPORT uintptr_t os_atomic_andptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v);
/* OR */
OSAPI_EXPORT void os_atomic_or32 (volatile os_atomic_uint32_t *x, uint32_t v);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT void os_atomic_or64 (volatile os_atomic_uint64_t *x, uint64_t v);
#endif
OSAPI_EXPORT void os_atomic_orptr (volatile os_atomic_uintptr_t *x, uintptr_t v);
OSAPI_EXPORT uint32_t os_atomic_or32_ov (volatile os_atomic_uint32_t *x, uint32_t v);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT uint64_t os_atomic_or64_ov (volatile os_atomic_uint64_t *x, uint64_t v);
#endif
OSAPI_EXPORT uintptr_t os_atomic_orptr_ov (volatile os_atomic_uintptr_t *x, uintptr_t v);
OSAPI_EXPORT uint32_t os_atomic_or32_nv (volatile os_atomic_uint32_t *x, uint32_t v);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT uint64_t os_atomic_or64_nv (volatile os_atomic_uint64_t *x, uint64_t v);
#endif
OSAPI_EXPORT uintptr_t os_atomic_orptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v);
/* CAS */
OSAPI_EXPORT int os_atomic_cas32 (volatile os_atomic_uint32_t *x, uint32_t exp, uint32_t des);
#if OS_ATOMIC64_SUPPORT
OSAPI_EXPORT int os_atomic_cas64 (volatile os_atomic_uint64_t *x, uint64_t exp, uint64_t des);
#endif
OSAPI_EXPORT int os_atomic_casptr (volatile os_atomic_uintptr_t *x, uintptr_t exp, uintptr_t des);
OSAPI_EXPORT int os_atomic_casvoidp (volatile os_atomic_voidp_t *x, void *exp, void *des);
/* FENCES */
OSAPI_EXPORT void os_atomic_fence (void);
OSAPI_EXPORT void os_atomic_fence_acq (void);
OSAPI_EXPORT void os_atomic_fence_rel (void);
#endif /* OS_HAVE_INLINE */
#if defined (__cplusplus)
}
#endif
#endif /* OS_ATOMICS_H */

View file

@ -0,0 +1,344 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40100
/* I don't quite know how to check whether 64-bit operations are
supported, but my guess is that the size of a pointer is a fairly
good indication. Define OS_ATOMIC_ATOMIC64_SUPPORT beforehand to override
this. (Obviously, I'm also assuming that uintptr_t is an unsigned
integer exactly as wide as a pointer, even though it may be
wider.) */
#ifndef OS_ATOMIC64_SUPPORT
#ifdef OS_64BIT
#define OS_ATOMIC64_SUPPORT 1
#else
#define OS_ATOMIC64_SUPPORT 0
#endif
#endif
#if ! OS_ATOMICS_OMIT_FUNCTIONS
/* Eliminate C warnings */
#if ! defined (__cplusplus)
VDDS_INLINE uint32_t os_atomic_ld32 (const volatile os_atomic_uint32_t *x);
VDDS_INLINE uintptr_t os_atomic_ldptr (const volatile os_atomic_uintptr_t *x);
VDDS_INLINE void *os_atomic_ldvoidp (const volatile os_atomic_voidp_t *x);
VDDS_INLINE void os_atomic_st32 (volatile os_atomic_uint32_t *x, uint32_t v);
VDDS_INLINE void os_atomic_stptr (volatile os_atomic_uintptr_t *x, uintptr_t v);
VDDS_INLINE void os_atomic_stvoidp (volatile os_atomic_voidp_t *x, void *v);
VDDS_INLINE void os_atomic_inc32 (volatile os_atomic_uint32_t *x);
VDDS_INLINE void os_atomic_incptr (volatile os_atomic_uintptr_t *x);
VDDS_INLINE uint32_t os_atomic_inc32_nv (volatile os_atomic_uint32_t *x);
VDDS_INLINE uintptr_t os_atomic_incptr_nv (volatile os_atomic_uintptr_t *x);
VDDS_INLINE void os_atomic_dec32 (volatile os_atomic_uint32_t *x);
VDDS_INLINE void os_atomic_decptr (volatile os_atomic_uintptr_t *x);
VDDS_INLINE uint32_t os_atomic_dec32_nv (volatile os_atomic_uint32_t *x);
VDDS_INLINE uintptr_t os_atomic_decptr_nv (volatile os_atomic_uintptr_t *x);
VDDS_INLINE uint32_t os_atomic_dec32_ov (volatile os_atomic_uint32_t *x);
VDDS_INLINE uintptr_t os_atomic_decptr_ov (volatile os_atomic_uintptr_t *x);
VDDS_INLINE void os_atomic_add32 (volatile os_atomic_uint32_t *x, uint32_t v);
VDDS_INLINE void os_atomic_addptr (volatile os_atomic_uintptr_t *x, uintptr_t v);
VDDS_INLINE void os_atomic_addvoidp (volatile os_atomic_voidp_t *x, ptrdiff_t v);
VDDS_INLINE uint32_t os_atomic_add32_nv (volatile os_atomic_uint32_t *x, uint32_t v);
VDDS_INLINE uintptr_t os_atomic_addptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v);
VDDS_INLINE void *os_atomic_addvoidp_nv (volatile os_atomic_voidp_t *x, ptrdiff_t v);
VDDS_INLINE void os_atomic_sub32 (volatile os_atomic_uint32_t *x, uint32_t v);
VDDS_INLINE void os_atomic_subptr (volatile os_atomic_uintptr_t *x, uintptr_t v);
VDDS_INLINE void os_atomic_subvoidp (volatile os_atomic_voidp_t *x, ptrdiff_t v);
VDDS_INLINE uint32_t os_atomic_sub32_nv (volatile os_atomic_uint32_t *x, uint32_t v);
VDDS_INLINE uintptr_t os_atomic_subptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v);
VDDS_INLINE void *os_atomic_subvoidp_nv (volatile os_atomic_voidp_t *x, ptrdiff_t v);
VDDS_INLINE void os_atomic_and32 (volatile os_atomic_uint32_t *x, uint32_t v);
VDDS_INLINE void os_atomic_andptr (volatile os_atomic_uintptr_t *x, uintptr_t v);
VDDS_INLINE uint32_t os_atomic_and32_ov (volatile os_atomic_uint32_t *x, uint32_t v);
VDDS_INLINE uintptr_t os_atomic_andptr_ov (volatile os_atomic_uintptr_t *x, uintptr_t v);
VDDS_INLINE uint32_t os_atomic_and32_nv (volatile os_atomic_uint32_t *x, uint32_t v);
VDDS_INLINE uintptr_t os_atomic_andptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v);
VDDS_INLINE void os_atomic_or32 (volatile os_atomic_uint32_t *x, uint32_t v);
VDDS_INLINE void os_atomic_orptr (volatile os_atomic_uintptr_t *x, uintptr_t v);
VDDS_INLINE uint32_t os_atomic_or32_ov (volatile os_atomic_uint32_t *x, uint32_t v);
VDDS_INLINE uintptr_t os_atomic_orptr_ov (volatile os_atomic_uintptr_t *x, uintptr_t v);
VDDS_INLINE uint32_t os_atomic_or32_nv (volatile os_atomic_uint32_t *x, uint32_t v);
VDDS_INLINE uintptr_t os_atomic_orptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v);
VDDS_INLINE int os_atomic_cas32 (volatile os_atomic_uint32_t *x, uint32_t exp, uint32_t des);
VDDS_INLINE int os_atomic_casptr (volatile os_atomic_uintptr_t *x, uintptr_t exp, uintptr_t des);
VDDS_INLINE int os_atomic_casvoidp (volatile os_atomic_voidp_t *x, void *exp, void *des);
VDDS_INLINE void os_atomic_fence (void);
VDDS_INLINE void os_atomic_fence_acq (void);
VDDS_INLINE void os_atomic_fence_rel (void);
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE uint64_t os_atomic_ld64 (const volatile os_atomic_uint64_t *x);
VDDS_INLINE void os_atomic_st64 (volatile os_atomic_uint64_t *x, uint64_t v);
VDDS_INLINE void os_atomic_inc64 (volatile os_atomic_uint64_t *x);
VDDS_INLINE uint64_t os_atomic_inc64_nv (volatile os_atomic_uint64_t *x);
VDDS_INLINE void os_atomic_dec64 (volatile os_atomic_uint64_t *x);
VDDS_INLINE uint64_t os_atomic_dec64_nv (volatile os_atomic_uint64_t *x);
VDDS_INLINE uint64_t os_atomic_dec64_ov (volatile os_atomic_uint64_t *x);
VDDS_INLINE void os_atomic_add64 (volatile os_atomic_uint64_t *x, uint64_t v);
VDDS_INLINE uint64_t os_atomic_add64_nv (volatile os_atomic_uint64_t *x, uint64_t v);
VDDS_INLINE void os_atomic_sub64 (volatile os_atomic_uint64_t *x, uint64_t v);
VDDS_INLINE uint64_t os_atomic_sub64_nv (volatile os_atomic_uint64_t *x, uint64_t v);
VDDS_INLINE void os_atomic_and64 (volatile os_atomic_uint64_t *x, uint64_t v);
VDDS_INLINE uint64_t os_atomic_and64_ov (volatile os_atomic_uint64_t *x, uint64_t v);
VDDS_INLINE uint64_t os_atomic_and64_nv (volatile os_atomic_uint64_t *x, uint64_t v);
VDDS_INLINE void os_atomic_or64 (volatile os_atomic_uint64_t *x, uint64_t v);
VDDS_INLINE uint64_t os_atomic_or64_ov (volatile os_atomic_uint64_t *x, uint64_t v);
VDDS_INLINE uint64_t os_atomic_or64_nv (volatile os_atomic_uint64_t *x, uint64_t v);
VDDS_INLINE int os_atomic_cas64 (volatile os_atomic_uint64_t *x, uint64_t exp, uint64_t des);
#endif
#endif
/* LD, ST */
VDDS_INLINE uint32_t os_atomic_ld32 (const volatile os_atomic_uint32_t *x) { return x->v; }
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE uint64_t os_atomic_ld64 (const volatile os_atomic_uint64_t *x) { return x->v; }
#endif
VDDS_INLINE uintptr_t os_atomic_ldptr (const volatile os_atomic_uintptr_t *x) { return x->v; }
VDDS_INLINE void *os_atomic_ldvoidp (const volatile os_atomic_voidp_t *x) { return (void *) os_atomic_ldptr (x); }
VDDS_INLINE void os_atomic_st32 (volatile os_atomic_uint32_t *x, uint32_t v) { x->v = v; }
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE void os_atomic_st64 (volatile os_atomic_uint64_t *x, uint64_t v) { x->v = v; }
#endif
VDDS_INLINE void os_atomic_stptr (volatile os_atomic_uintptr_t *x, uintptr_t v) { x->v = v; }
VDDS_INLINE void os_atomic_stvoidp (volatile os_atomic_voidp_t *x, void *v) { os_atomic_stptr (x, (uintptr_t) v); }
/* INC */
VDDS_INLINE void os_atomic_inc32 (volatile os_atomic_uint32_t *x) {
__sync_fetch_and_add (&x->v, 1);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE void os_atomic_inc64 (volatile os_atomic_uint64_t *x) {
__sync_fetch_and_add (&x->v, 1);
}
#endif
VDDS_INLINE void os_atomic_incptr (volatile os_atomic_uintptr_t *x) {
__sync_fetch_and_add (&x->v, 1);
}
VDDS_INLINE uint32_t os_atomic_inc32_nv (volatile os_atomic_uint32_t *x) {
return __sync_add_and_fetch (&x->v, 1);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE uint64_t os_atomic_inc64_nv (volatile os_atomic_uint64_t *x) {
return __sync_add_and_fetch (&x->v, 1);
}
#endif
VDDS_INLINE uintptr_t os_atomic_incptr_nv (volatile os_atomic_uintptr_t *x) {
return __sync_add_and_fetch (&x->v, 1);
}
/* DEC */
VDDS_INLINE void os_atomic_dec32 (volatile os_atomic_uint32_t *x) {
__sync_fetch_and_sub (&x->v, 1);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE void os_atomic_dec64 (volatile os_atomic_uint64_t *x) {
__sync_fetch_and_sub (&x->v, 1);
}
#endif
VDDS_INLINE void os_atomic_decptr (volatile os_atomic_uintptr_t *x) {
__sync_fetch_and_sub (&x->v, 1);
}
VDDS_INLINE uint32_t os_atomic_dec32_nv (volatile os_atomic_uint32_t *x) {
return __sync_sub_and_fetch (&x->v, 1);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE uint64_t os_atomic_dec64_nv (volatile os_atomic_uint64_t *x) {
return __sync_sub_and_fetch (&x->v, 1);
}
#endif
VDDS_INLINE uintptr_t os_atomic_decptr_nv (volatile os_atomic_uintptr_t *x) {
return __sync_sub_and_fetch (&x->v, 1);
}
VDDS_INLINE uint32_t os_atomic_dec32_ov (volatile os_atomic_uint32_t *x) {
return __sync_fetch_and_sub (&x->v, 1);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE uint64_t os_atomic_dec64_ov (volatile os_atomic_uint64_t *x) {
return __sync_fetch_and_sub (&x->v, 1);
}
#endif
VDDS_INLINE uintptr_t os_atomic_decptr_ov (volatile os_atomic_uintptr_t *x) {
return __sync_fetch_and_sub (&x->v, 1);
}
/* ADD */
VDDS_INLINE void os_atomic_add32 (volatile os_atomic_uint32_t *x, uint32_t v) {
__sync_fetch_and_add (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE void os_atomic_add64 (volatile os_atomic_uint64_t *x, uint64_t v) {
__sync_fetch_and_add (&x->v, v);
}
#endif
VDDS_INLINE void os_atomic_addptr (volatile os_atomic_uintptr_t *x, uintptr_t v) {
__sync_fetch_and_add (&x->v, v);
}
VDDS_INLINE void os_atomic_addvoidp (volatile os_atomic_voidp_t *x, ptrdiff_t v) {
os_atomic_addptr ((volatile os_atomic_uintptr_t *) x, (uintptr_t) v);
}
VDDS_INLINE uint32_t os_atomic_add32_nv (volatile os_atomic_uint32_t *x, uint32_t v) {
return __sync_add_and_fetch (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE uint64_t os_atomic_add64_nv (volatile os_atomic_uint64_t *x, uint64_t v) {
return __sync_add_and_fetch (&x->v, v);
}
#endif
VDDS_INLINE uintptr_t os_atomic_addptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v) {
return __sync_add_and_fetch (&x->v, v);
}
VDDS_INLINE void *os_atomic_addvoidp_nv (volatile os_atomic_voidp_t *x, ptrdiff_t v) {
return (void *) os_atomic_addptr_nv ((volatile os_atomic_uintptr_t *) x, (uintptr_t) v);
}
/* SUB */
VDDS_INLINE void os_atomic_sub32 (volatile os_atomic_uint32_t *x, uint32_t v) {
__sync_fetch_and_sub (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE void os_atomic_sub64 (volatile os_atomic_uint64_t *x, uint64_t v) {
__sync_fetch_and_sub (&x->v, v);
}
#endif
VDDS_INLINE void os_atomic_subptr (volatile os_atomic_uintptr_t *x, uintptr_t v) {
__sync_fetch_and_sub (&x->v, v);
}
VDDS_INLINE void os_atomic_subvoidp (volatile os_atomic_voidp_t *x, ptrdiff_t v) {
os_atomic_subptr ((volatile os_atomic_uintptr_t *) x, (uintptr_t) v);
}
VDDS_INLINE uint32_t os_atomic_sub32_nv (volatile os_atomic_uint32_t *x, uint32_t v) {
return __sync_sub_and_fetch (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE uint64_t os_atomic_sub64_nv (volatile os_atomic_uint64_t *x, uint64_t v) {
return __sync_sub_and_fetch (&x->v, v);
}
#endif
VDDS_INLINE uintptr_t os_atomic_subptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v) {
return __sync_sub_and_fetch (&x->v, v);
}
VDDS_INLINE void *os_atomic_subvoidp_nv (volatile os_atomic_voidp_t *x, ptrdiff_t v) {
return (void *) os_atomic_subptr_nv ((volatile os_atomic_uintptr_t *) x, (uintptr_t) v);
}
/* AND */
VDDS_INLINE void os_atomic_and32 (volatile os_atomic_uint32_t *x, uint32_t v) {
__sync_fetch_and_and (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE void os_atomic_and64 (volatile os_atomic_uint64_t *x, uint64_t v) {
__sync_fetch_and_and (&x->v, v);
}
#endif
VDDS_INLINE void os_atomic_andptr (volatile os_atomic_uintptr_t *x, uintptr_t v) {
__sync_fetch_and_and (&x->v, v);
}
VDDS_INLINE uint32_t os_atomic_and32_ov (volatile os_atomic_uint32_t *x, uint32_t v) {
return __sync_fetch_and_and (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE uint64_t os_atomic_and64_ov (volatile os_atomic_uint64_t *x, uint64_t v) {
return __sync_fetch_and_and (&x->v, v);
}
#endif
VDDS_INLINE uintptr_t os_atomic_andptr_ov (volatile os_atomic_uintptr_t *x, uintptr_t v) {
return __sync_fetch_and_and (&x->v, v);
}
VDDS_INLINE uint32_t os_atomic_and32_nv (volatile os_atomic_uint32_t *x, uint32_t v) {
return __sync_and_and_fetch (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE uint64_t os_atomic_and64_nv (volatile os_atomic_uint64_t *x, uint64_t v) {
return __sync_and_and_fetch (&x->v, v);
}
#endif
VDDS_INLINE uintptr_t os_atomic_andptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v) {
return __sync_and_and_fetch (&x->v, v);
}
/* OR */
VDDS_INLINE void os_atomic_or32 (volatile os_atomic_uint32_t *x, uint32_t v) {
__sync_fetch_and_or (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE void os_atomic_or64 (volatile os_atomic_uint64_t *x, uint64_t v) {
__sync_fetch_and_or (&x->v, v);
}
#endif
VDDS_INLINE void os_atomic_orptr (volatile os_atomic_uintptr_t *x, uintptr_t v) {
__sync_fetch_and_or (&x->v, v);
}
VDDS_INLINE uint32_t os_atomic_or32_ov (volatile os_atomic_uint32_t *x, uint32_t v) {
return __sync_fetch_and_or (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE uint64_t os_atomic_or64_ov (volatile os_atomic_uint64_t *x, uint64_t v) {
return __sync_fetch_and_or (&x->v, v);
}
#endif
VDDS_INLINE uintptr_t os_atomic_orptr_ov (volatile os_atomic_uintptr_t *x, uintptr_t v) {
return __sync_fetch_and_or (&x->v, v);
}
VDDS_INLINE uint32_t os_atomic_or32_nv (volatile os_atomic_uint32_t *x, uint32_t v) {
return __sync_or_and_fetch (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE uint64_t os_atomic_or64_nv (volatile os_atomic_uint64_t *x, uint64_t v) {
return __sync_or_and_fetch (&x->v, v);
}
#endif
VDDS_INLINE uintptr_t os_atomic_orptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v) {
return __sync_or_and_fetch (&x->v, v);
}
/* CAS */
VDDS_INLINE int os_atomic_cas32 (volatile os_atomic_uint32_t *x, uint32_t exp, uint32_t des) {
return __sync_bool_compare_and_swap (&x->v, exp, des);
}
#if OS_ATOMIC64_SUPPORT
VDDS_INLINE int os_atomic_cas64 (volatile os_atomic_uint64_t *x, uint64_t exp, uint64_t des) {
return __sync_bool_compare_and_swap (&x->v, exp, des);
}
#endif
VDDS_INLINE int os_atomic_casptr (volatile os_atomic_uintptr_t *x, uintptr_t exp, uintptr_t des) {
return __sync_bool_compare_and_swap (&x->v, exp, des);
}
VDDS_INLINE int os_atomic_casvoidp (volatile os_atomic_voidp_t *x, void *exp, void *des) {
return os_atomic_casptr (x, (uintptr_t) exp, (uintptr_t) des);
}
/* FENCES */
VDDS_INLINE void os_atomic_fence (void) {
__sync_synchronize ();
}
VDDS_INLINE void os_atomic_fence_acq (void) {
os_atomic_fence ();
}
VDDS_INLINE void os_atomic_fence_rel (void) {
os_atomic_fence ();
}
#endif /* not omit functions */
#define OS_ATOMIC_SUPPORT 1
#endif

View file

@ -0,0 +1,435 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/* x86 has supported 64-bit CAS for a long time, so Windows ought to
provide all the interlocked operations for 64-bit operands on x86
platforms, but it doesn't. */
#if defined OS_64BIT
#define OS_ATOMIC64_SUPPORT 1
#else
#define OS_ATOMIC64_SUPPORT 0
#endif
#if defined OS_64BIT
#define OS_ATOMIC_PTROP(name) name##64
#else
#define OS_ATOMIC_PTROP(name) name
#endif
#if ! OS_ATOMICS_OMIT_FUNCTIONS
/* Experience is that WinCE doesn't provide these, and that neither does VS8 */
#if ! defined OS_WINCE_DEFS_H && _MSC_VER > 1400
#if defined _M_IX86 || defined _M_ARM
#define OS_ATOMIC_INTERLOCKED_AND _InterlockedAnd
#define OS_ATOMIC_INTERLOCKED_OR _InterlockedOr
#define OS_ATOMIC_INTERLOCKED_AND64 _InterlockedAnd64
#define OS_ATOMIC_INTERLOCKED_OR64 _InterlockedOr64
#else
#define OS_ATOMIC_INTERLOCKED_AND InterlockedAnd
#define OS_ATOMIC_INTERLOCKED_OR InterlockedOr
#define OS_ATOMIC_INTERLOCKED_AND64 InterlockedAnd64
#define OS_ATOMIC_INTERLOCKED_OR64 InterlockedOr64
#endif
#endif
#if OS_ATOMIC_HAVE_INLINE
#define OS_ATOMIC_API_INLINE OS_ATOMIC_INLINE
#else
#define OS_ATOMIC_API_INLINE OSAPI_EXPORT
#endif
/* LD, ST */
OS_ATOMIC_API_INLINE uint32_t os_atomic_ld32 (const volatile os_atomic_uint32_t *x) { return x->v; }
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_ld64 (const volatile os_atomic_uint64_t *x) { return x->v; }
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_ldptr (const volatile os_atomic_uintptr_t *x) { return x->v; }
OS_ATOMIC_API_INLINE void *os_atomic_ldvoidp (const volatile os_atomic_voidp_t *x) { return (void *) os_atomic_ldptr (x); }
OS_ATOMIC_API_INLINE void os_atomic_st32 (volatile os_atomic_uint32_t *x, uint32_t v) { x->v = v; }
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE void os_atomic_st64 (volatile os_atomic_uint64_t *x, uint64_t v) { x->v = v; }
#endif
OS_ATOMIC_API_INLINE void os_atomic_stptr (volatile os_atomic_uintptr_t *x, uintptr_t v) { x->v = v; }
OS_ATOMIC_API_INLINE void os_atomic_stvoidp (volatile os_atomic_voidp_t *x, void *v) { os_atomic_stptr (x, (uintptr_t) v); }
/* CAS */
OS_ATOMIC_API_INLINE int os_atomic_cas32 (volatile os_atomic_uint32_t *x, uint32_t exp, uint32_t des) {
return InterlockedCompareExchange (&x->v, des, exp) == exp;
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE int os_atomic_cas64 (volatile os_atomic_uint64_t *x, uint64_t exp, uint64_t des) {
return InterlockedCompareExchange64 (&x->v, des, exp) == exp;
}
#endif
OS_ATOMIC_API_INLINE int os_atomic_casptr (volatile os_atomic_uintptr_t *x, uintptr_t exp, uintptr_t des) {
return OS_ATOMIC_PTROP (InterlockedCompareExchange) (&x->v, des, exp) == exp;
}
OS_ATOMIC_API_INLINE int os_atomic_casvoidp (volatile os_atomic_voidp_t *x, void *exp, void *des) {
return os_atomic_casptr ((volatile os_atomic_uintptr_t *) x, (uintptr_t) exp, (uintptr_t) des);
}
/* INC */
OS_ATOMIC_API_INLINE void os_atomic_inc32 (volatile os_atomic_uint32_t *x) {
InterlockedIncrement (&x->v);
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE void os_atomic_inc64 (volatile os_atomic_uint64_t *x) {
InterlockedIncrement64 (&x->v);
}
#endif
OS_ATOMIC_API_INLINE void os_atomic_incptr (volatile os_atomic_uintptr_t *x) {
OS_ATOMIC_PTROP (InterlockedIncrement) (&x->v);
}
OS_ATOMIC_API_INLINE uint32_t os_atomic_inc32_nv (volatile os_atomic_uint32_t *x) {
return InterlockedIncrement (&x->v);
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_inc64_nv (volatile os_atomic_uint64_t *x) {
return InterlockedIncrement64 (&x->v);
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_incptr_nv (volatile os_atomic_uintptr_t *x) {
return OS_ATOMIC_PTROP (InterlockedIncrement) (&x->v);
}
/* DEC */
OS_ATOMIC_API_INLINE void os_atomic_dec32 (volatile os_atomic_uint32_t *x) {
InterlockedDecrement (&x->v);
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE void os_atomic_dec64 (volatile os_atomic_uint64_t *x) {
InterlockedDecrement64 (&x->v);
}
#endif
OS_ATOMIC_API_INLINE void os_atomic_decptr (volatile os_atomic_uintptr_t *x) {
OS_ATOMIC_PTROP (InterlockedDecrement) (&x->v);
}
OS_ATOMIC_API_INLINE uint32_t os_atomic_dec32_nv (volatile os_atomic_uint32_t *x) {
return InterlockedDecrement (&x->v);
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_dec64_nv (volatile os_atomic_uint64_t *x) {
return InterlockedDecrement64 (&x->v);
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_decptr_nv (volatile os_atomic_uintptr_t *x) {
return OS_ATOMIC_PTROP (InterlockedDecrement) (&x->v);
}
OS_ATOMIC_API_INLINE uint32_t os_atomic_dec32_ov (volatile os_atomic_uint32_t *x) {
return InterlockedDecrement (&x->v) + 1;
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_dec64_ov (volatile os_atomic_uint64_t *x) {
return InterlockedDecrement64 (&x->v) + 1;
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_decptr_ov (volatile os_atomic_uintptr_t *x) {
return OS_ATOMIC_PTROP (InterlockedDecrement) (&x->v) + 1;
}
/* ADD */
OS_ATOMIC_API_INLINE void os_atomic_add32 (volatile os_atomic_uint32_t *x, uint32_t v) {
InterlockedExchangeAdd (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE void os_atomic_add64 (volatile os_atomic_uint64_t *x, uint64_t v) {
InterlockedExchangeAdd64 (&x->v, v);
}
#endif
OS_ATOMIC_API_INLINE void os_atomic_addptr (volatile os_atomic_uintptr_t *x, uintptr_t v) {
OS_ATOMIC_PTROP (InterlockedExchangeAdd) (&x->v, v);
}
OS_ATOMIC_API_INLINE void os_atomic_addvoidp (volatile os_atomic_voidp_t *x, ptrdiff_t v) {
os_atomic_addptr ((volatile os_atomic_uintptr_t *) x, (uintptr_t) v);
}
OS_ATOMIC_API_INLINE uint32_t os_atomic_add32_nv (volatile os_atomic_uint32_t *x, uint32_t v) {
return InterlockedExchangeAdd (&x->v, v) + v;
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_add64_nv (volatile os_atomic_uint64_t *x, uint64_t v) {
return InterlockedExchangeAdd64 (&x->v, v) + v;
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_addptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v) {
return OS_ATOMIC_PTROP (InterlockedExchangeAdd) (&x->v, v) + v;
}
OS_ATOMIC_API_INLINE void *os_atomic_addvoidp_nv (volatile os_atomic_voidp_t *x, ptrdiff_t v) {
return (void *) os_atomic_addptr_nv ((volatile os_atomic_uintptr_t *) x, (uintptr_t) v);
}
/* SUB */
OS_ATOMIC_API_INLINE void os_atomic_sub32 (volatile os_atomic_uint32_t *x, uint32_t v) {
/* disable unary minus applied to unsigned type, result still unsigned */
#pragma warning (push)
#pragma warning (disable: 4146)
InterlockedExchangeAdd (&x->v, -v);
#pragma warning (pop)
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE void os_atomic_sub64 (volatile os_atomic_uint64_t *x, uint64_t v) {
/* disable unary minus applied to unsigned type, result still unsigned */
#pragma warning (push)
#pragma warning (disable: 4146)
InterlockedExchangeAdd64 (&x->v, -v);
#pragma warning (pop)
}
#endif
OS_ATOMIC_API_INLINE void os_atomic_subptr (volatile os_atomic_uintptr_t *x, uintptr_t v) {
/* disable unary minus applied to unsigned type, result still unsigned */
#pragma warning (push)
#pragma warning (disable: 4146)
OS_ATOMIC_PTROP (InterlockedExchangeAdd) (&x->v, -v);
#pragma warning (pop)
}
OS_ATOMIC_API_INLINE void os_atomic_subvoidp (volatile os_atomic_voidp_t *x, ptrdiff_t v) {
os_atomic_subptr ((volatile os_atomic_uintptr_t *) x, (uintptr_t) v);
}
OS_ATOMIC_API_INLINE uint32_t os_atomic_sub32_nv (volatile os_atomic_uint32_t *x, uint32_t v) {
/* disable unary minus applied to unsigned type, result still unsigned */
#pragma warning (push)
#pragma warning (disable: 4146)
return InterlockedExchangeAdd (&x->v, -v) - v;
#pragma warning (pop)
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_sub64_nv (volatile os_atomic_uint64_t *x, uint64_t v) {
/* disable unary minus applied to unsigned type, result still unsigned */
#pragma warning (push)
#pragma warning (disable: 4146)
return InterlockedExchangeAdd64 (&x->v, -v) - v;
#pragma warning (pop)
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_subptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v) {
/* disable unary minus applied to unsigned type, result still unsigned */
#pragma warning (push)
#pragma warning (disable: 4146)
return OS_ATOMIC_PTROP (InterlockedExchangeAdd) (&x->v, -v) - v;
#pragma warning (pop)
}
OS_ATOMIC_API_INLINE void *os_atomic_subvoidp_nv (volatile os_atomic_voidp_t *x, ptrdiff_t v) {
return (void *) os_atomic_subptr_nv ((volatile os_atomic_uintptr_t *) x, (uintptr_t) v);
}
/* AND */
#if defined OS_ATOMIC_INTERLOCKED_AND
OS_ATOMIC_API_INLINE void os_atomic_and32 (volatile os_atomic_uint32_t *x, uint32_t v) {
OS_ATOMIC_INTERLOCKED_AND (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE void os_atomic_and64 (volatile os_atomic_uint64_t *x, uint64_t v) {
InterlockedAnd64 (&x->v, v);
}
#endif
OS_ATOMIC_API_INLINE void os_atomic_andptr (volatile os_atomic_uintptr_t *x, uintptr_t v) {
OS_ATOMIC_PTROP (OS_ATOMIC_INTERLOCKED_AND) (&x->v, v);
}
OS_ATOMIC_API_INLINE uint32_t os_atomic_and32_ov (volatile os_atomic_uint32_t *x, uint32_t v) {
return OS_ATOMIC_INTERLOCKED_AND (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_and64_ov (volatile os_atomic_uint64_t *x, uint64_t v) {
return InterlockedAnd64 (&x->v, v);
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_andptr_ov (volatile os_atomic_uintptr_t *x, uintptr_t v) {
return OS_ATOMIC_PTROP (OS_ATOMIC_INTERLOCKED_AND) (&x->v, v);
}
OS_ATOMIC_API_INLINE uint32_t os_atomic_and32_nv (volatile os_atomic_uint32_t *x, uint32_t v) {
return OS_ATOMIC_INTERLOCKED_AND (&x->v, v) & v;
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_and64_nv (volatile os_atomic_uint64_t *x, uint64_t v) {
return InterlockedAnd64 (&x->v, v) & v;
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_andptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v) {
return OS_ATOMIC_PTROP (OS_ATOMIC_INTERLOCKED_AND) (&x->v, v) & v;
}
#else /* synthesize via CAS */
OS_ATOMIC_API_INLINE uint32_t os_atomic_and32_ov (volatile os_atomic_uint32_t *x, uint32_t v) {
uint64_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (!os_atomic_cas32 (x, oldval, newval));
return oldval;
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_and64_ov (volatile os_atomic_uint64_t *x, uint64_t v) {
uint64_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (!os_atomic_cas64 (x, oldval, newval));
return oldval;
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_andptr_ov (volatile os_atomic_uintptr_t *x, uintptr_t v) {
uintptr_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (!os_atomic_casptr (x, oldval, newval));
return oldval;
}
OS_ATOMIC_API_INLINE uint32_t os_atomic_and32_nv (volatile os_atomic_uint32_t *x, uint32_t v) {
uint32_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (!os_atomic_cas32 (x, oldval, newval));
return newval;
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_and64_nv (volatile os_atomic_uint64_t *x, uint64_t v) {
uint64_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (!os_atomic_cas64 (x, oldval, newval));
return newval;
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_andptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v) {
uintptr_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (!os_atomic_casptr (x, oldval, newval));
return newval;
}
OS_ATOMIC_API_INLINE void os_atomic_and32 (volatile os_atomic_uint32_t *x, uint32_t v) {
(void) os_atomic_and32_nv (x, v);
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE void os_atomic_and64 (volatile os_atomic_uint64_t *x, uint64_t v) {
(void) os_atomic_and64_nv (x, v);
}
#endif
OS_ATOMIC_API_INLINE void os_atomic_andptr (volatile os_atomic_uintptr_t *x, uintptr_t v) {
(void) os_atomic_andptr_nv (x, v);
}
#endif
/* OR */
#if defined OS_ATOMIC_INTERLOCKED_OR
OS_ATOMIC_API_INLINE void os_atomic_or32 (volatile os_atomic_uint32_t *x, uint32_t v) {
OS_ATOMIC_INTERLOCKED_OR (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE void os_atomic_or64 (volatile os_atomic_uint64_t *x, uint64_t v) {
InterlockedOr64 (&x->v, v);
}
#endif
OS_ATOMIC_API_INLINE void os_atomic_orptr (volatile os_atomic_uintptr_t *x, uintptr_t v) {
OS_ATOMIC_PTROP (OS_ATOMIC_INTERLOCKED_OR) (&x->v, v);
}
OS_ATOMIC_API_INLINE uint32_t os_atomic_or32_ov (volatile os_atomic_uint32_t *x, uint32_t v) {
return OS_ATOMIC_INTERLOCKED_OR (&x->v, v);
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_or64_ov (volatile os_atomic_uint64_t *x, uint64_t v) {
return InterlockedOr64 (&x->v, v);
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_orptr_ov (volatile os_atomic_uintptr_t *x, uintptr_t v) {
return OS_ATOMIC_PTROP (OS_ATOMIC_INTERLOCKED_OR) (&x->v, v);
}
OS_ATOMIC_API_INLINE uint32_t os_atomic_or32_nv (volatile os_atomic_uint32_t *x, uint32_t v) {
return OS_ATOMIC_INTERLOCKED_OR (&x->v, v) | v;
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_or64_nv (volatile os_atomic_uint64_t *x, uint64_t v) {
return InterlockedOr64 (&x->v, v) | v;
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_orptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v) {
return OS_ATOMIC_PTROP (OS_ATOMIC_INTERLOCKED_OR) (&x->v, v) | v;
}
#else /* synthesize via CAS */
OS_ATOMIC_API_INLINE uint32_t os_atomic_or32_ov (volatile os_atomic_uint32_t *x, uint32_t v) {
uint32_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (!os_atomic_cas32 (x, oldval, newval));
return oldval;
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_or64_ov (volatile os_atomic_uint64_t *x, uint64_t v) {
uint64_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (!os_atomic_cas64 (x, oldval, newval));
return oldval;
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_orptr_ov (volatile os_atomic_uintptr_t *x, uintptr_t v) {
uintptr_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (!os_atomic_casptr (x, oldval, newval));
return oldval;
}
OS_ATOMIC_API_INLINE uint32_t os_atomic_or32_nv (volatile os_atomic_uint32_t *x, uint32_t v) {
uint32_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (!os_atomic_cas32 (x, oldval, newval));
return newval;
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE uint64_t os_atomic_or64_nv (volatile os_atomic_uint64_t *x, uint64_t v) {
uint64_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (!os_atomic_cas64 (x, oldval, newval));
return newval;
}
#endif
OS_ATOMIC_API_INLINE uintptr_t os_atomic_orptr_nv (volatile os_atomic_uintptr_t *x, uintptr_t v) {
uintptr_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (!os_atomic_casptr (x, oldval, newval));
return newval;
}
OS_ATOMIC_API_INLINE void os_atomic_or32 (volatile os_atomic_uint32_t *x, uint32_t v) {
(void) os_atomic_or32_nv (x, v);
}
#if OS_ATOMIC64_SUPPORT
OS_ATOMIC_API_INLINE void os_atomic_or64 (volatile os_atomic_uint64_t *x, uint64_t v) {
(void) os_atomic_or64_nv (x, v);
}
#endif
OS_ATOMIC_API_INLINE void os_atomic_orptr (volatile os_atomic_uintptr_t *x, uintptr_t v) {
(void) os_atomic_orptr_nv (x, v);
}
#endif
/* FENCES */
OS_ATOMIC_API_INLINE void os_atomic_fence (void) {
/* 28113: accessing a local variable tmp via an Interlocked
function: This is an unusual usage which could be reconsidered.
It is too heavyweight, true, but it does the trick. */
#pragma warning (push)
#pragma warning (disable: 28113)
volatile LONG tmp = 0;
InterlockedExchange (&tmp, 0);
#pragma warning (pop)
}
OS_ATOMIC_API_INLINE void os_atomic_fence_acq (void) {
os_atomic_fence ();
}
OS_ATOMIC_API_INLINE void os_atomic_fence_rel (void) {
os_atomic_fence ();
}
#undef OS_ATOMIC_INTERLOCKED_AND
#undef OS_ATOMIC_INTERLOCKED_OR
#undef OS_ATOMIC_INTERLOCKED_AND64
#undef OS_ATOMIC_INTERLOCKED_OR64
#undef OS_ATOMIC_API_INLINE
#endif /* not omit functions */
#undef OS_ATOMIC_PTROP
#define OS_ATOMIC_SUPPORT 1

View file

@ -0,0 +1,129 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_DECL_ATTRIBUTES_H
#define OS_DECL_ATTRIBUTES_H
#define OS_GNUC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#ifndef __has_attribute
# if defined __GNUC__ && !defined __clang__
# define __has_attribute(x) 1 /* Compatibility with GCC compilers that don't have __has_attribute. */
# else
# define __has_attribute(x) 0 /* Compatibility with compilers that don't have __has_attribute. */
# endif
#endif
#ifndef __attribute_malloc__
# if __has_attribute(malloc)
# define __attribute_malloc__ __attribute__((__malloc__))
# else
# define __attribute_malloc__ /* Ignore. */
# endif
#endif
#ifndef __attribute_unused__
# if __has_attribute(unused)
# define __attribute_unused__ __attribute__((__unused__))
# else
# define __attribute_unused__ /* Ignore. */
# endif
#endif
#ifndef __attribute_noreturn__
# if __has_attribute(noreturn)
# define __attribute_noreturn__ __attribute__((__noreturn__))
# else
# define __attribute_noreturn__ /* Ignore. */
# endif
#endif
#if defined FIX_FAULTY_ATTRIBUTE_NONNULL || defined __clang__ || OS_GNUC_VERSION >= 50200
/* Some platforms have a faulty definition of the __nonnull macro where params
* are expanded within brackets, causing the parameters to be treated as a comma-
* expression. If FIX_FAULTY_ATTRIBUTE_NONNULL is defined, the macro is undeffed
* so our own definition will be used instead. */
# undef __nonnull
#endif
#ifndef __nonnull
# if __has_attribute(nonnull)
# define __nonnull(params) __attribute__((__nonnull__ params))
# define __nonnull_all__ __attribute__((__nonnull__))
# else
# define __nonnull(params) /* Ignore. */
# define __nonnull_all__ /* Ignore. */
# endif
#else
# define __nonnull_all__ __attribute__((__nonnull__))
#endif
#ifndef __attribute_returns_nonnull__
# if __has_attribute(returns_nonnull) && (defined __clang__ || OS_GNUC_VERSION >= 40900)
# define __attribute_returns_nonnull__ __attribute__((__returns_nonnull__))
# else
# define __attribute_returns_nonnull__ /* Ignore. */
# endif
#endif
#ifndef __attribute_alloc_size__
/* Silence GCC <= V4.2.4, which reports that it has the attribute, but nags that it ignores it. */
# if __has_attribute(alloc_size) && OS_GNUC_VERSION > 40204
# define __attribute_alloc_size__(params) __attribute__ ((__alloc_size__ params))
# else
# define __attribute_alloc_size__(params) /* Ignore. */
# endif
#endif
#ifndef __attribute_const__
# if __has_attribute(const)
# define __attribute_const__ __attribute__ ((__const__))
# else
# define __attribute_const__ /* Ignore. */
# endif
#endif
#ifndef __attribute_pure__
# if __has_attribute(pure)
# define __attribute_pure__ __attribute__ ((__pure__))
# else
# define __attribute_pure__ /* Ignore. */
# endif
#endif
#ifndef __attribute_format__
# if __has_attribute(format)
# define __attribute_format__(params) __attribute__ ((__format__ params))
# else
# define __attribute_format__(params) /* Ignore. */
# endif
#endif
#ifndef __attribute_warn_unused_result__
# if __has_attribute(warn_unused_result)
# define __attribute_warn_unused_result__ __attribute__ ((__warn_unused_result__))
# else
# define __attribute_warn_unused_result__ /* Ignore. */
# endif
#endif
#ifndef __attribute_assume_aligned__
# if __has_attribute(assume_aligned)
# define __attribute_assume_aligned__(params) __attribute__ ((__assume_aligned__ params))
# else
# define __attribute_assume_aligned__(params) /* Ignore. */
# endif
#endif
#include "os/os_decl_attributes_sal.h"
#undef OS_GNUC_VERSION
#endif

File diff suppressed because it is too large Load diff

286
src/os/include/os/os_defs.h Normal file
View file

@ -0,0 +1,286 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_DEFS_H
#define OS_DEFS_H
#define OS_LITTLE_ENDIAN 1
#define OS_BIG_ENDIAN 2
#if OS_ENDIANNESS != OS_LITTLE_ENDIAN && OS_ENDIANNESS != OS_BIG_ENDIAN
#error "OS_ENDIANNESS not set correctly"
#endif
#ifndef OS_HAS_UCONTEXT_T
#error "OS_HAS_UCONTEXT_T not set"
#endif
#ifndef OS_SOCKET_USE_FCNTL
#error "OS_SOCKET_USE_FCNTL must be defined for this platform."
#endif
#ifndef OS_SOCKET_USE_IOCTL
#error "OS_SOCKET_USE_IOCTL must be defined for this platform."
#endif
#if (OS_SOCKET_USE_IOCTL == 1) && (OS_SOCKET_USE_FCNTL == 1)
#error "this platform must set only one of OS_SOCKET_USE_IOCTL and OS_SOCKET_USE_FCNTL to 1"
#endif
#ifndef OS_FILESEPCHAR
#error "OS_FILESEPCHAR must be defined for this platform."
#endif
#include "os/os_decl_attributes.h"
#if defined (__cplusplus)
extern "C" {
#endif
/* \brief OS_FUNCTION provides undecorated function name of current function
*
* Behavior of OS_FUNCTION outside a function is undefined. Note that
* implementations differ across compilers and compiler versions. It might be
* implemented as either a string literal or a constant variable.
*/
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
# define OS_FUNCTION __func__
#elif defined(__cplusplus) && (__cplusplus >= 201103)
# define OS_FUNCTION __func__
#elif defined(__GNUC__)
# define OS_FUNCTION __FUNCTION__
#elif defined(__clang__)
# define OS_FUNCTION __FUNCTION__
#elif defined(__ghs__)
# define OS_FUNCTION __FUNCTION__
#elif (defined(__SUNPRO_C) || defined(__SUNPRO_CC))
/* Solaris Studio had support for __func__ before it supported __FUNCTION__.
Compiler flag -features=extensions is required on older versions. */
# define OS_FUNCTION __func__
#elif defined(__FUNCTION__)
/* Visual Studio */
# define OS_FUNCTION __FUNCTION__
#elif defined(__vxworks)
/* At least versions 2.9.6 and 3.3.4 of the GNU C Preprocessor only define
__GNUC__ if the entire GNU C compiler is in use. VxWorks 5.5 targets invoke
the preprocessor separately resulting in __GNUC__ not being defined. */
# define OS_FUNCTION __FUNCTION__
#else
# warning "OS_FUNCTION is not supported"
#endif
/* \brief OS_PRETTY_FUNCTION provides function signature of current function
*
* See comments on OS_FUNCTION for details.
*/
#if defined(__GNUC__)
# define OS_PRETTY_FUNCTION __PRETTY_FUNCTION__
#elif defined(__clang__)
# define OS_PRETTY_FUNCTION __PRETTY_FUNCTION__
#elif defined(__ghs__)
# define OS_PRETTY_FUNCTION __PRETTY_FUNCTION__
#elif (defined(__SUNPRO_C) && __SUNPRO_C >= 0x5100)
/* Solaris Studio supports __PRETTY_FUNCTION__ in C since version 12.1 */
# define OS_PRETTY_FUNCTION __PRETTY_FUNCTION__
#elif (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5120)
/* Solaris Studio supports __PRETTY_FUNCTION__ in C++ since version 12.3 */
# define OS_PRETTY_FUNCTION __PRETTY_FUNCTION__
#elif defined(__FUNCSIG__)
/* Visual Studio */
# define OS_PRETTY_FUNCTION __FUNCSIG__
#elif defined(__vxworks)
/* See comments on __vxworks macro above. */
# define OS_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
/* Do not warn user about OS_PRETTY_FUNCTION falling back to OS_FUNCTION.
# warning "OS_PRETTY_FUNCTION is not supported, using OS_FUNCTION"
*/
# define OS_PRETTY_FUNCTION OS_FUNCTION
#endif
#if defined(__GNUC__)
#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
#define OSPL_GCC_DIAG_STR(s) #s
#define OSPL_GCC_DIAG_JOINSTR(x,y) OSPL_GCC_DIAG_STR(x ## y)
#define OSPL_GCC_DIAG_DO_PRAGMA(x) _Pragma (#x)
#define OSPL_GCC_DIAG_PRAGMA(x) OSPL_GCC_DIAG_DO_PRAGMA(GCC diagnostic x)
#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
#define OS_WARNING_GNUC_OFF(x) OSPL_GCC_DIAG_PRAGMA(push) OSPL_GCC_DIAG_PRAGMA(ignored OSPL_GCC_DIAG_JOINSTR(-W,x))
#define OS_WARNING_GNUC_ON(x) OSPL_GCC_DIAG_PRAGMA(pop)
#else
#define OS_WARNING_GNUC_OFF(x) OSPL_GCC_DIAG_PRAGMA(ignored OSPL_GCC_DIAG_JOINSTR(-W,x))
#define OS_WARNING_GNUC_ON(x) OSPL_GCC_DIAG_PRAGMA(warning OSPL_GCC_DIAG_JOINSTR(-W,x))
#endif
#else
#define OS_WARNING_GNUC_OFF(x)
#define OS_WARNING_GNUC_ON(x)
#endif
#else
#define OS_WARNING_GNUC_OFF(x)
#define OS_WARNING_GNUC_ON(x)
#endif
#ifdef _MSC_VER
#define OS_WARNING_MSVC_OFF(x) \
__pragma (warning(push)) \
__pragma (warning(disable: ## x))
#define OS_WARNING_MSVC_ON(x) \
__pragma (warning(pop))
#else
#define OS_WARNING_MSVC_OFF(x)
#define OS_WARNING_MSVC_ON(x)
#endif
/**
* \brief Calculate maximum value of an integer type
*
* A somewhat complex, but efficient way to calculate the maximum value of an
* integer type at compile time.
*
* For unsigned numerical types the first part up to XOR is enough. The second
* part is to make up for signed numerical types.
*/
#define OS_MAX_INTEGER(T) \
((T)(((T)~0) ^ ((T)!((T)~0 > 0) << (CHAR_BIT * sizeof(T) - 1))))
/**
* \brief Calculate minimum value of an integer type
*/
#define OS_MIN_INTEGER(T) \
((-OS_MAX_INTEGER(T)) - 1)
#if !defined (OS_UNUSED_ARG)
#define OS_UNUSED_ARG(a) (void) (a)
#endif
/** \brief Time structure definition
*/
typedef struct os_time {
/** Seconds since the Unix epoch; 1-jan-1970 00:00:00 (UTC) */
os_timeSec tv_sec;
/** Number of nanoseconds since the Unix epoch, modulo 10^9. */
int32_t tv_nsec;
/** os_time can be used for a duration type with the following
semantics for negative durations: tv_sec specifies the
sign of the duration, tv_nsec is always positive and added
to the real value (thus real value is tv_sec+tv_nsec/10^9,
for example { -1, 500000000 } is -0.5 seconds) */
} os_time;
/** \brief Types on which we define atomic operations. The 64-bit
* types are always defined, even if we don't really support atomic
* operations on them.
*/
typedef struct { uint32_t v; } os_atomic_uint32_t;
typedef struct { uint64_t v; } os_atomic_uint64_t;
typedef struct { uintptr_t v; } os_atomic_uintptr_t;
typedef os_atomic_uintptr_t os_atomic_voidp_t;
/** \brief Initializers for the types on which atomic operations are
defined.
*/
#define OS_ATOMIC_UINT32_INIT(v) { (v) }
#define OS_ATOMIC_UINT64_INIT(v) { (v) }
#define OS_ATOMIC_UINTPTR_INIT(v) { (v) }
#define OS_ATOMIC_VOIDP_INIT(v) { (uintptr_t) (v) }
/** \brief Definition of the service return values */
typedef _Return_type_success_(return == os_resultSuccess) enum os_result {
/** The service is successfully completed */
os_resultSuccess,
/** A resource was not found */
os_resultUnavailable,
/** The service is timed out */
os_resultTimeout,
/** The requested resource is busy */
os_resultBusy,
/** An invalid argument is passed */
os_resultInvalid,
/** The operating system returned a failure */
os_resultFail
} os_result;
/* We want to inline these, but we don't want to emit an exernally
visible symbol for them and we don't want warnings if we don't use
them.
It appears as if a plain "inline" will do just that in C99.
In traditional GCC one had to use "extern inline" to achieve that
effect, but that will cause an externally visible symbol to be
emitted by a C99 compiler.
Starting with GCC 4.3, GCC conforms to the C99 standard if
compiling in C99 mode, unless -fgnu89-inline is specified. It
defines __GNUC_STDC_INLINE__ if "inline"/"extern inline" behaviour
is conforming the C99 standard.
So: GCC >= 4.3: choose between "inline" & "extern inline" based
upon __GNUC_STDC_INLINE__; for GCCs < 4.2, rely on the traditional
GCC behaiour; and for other compilers assume they behave conforming
the standard if they advertise themselves as C99 compliant (use
"inline"), and assume they do not support the inline keywords
otherwise.
GCC when not optimizing ignores "extern inline" functions. So we
need to distinguish between optimizing & non-optimizing ... */
/* Defining OS_HAVE_INLINE is a supported way of overruling this file */
#ifndef OS_HAVE_INLINE
#if __STDC_VERSION__ >= 199901L
# /* C99, but old GCC nonetheless doesn't implement C99 semantics ... */
# if __GNUC__ && ! defined __GNUC_STDC_INLINE__
# define OS_HAVE_INLINE 1
# define VDDS_INLINE extern __inline__
# else
# define OS_HAVE_INLINE 1
# define VDDS_INLINE inline
# endif
#elif defined __STDC__ && defined __GNUC__ && ! defined __cplusplus
# if __OPTIMIZE__
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
# ifdef __GNUC_STDC_INLINE__
# define OS_HAVE_INLINE 1
# define VDDS_INLINE __inline__
# else
# define OS_HAVE_INLINE 1
# define VDDS_INLINE extern __inline__
# endif
# else
# define OS_HAVE_INLINE 1
# define VDDS_INLINE extern __inline__
# endif
# endif
#endif
#if ! OS_HAVE_INLINE
#define VDDS_INLINE
#endif
#endif /* not defined OS_HAVE_INLINE */
#if defined(_MSC_VER)
/* Thread-local storage using __declspec(thread) on Windows versions before
Vista and Server 2008 works in DLLs if they are bound to the executable,
it does not work if the library is loaded using LoadLibrary. */
#define os_threadLocal __declspec(thread)
#elif defined(__GNUC__) || (defined(__clang__) && __clang_major__ >= 2)
/* GCC supports Thread-local storage for x86 since version 3.3. Clang
supports Thread-local storage since version 2.0. */
/* VxWorks 7 supports __thread for both GCC and DIAB, older versions may
support it as well, but that is not verified. */
#define os_threadLocal __thread
#else
#error "os_threadLocal is not supported"
#endif
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,72 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_ERRNO_H
#define OS_ERRNO_H
#if defined (__cplusplus)
extern "C" {
#endif
#include "os/os_defs.h"
#if (defined(WIN32) || defined(WINCE))
#include <winerror.h>
#endif
#include <errno.h> /* Required on Windows platforms too */
/** \brief Get error code set by last operation that failed
*
* @return Error code
*/
OSAPI_EXPORT int
os_getErrno (
void);
/** \brief Set error code to specified value
*
* @return void
* @param err Error code
*/
OSAPI_EXPORT void
os_setErrno (
int err);
/**
* \brief Get description for specified error code
*
* @return 0 success. On error a (positive) error number is returned
* @param err Error number
* @param buf Buffer to store description in
* @oaram bufsz Number of bytes available in buf
*/
OSAPI_EXPORT int
os_strerror_r (
_In_ int err,
_Out_writes_z_(bufsz) char *buf,
_In_ size_t bufsz);
/**
* \brief Get description for specified error code
*
* @return Pointer to string allocated in thread specific memory
* @param err Error number
*/
OSAPI_EXPORT const char *
os_strerror (
_In_ int err);
#if defined (__cplusplus)
}
#endif
#endif /* OS_ERRNO_H */

167
src/os/include/os/os_heap.h Normal file
View file

@ -0,0 +1,167 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/****************************************************************
* Interface definition for OS layer heap memory managment *
****************************************************************/
/** \file os_heap.h
* \brief Heap memory management
*
* os_heap.h provides abstraction to heap memory management functions.
*/
#ifndef OS_HEAP_H
#define OS_HEAP_H
#if defined (__cplusplus)
extern "C" {
#endif
/* !!!!!!!!NOTE From here no more includes are allowed!!!!!!! */
/** \brief Allocate memory from heap
*
* Allocate memory from heap with the identified size. The returned pointer must be free'd with
* os_free. If size is 0, os_malloc_s will still return a non-NULL pointer which must be free'd
* with os_free.
*
* Possible Results:
* - returns pointer to allocated memory, abort() if out of memory detected
*/
_Check_return_ _Ret_bytecap_(size)
OSAPI_EXPORT void * os_malloc(_In_ size_t size);
/** \brief Allocate memory from heap
*
* Allocate memory from heap with the identified size. The returned pointer must be free'd with
* os_free. If size is 0, os_malloc_s will still return a non-NULL pointer which must be free'd
* with os_free.
*
* Possible Results:
* - returns pointer to allocated memory, or null if out of memory
*/
_Check_return_ _Ret_opt_bytecap_(size)
OSAPI_EXPORT void * os_malloc_s(_In_ size_t size);
/** \brief Allocate zeroed memory from heap
*
* Allocate memory from heap with the identified size and initialized to zero. The returned
* pointer must be free'd with os_free. If size is 0, os_malloc_0_s will still return a non-NULL
* pointer which must be free'd with os_free.
*
* Possible Results:
* - returns pointer to allocated zeroed memory, abort() if out of memory detected
*/
_Check_return_
_Ret_bytecount_(size)
OSAPI_EXPORT void *
os_malloc_0(_In_ size_t size)
__attribute_malloc__
__attribute_alloc_size__((1));
/** \brief Allocate zeroed memory from heap
*
* Allocate memory from heap with the identified size and initialized to zero. The returned
* pointer must be free'd with os_free. If size is 0, os_malloc_0_s will still return a non-NULL
* pointer which must be free'd with os_free.
*
* Possible Results:
* - returns pointer to allocated zeroed memory, or null if out of memory
*/
_Check_return_
_Ret_opt_bytecount_(size)
OSAPI_EXPORT void *
os_malloc_0_s(_In_ size_t size)
__attribute_malloc__
__attribute_alloc_size__((1));
/** \brief Allocate memory from heap for an array with count elements of size size
*
* The allocated memory is initialized to zero. The returned pointer must be free'd
* with os_free. If size and/or count is 0, os_calloc will still return a non-NULL
* pointer which must be free'd with os_free.
*
* Possible Results:
* - returns pointer to allocated and zeroed memory, abort() if out of memory detected
*/
_Check_return_
_Ret_bytecount_(count * size)
OSAPI_EXPORT void *
os_calloc(_In_ size_t count,
_In_ size_t size)
__attribute_malloc__;
/** \brief Allocate memory from heap for an array with count elements of size size
*
* The allocated memory is initialized to zero. The returned pointer must be free'd
* with os_free. If size and/or count is 0, os_calloc_s will still return a non-NULL
* pointer which must be free'd with os_free.
*
* Possible Results:
* - returns pointer to allocated and zeroed memory, or null if out of memory
*/
_Check_return_
_Ret_opt_bytecount_(count * size)
OSAPI_EXPORT void *
os_calloc_s(_In_ size_t count,
_In_ size_t size)
__attribute_malloc__;
/** \brief Reallocate memory from heap
*
* Reallocate memory from heap. If memblk is NULL the function returns os_malloc_s(size). If
* size is 0, os_realloc_s free's the memory pointed to by memblk and returns a pointer as if
* os_malloc_s(0) was invoked. The returned pointer must be free'd with os_free.
* Possible Results:
* - return pointer to reallocated memory, abort() if out of memory detected
*/
_Check_return_
_Ret_bytecap_(size)
OSAPI_EXPORT void *
os_realloc(
_Pre_maybenull_ _Post_ptr_invalid_ void *memblk,
_In_ size_t size)
__attribute_malloc__
__attribute_alloc_size__((1));
/** \brief Reallocate memory from heap
*
* Reallocate memory from heap. If memblk is NULL the function returns os_malloc_s(size). If
* size is 0, os_realloc_s free's the memory pointed to by memblk and returns a pointer as if
* os_malloc_s(0) was invoked. The returned pointer must be free'd with os_free.
* Possible Results:
* - return pointer to reallocated memory, or null if out of memory .
*/
_Success_(return != NULL)
_Check_return_
_Ret_opt_bytecap_(size)
OSAPI_EXPORT void *
os_realloc_s(
_Pre_maybenull_ _Post_ptr_invalid_ void *memblk,
_In_ size_t size)
__attribute_malloc__
__attribute_alloc_size__((1));
/** \brief Free allocated memory and return it to heap
*
* Free the allocated memory pointed to by \b ptr
* and release it to the heap. When \b ptr is NULL,
* os_free will return without doing any action.
*/
OSAPI_EXPORT void
os_free(_Pre_maybenull_ _Post_ptr_invalid_ void *ptr);
#if defined (__cplusplus)
}
#endif
#endif /* OS_HEAP_H */

View file

@ -0,0 +1,18 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_INIT_H
#define OS_INIT_H
void os_osInit(void);
void os_osExit(void);
#endif

View file

@ -0,0 +1,79 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_ITER_H
#define OS_ITER_H
#if defined(__cplusplus)
extern "C" {
#endif
typedef struct os_iter_s os_iter; /* opaque type */
_Check_return_
_Ret_valid_
OSAPI_EXPORT os_iter *
os_iterNew(
void);
OSAPI_EXPORT void
os_iterFree(
_In_opt_ _Post_ptr_invalid_ os_iter *iter,
_In_opt_ void(*func)(_Inout_ void *));
OSAPI_EXPORT _Ret_range_(0, INT32_MAX) uint32_t
os_iterLength(
_In_ const os_iter *__restrict iter);
/* Negative integers (borrowed from Python) can be used to access elements in
the iter. Most often it is used as a shorthand to access the last element.
i.e. os_iterOjbect(iter, -1) is functionally equivalent to
os_iterOjbect(iter, os_iterLength(iter) - 1) */
/* Special constant functionally equivalent to the value returned by
os_iterLength when passed as an index to os_iterInsert. INT32_MIN never
represents a valid negative index as it is exactly -(pow(2, n - 1)), whereas
the maximum positive value is exactly (pow(2, n - 1) - 1), therefore the
resulting index would always be negative */
#define OS_ITER_LENGTH (INT32_MIN)
OSAPI_EXPORT _Success_(return >= 0) _Ret_range_(-1, INT32_MAX) int32_t
os_iterInsert(
_Inout_ os_iter *iter,
_In_opt_ void *object,
_In_ int32_t index);
#define os_iterPrepend(iter, ojbect) \
os_iterInsert((iter), (object), 0)
#define os_iterAppend(iter, object) \
os_iterInsert((iter), (object), OS_ITER_LENGTH)
OSAPI_EXPORT _Ret_opt_valid_ void *
os_iterObject(
_In_ const os_iter *iter,
_In_range_(INT32_MIN+1, INT32_MAX) int32_t index);
OSAPI_EXPORT _Ret_opt_valid_ void *
os_iterTake(
_Inout_ os_iter *iter,
_In_range_(INT32_MIN+1, INT32_MAX) int32_t index);
OSAPI_EXPORT void
os_iterWalk(
_In_ const os_iter *iter,
_In_ void(*func)(_Inout_ void *obj, _Inout_opt_ void *arg),
_Inout_opt_ void *arg);
#if defined (__cplusplus)
}
#endif
#endif /* OS_ITER_H */

View file

@ -0,0 +1,27 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_PUBLIC_H
#define OS_PLATFORM_PUBLIC_H
#if __linux__ == 1
#include "os/posix/os_platform_public.h"
#elif defined(__VXWORKS__)
#include "os/posix/os_platform_public.h"
#elif defined(_MSC_VER)
#include "os/windows/os_platform_public.h"
#elif defined __APPLE__
#include "os/posix/os_platform_public.h"
#else
#error "Platform missing from os_public.h list"
#endif
#endif

View file

@ -0,0 +1,95 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/****************************************************************
* Interface definition for process management *
****************************************************************/
/** \file os_process.h
* \brief Process management - process creation and termination
*/
#ifndef OS_PROCESS_H
#define OS_PROCESS_H
#if defined (__cplusplus)
extern "C" {
#endif
#include "os/os_defs.h"
/* !!!!!!!!NOTE From here no more includes are allowed!!!!!!! */
/** \brief Return the process ID of the calling process
*
* Possible Results:
* - returns the process ID of the calling process
*/
OSAPI_EXPORT os_procId os_procIdSelf(void);
/** \brief Figure out the identity of the current process
*
* Possible Results:
* - returns the actual length of procIdentity
*
* Postcondition:
* - \b procIdentity is ""
* the process identity could not be determined
* - \b procIdentity is "<decimal number>" | "0x<hexadecimal number>"
* only the process numeric identity could be determined
* - \b procIdentity is "<process name> (<decimal number>)" | "<process name> (0x<hexadecimal number>)"
* the process name and numeric identity could be determined
*
* \b procIdentity will not be filled beyond the specified \b procIdentitySize
*/
OSAPI_EXPORT int
os_procNamePid(
_Out_writes_z_(procIdentitySize) char *procIdentity,
_In_ size_t procIdentitySize);
/** \brief Figure out the name of the current process
*
* Possible Results:
* - returns the actual length of procName
*
* Postcondition:
* - \b procName is ""
* the process name could not be determined
* - \b procName is "<process name>"
* the process name could be determined
*
* \b procName will not be filled beyond the specified \b procNameSize
*/
OSAPI_EXPORT int
os_procName(
_Out_writes_z_(procNameSize) char *procName,
_In_ size_t procNameSize);
/** \brief Register an process exit handler
*
* Register an process exit handler. Multiple handlers may be
* registered. The handlers are called in reverse order of
* registration.
*
* Possible Results:
* - os_resultSuccess: function registered
* - os_resultFail: function could not be registered
* - assertion failure: function = NULL
*/
OSAPI_EXPORT os_result
os_procAtExit(
_In_ void (*function)(void));
#if defined (__cplusplus)
}
#endif
#endif /* OS_PROCESS_H */

View file

@ -0,0 +1,19 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PUBLIC_H
#define OS_PUBLIC_H
#include <stddef.h>
#include "os/os_platform_public.h"
#include "os/os_decl_attributes.h"
#endif

View file

@ -0,0 +1,137 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_REPORT_H
#define OS_REPORT_H
#include <stdarg.h>
#if defined (__cplusplus)
extern "C" {
#endif
/* !!!!!!!!NOTE From here no more includes are allowed!!!!!!! */
/* Subcomponents might need to alter the report before actually handing it over
* to os_report. Since os_report truncates messages, those components can get
* away with fixed size buffers as well, but the maximum size must known at
* that point.
*/
#define OS_REPORT_BUFLEN 1024
/*
Note - in the below the check of reportType against os_reportVerbosity is also present
in os_report. By duplicating it we avoid putting the call onto the stack and evaluating
args if not necessary.
*/
#define OS_REPORT(type,context,code,message,...) \
(((type) >= os_reportVerbosity) ? os_report((type),(context),__FILE__,__LINE__,(code),(message),##__VA_ARGS__) : (void)0)
#define OS_DEBUG(context,code,message,...) OS_REPORT(OS_REPORT_DEBUG,(context),(code),(message),##__VA_ARGS__)
#define OS_INFO(context,code,message,...) OS_REPORT(OS_REPORT_INFO,(context),(code),(message),##__VA_ARGS__)
#define OS_WARNING(context,code,message,...) OS_REPORT(OS_REPORT_WARNING,(context),(code),(message),##__VA_ARGS__)
#define OS_ERROR(context,code,message,...) OS_REPORT(OS_REPORT_ERROR,(context),(code),(message),##__VA_ARGS__)
#define OS_CRITICAL(context,code,message,...) OS_REPORT(OS_REPORT_CRITICAL,(context),(code),(message),##__VA_ARGS__)
#define OS_FATAL(context,code,message,...) OS_REPORT(OS_REPORT_FATAL,(context),(code),(message),##__VA_ARGS__)
#define OS_REPORT_STACK() \
os_report_stack()
#define OS_REPORT_FLUSH(condition) \
os_report_flush((condition), OS_FUNCTION, __FILE__, __LINE__)
/**
* These types are an ordered series of incremental 'importance' (to the user)
* levels.
* @see os_reportVerbosity
*/
typedef enum os_reportType {
OS_REPORT_DEBUG,
OS_REPORT_INFO,
OS_REPORT_WARNING,
OS_REPORT_ERROR,
OS_REPORT_FATAL,
OS_REPORT_CRITICAL,
OS_REPORT_NONE
} os_reportType;
OSAPI_EXPORT extern os_reportType os_reportVerbosity;
OSAPI_EXPORT void
os_reportInit(_In_ bool forceReInit);
OSAPI_EXPORT void
os_reportExit(void);
/** \brief Report message
*
* Consider this function private. It should be invoked by reporting functions
* specified in the language bindings only.
*
* @param type type of report
* @param context context in which report was generated, often function name
* from which function was invoked
* @param path path of file from which function was invoked
* @param line line of file from which function was invoked
* @param code error code associated with the report
* @param format message to log
* @param ... Parameter to log
*/
OSAPI_EXPORT void
os_report(
_In_ os_reportType type,
_In_z_ const char *context,
_In_z_ const char *path,
_In_ int32_t line,
_In_ int32_t code,
_In_z_ _Printf_format_string_ const char *format,
...) __attribute_format__((printf,6,7));
/*****************************************
* Report stack related functions
*****************************************/
/**
* The os_report_stack operation enables a report stack for the current thread.
* The stack will be disabled again by the os_report_flush operation.
*/
OSAPI_EXPORT void
os_report_stack(
void);
/**
* The os_report_stack_free operation frees all memory allocated by the current
* thread for the report stack.
*/
OSAPI_EXPORT void
os_report_stack_free(
void);
/**
* The os_report_flush operation removes the report message from the stack,
* and if valid is TRUE also writes them into the report device.
* This operation additionally disables the stack.
*/
OSAPI_EXPORT void
os_report_flush(
_In_ bool valid,
_In_z_ const char *context,
_In_z_ const char *file,
_In_ int line);
#if defined (__cplusplus)
}
#endif
#endif /* OS_REPORT_H */

View file

@ -0,0 +1,392 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_SOCKET_H
#define OS_SOCKET_H
#ifndef OS_SOCKET_HAS_IPV6
#error "OS_SOCKET_HAS_IPV6 should have been defined by os_platform_socket.h"
#endif
#ifndef OS_IFNAMESIZE
#error "OS_IFNAMESIZE should have been defined by os_platform_socket.h"
#endif
#ifndef OS_SOCKET_HAS_SA_LEN
#error "OS_SOCKET_HAS_SA_LEN should have been defined by os_platform_socket.h"
#endif
#ifndef OS_NO_SIOCGIFINDEX
#error "OS_NO_SIOCGIFINDEX should have been defined by os_platform_socket.h"
#endif
#ifndef OS_NO_NETLINK
#error "OS_NO_NETLINK should have been defined by os_platform_socket.h"
#endif
#ifndef OS_SOCKET_HAS_SSM
#error "OS_SOCKET_HAS_SSM should have been defined by os_platform_socket.h"
#endif
#if defined (__cplusplus)
extern "C" {
#endif
/* !!!!!!!!NOTE From here no more includes are allowed!!!!!!! */
/**
* @file
* @addtogroup OS_NET
* @{
*/
/**
* Socket handle type. SOCKET on windows, int otherwise.
*/
/* Indirecting all the socket types. Some IPv6 & protocol agnostic
stuff seems to be not always be available */
typedef struct sockaddr_in os_sockaddr_in;
typedef struct sockaddr os_sockaddr;
#ifdef OS_SOCKET_HAS_IPV6
#if (OS_SOCKET_HAS_IPV6 == 0)
struct foo_in6_addr {
unsigned char foo_s6_addr[16];
};
typedef struct foo_in6_addr os_in6_addr;
struct foo_sockaddr_in6 {
os_os_ushort sin6_family;
os_os_ushort sin6_port;
uint32_t sin6_flowinfo;
os_in6_addr sin6_addr;
uint32_t sin6_scope_id;
};
typedef struct foo_sockaddr_in6 os_sockaddr_in6;
struct foo_sockaddr_storage {
#if (OS_SOCKET_HAS_SA_LEN == 1)
os_uchar ss_len;
os_uchar ss_family;
#else
os_os_ushort ss_family;
#endif
/* Below aren't 'real' members. Just here for padding to make it big enough
for any possible IPv6 address. Not that IPv6 works on this OS. */
os_os_ushort sin6_port;
uint32_t sin6_flowinfo;
os_in6_addr sin6_addr;
uint32_t sin6_scope_id;
};
typedef struct foo_sockaddr_storage os_sockaddr_storage;
struct foo_ipv6_mreq {
os_in6_addr ipv6mr_multiaddr;
unsigned int ipv6mr_interface;
};
typedef struct foo_ipv6_mreq os_ipv6_mreq;
#else
typedef struct ipv6_mreq os_ipv6_mreq;
typedef struct in6_addr os_in6_addr;
#if defined (OSPL_VXWORKS653)
typedef struct sockaddr_in os_sockaddr_storage;
#else
typedef struct sockaddr_storage os_sockaddr_storage;
#endif
typedef struct sockaddr_in6 os_sockaddr_in6;
#endif
#else
#error OS_SOCKET_HAS_IPV6 not defined
#endif
extern const os_in6_addr os_in6addr_any;
extern const os_in6_addr os_in6addr_loopback;
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46 /* strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") + 1 */
#endif
#define INET6_ADDRSTRLEN_EXTENDED (INET6_ADDRSTRLEN + 8) /* + strlen("[]:12345") */
/* The maximum buffersize needed to safely store the output of
* os_sockaddrAddressPortToString or os_sockaddrAddressToString. */
#define OS_SOCKET_MAX_ADDRSTRLEN INET6_ADDRSTRLEN_EXTENDED
#define SD_FLAG_IS_SET(flags, flag) ((((uint32_t)(flags) & (uint32_t)(flag))) != 0U)
/**
* Structure to hold a network interface's attributes
*/
typedef struct os_ifAttributes_s {
/**
* The network interface name (or at least OS_IFNAMESIZE - 1 charcaters thereof)
*/
char name[OS_IFNAMESIZE];
/**
* Iff the interface is IPv4 holds the ioctl query result flags for this interface.
*/
uint32_t flags;
/**
* The network interface address of this interface.
*/
os_sockaddr_storage address;
/**
* Iff this is an IPv4 interface, holds the broadcast address for the sub-network this
* interface is connected to.
*/
os_sockaddr_storage broadcast_address;
/**
* Iff this is an IPv4 interface, holds the subnet mast for this interface
*/
os_sockaddr_storage network_mask;
/**
* Holds the interface index for this interface.
*/
unsigned interfaceIndexNo;
} os_ifAttributes;
OSAPI_EXPORT os_result
os_sockQueryInterfaces(
os_ifAttributes *ifList,
uint32_t listSize,
uint32_t *validElements);
/**
* Fill-in a pre-allocated list of os_ifAttributes_s with details of
* the available IPv6 network interfaces.
* @param listSize Number of elements there is space for in the list.
* @param ifList Pointer to head of list
* @param validElements Out param to hold the number of interfaces found
* whose detauils have been returned.
* @return os_resultSuccess if 0 or more interfaces were found, os_resultFail if
* an error occurred.
* @see os_sockQueryInterfaces
*/
OSAPI_EXPORT os_result
os_sockQueryIPv6Interfaces(
os_ifAttributes *ifList,
uint32_t listSize,
uint32_t *validElements);
OSAPI_EXPORT os_socket
os_sockNew(
int domain, /* AF_INET */
int type /* SOCK_DGRAM */);
OSAPI_EXPORT os_result
os_sockBind(
os_socket s,
const struct sockaddr *name,
uint32_t namelen);
OSAPI_EXPORT os_result
os_sockGetsockname(
os_socket s,
const struct sockaddr *name,
uint32_t namelen);
OSAPI_EXPORT os_result
os_sockSendto(
os_socket s,
const void *msg,
size_t len,
const struct sockaddr *to,
size_t tolen,
size_t *bytesSent);
OSAPI_EXPORT os_result
os_sockRecvfrom(
os_socket s,
void *buf,
size_t len,
struct sockaddr *from,
size_t *fromlen,
size_t *bytesRead);
OSAPI_EXPORT os_result
os_sockGetsockopt(
os_socket s,
int32_t level, /* SOL_SOCKET */
int32_t optname, /* SO_REUSEADDR, SO_DONTROUTE, SO_BROADCAST, SO_SNDBUF, SO_RCVBUF */
void *optval,
uint32_t *optlen);
OSAPI_EXPORT os_result
os_sockSetsockopt(
os_socket s,
int32_t level, /* SOL_SOCKET */
int32_t optname, /* SO_REUSEADDR, SO_DONTROUTE, SO_BROADCAST, SO_SNDBUF, SO_RCVBUF */
const void *optval,
uint32_t optlen);
/**
* Sets the I/O on the socket to nonblocking if value is nonzero,
* or to blocking if value is 0.
*
* @param s The socket to set the I/O mode for
* @param nonblock Boolean indicating whether nonblocking mode should be enabled
* @return - os_resultSuccess: if the flag could be set successfully
* - os_resultBusy: if the flag could not be set because a blocking
* call is in progress on the socket
* - os_resultInvalid: if s is not a valid socket
* - os_resultFail: if an operating system error occurred
*/
OSAPI_EXPORT os_result
os_sockSetNonBlocking(
os_socket s,
bool nonblock);
OSAPI_EXPORT os_result
os_sockFree(
os_socket s);
#ifdef WIN32
/* SOCKETs on Windows are NOT integers. The nfds parameter is only there for
compatibility, the implementation ignores it. Implicit casts will generate
warnings though, therefore os_sockSelect on Windows is a proxy macro that
discards the parameter */
#define os_sockSelect(nfds, readfds, writefds, errorfds, timeout) \
os__sockSelect((readfds), (writefds), (errorfds), (timeout))
OSAPI_EXPORT int32_t
os__sockSelect(
fd_set *readfds,
fd_set *writefds,
fd_set *errorfds,
os_time *timeout);
#else
OSAPI_EXPORT int32_t
os_sockSelect(
int32_t nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *errorfds,
os_time *timeout);
#endif /* WIN32 */
/* docced in implementation file */
OSAPI_EXPORT os_result
os_sockaddrInit(os_sockaddr* sa,
bool isIPv4); /* IPvX is poorly abstracted; this is temporary */
/* docced in implementation file */
OSAPI_EXPORT bool
os_sockaddrIPAddressEqual(const os_sockaddr* this_sock,
const os_sockaddr* that_sock);
OSAPI_EXPORT int
os_sockaddrIpAddressCompare(const os_sockaddr* addr1,
const os_sockaddr* addr2) __nonnull_all__
__attribute_pure__;
/* docced in implementation file */
OSAPI_EXPORT bool
os_sockaddrSameSubnet(const os_sockaddr* thisSock,
const os_sockaddr* thatSock,
const os_sockaddr* mask);
/**
* Convert a socket address to a string format presentation representation
* @param sa The socket address struct.
* @param buffer A character buffer to hold the string rep of the address.
* @param buflen The (max) size of the buffer
* @return Pointer to start of string
*/
OSAPI_EXPORT char*
os_sockaddrAddressToString(const os_sockaddr* sa,
char* buffer, size_t buflen);
/**
* Convert a socket address to a string format representation including the
* portnumber.
* @param sa The socket address struct.
* @param buffer A character buffer to hold the string rep of the address.
* @param buflen The (max) size of the buffer
* @return Pointer to start of string
*/
OSAPI_EXPORT char*
os_sockaddrAddressPortToString(
const os_sockaddr* sa,
char* buffer,
size_t buflen);
/**
* Convert the provided addressString into a os_sockaddr.
*
* @param addressString The string representation of a network address.
* @param addressOut A pointer to an os_sockaddr. Must be big enough for
* the address type specified by the string. This implies it should
* generally be the address of an os_sockaddr_storage for safety's sake.
* @param isIPv4 If the addressString is a hostname specifies whether
* and IPv4 address should be returned. If false an Ipv6 address will be
* requested. If the address is in either valid decimal presentation format
* param will be ignored.
* @return true on successful conversion. false otherwise
*/
_Success_(return) OSAPI_EXPORT bool
os_sockaddrStringToAddress(
_In_z_ const char *addressString,
_When_(isIPv4, _Out_writes_bytes_(sizeof(os_sockaddr_in)))
_When_(!isIPv4, _Out_writes_bytes_(sizeof(os_sockaddr_in6)))
os_sockaddr *addressOut,
_In_ bool isIPv4);
/* docced in implementation file */
OSAPI_EXPORT bool
os_sockaddrIsLoopback(const os_sockaddr* thisSock);
/**
* Returns sizeof(sa) based on the family of the actual content.
* @param sa the sockaddr to get the actual size for
* @return The actual size sa based on the family. If the family is
* unknown 0 will be returned.
* @pre sa is a valid sockaddr pointer
*/
OSAPI_EXPORT size_t
os_sockaddrSizeof(const os_sockaddr* sa);
/**
* Sets the address of the sockaddr to the special IN_ADDR_ANY value.
* @param sa the sockaddr to set the address for
* @pre sa is a valid sockaddr pointer
* @post Address of sa is set to the special IN_ADDR_ANY value
*/
OSAPI_EXPORT void
os_sockaddrSetInAddrAny(os_sockaddr* sa);
/**
* Sets the port number in the supplied sockaddr.
* @param sa the sockaddr to set the port in
* @param port the port number to be set in network byte order
* @pre sa is a valid sockaddr pointer
* @post Port number of sa is set to port
*/
OSAPI_EXPORT void
os_sockaddrSetPort(os_sockaddr* sa, uint16_t port);
/**
* Retrieves the port number from the supplied sockaddr.
* @param sa the sockaddr to retrieve the port from
* @return The port number stored in the supplied sockaddr (hence in network byte order)
* @pre sa is a valid sockaddr pointer
*/
OSAPI_EXPORT uint16_t
os_sockaddrGetPort(const os_sockaddr* const sa);
/**
* @}
*/
#if defined (__cplusplus)
}
#endif
#endif /* OS_SOCKET_H */

View file

@ -0,0 +1,851 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/****************************************************************
* Interface definition for standard operating system features *
****************************************************************/
/** \file os_stdlib.h
* \brief standard operating system features
*/
#ifndef OS_STDLIB_H
#define OS_STDLIB_H
#include <stdio.h>
#include <stdarg.h>
#include "os/os_defs.h"
#if defined (__cplusplus)
extern "C" {
#endif
/* !!!!!!!!NOTE From here no more includes are allowed!!!!!!! */
/** \brief Get host or processor name
*
* Possible Results:
* - assertion failure: hostname = NULL
* - returns os_resultSuccess if
* hostname correctly identifies the name of the host
* - returns os_resultFail if
* actual hostname is longer than buffersize
*/
OSAPI_EXPORT os_result
os_gethostname(
char *hostname,
size_t buffersize);
/** \brief Get environment variable definition
*
* Postcondition:
* - the pointer returned is only to be accessed readonly
*
* Possible Results:
* - assertion failure: variable = NULL
* - returns pointer to value of variable if
* variable is found
* - returns NULL if
* variable is not found
*
* TODO CHAM-379 : Coverity generates a tainted string.
* For now, the Coverity warning reported intentional in Coverity.
*/
OSAPI_EXPORT _Ret_opt_z_ const char *
os_getenv(
_In_z_ const char *variable);
/** \brief Set environment variable definition
*
* Precondition:
* - variable_definition follows the format "<variable>=<value>"
*
* Possible Results:
* - assertion failure: variable_definition = NULL
* - returns os_resultSuccess if
* environment variable is set according the variable_definition
* - returns os_resultFail if
* environment variable could not be set according the
* variable_definition
* @deprecated This function is a thin, bordering on anorexic, wrapper to
* putenv. putenv behaviour varies from unsafe to leaky across different
* platforms. Use ::os_setenv instead.
*/
OSAPI_EXPORT os_result
os_putenv(
char *variable_definition);
/** \brief Get file seperator
*
* Possible Results:
* - "<file-seperator-character>"
*/
OSAPI_EXPORT const char *
os_fileSep(void);
/** \brief Get path seperator
*
* Possible Results:
* - "<file-seperator-character>"
*/
OSAPI_EXPORT const char *
os_pathSep(void);
#define OS_PATHSEPCHAR OS_OS_PATHSEPCHAR
#define OS_EXESUFFIX OS_OS_EXESUFFIX
#define OS_BATSUFFIX OS_OS_BATSUFFIX
#define OS_LIB_LOAD_PATH_VAR OS_OS_LIB_LOAD_PATH_VAR
/** \brief Check user's permissions for a file
*
* Precondition:
* - permission is a mask of:
* OS_ROK check for read access
* OS_WOK check for write access
* OS_XOK check for execution access
* OS_FOK check for existence of the file
*
* Possible results:
* - return os_resultSuccess if
* requested file access is granted
* - return os_resultFail if
* requested file access is not granted
*/
OSAPI_EXPORT os_result
os_access(
const char *file_path,
int32_t permission);
/** \brief Locate an executable file in the path
*
* Precondition:
* - permission is a mask of:
* OS_ROK check for read access
* OS_WOK check for write access
* OS_XOK check for execution access
* OS_FOK check for existence of the file
*
* Possible results:
* - return an os_malloc-ed string if a file with
* the given permission mask was found in
* PATH. The return value contains the full
* path name of the file found.
* If the name of the file contains an
* absolute or relative path, then no
* search is done in the PATH.
* - return NULL if no file was found in PATH
*/
OSAPI_EXPORT char *
os_locate(
const char *name,
int32_t permission);
/** \brief mkdir wrapper
*
* because operating systems has different
* interfaces to mkdir a wrapper is made
*
* Precondition:
* None
*
* Possible results:
* - return 0 if
* requested dir is created
* - return -1 if
* requested dir could not be created
*/
OSAPI_EXPORT int32_t
os_mkdir(
const char *path,
os_mode_t mode);
/** \brief Create a path including parent dirs
*
* Alternative to os_mkdir that creates all path elements instead
* of only the top-level directory
*
* Preconditions:
* None
*
* Possible results:
* - return os_resultSuccess if
* requested path is created
* - return os_resultFail if
* requested path could not be created
*
* When path creation fails an appropriate error message is reported
*/
OSAPI_EXPORT os_result
os_mkpath(
const char *path,
os_mode_t mode);
/** \brief dirname wrapper
*
* because not all operating systems have
* interfaces to dirname a wrapper is made
*
* Precondition:
* None
*
* Possible results:
* - return '.' if
* path is a null pointer
* - return char *
* to a string that is the parent directory of path
*/
OSAPI_EXPORT char * os_dirname_r(char *path);
/** \brief rindex wrapper
*
* because not all operating systems have
* interfaces to rindex a wrapper is made
*
* Precondition:
* None
*
* Possible results:
* - return NULL if
* char c is not found in string s
* - return address of last occurance of c in s
*/
OSAPI_EXPORT char *
os_rindex(
const char *s,
int c);
/** \brief index wrapper
*
* because not all operating systems have
* interfaces to index a wrapper is made
*
* Precondition:
* None
*
* Possible results:
* - return NULL if
* char c is not found in string s
* - return address of first occurance of c in s
*/
OSAPI_EXPORT char *
os_index(
const char *s,
int c);
/** \brief strdup wrapper
*
* because not all operating systems have
* interfaces to strdup a wrapper is made
*
* Precondition:
* None
* Postcondition:
* The allocated string must be freed using os_free
*
* Possible results:
* - return duplicate of the string s1 allocated via
* os_malloc
*/
_Ret_z_
_Check_return_
OSAPI_EXPORT char *
os_strdup(
_In_z_ const char *s1) __nonnull_all__
__attribute_malloc__
__attribute_returns_nonnull__
__attribute_warn_unused_result__;
/** \brief os_strsep wrapper
*
* See strsep()
*/
OSAPI_EXPORT char *
os_strsep(
char **stringp,
const char *delim);
/** \brief os_vsnprintf wrapper
*
* Microsoft generates deprected warnings for vsnprintf,
* wrapper removes warnings for win32
*
* Precondition:
* None
* Postcondition:
* None
*
* Possible results:
* - os_vsnprintf() does not write more than size bytes (including the trailing '\0').
* If the output was truncated due to this limit then the return value is the
* number of characters (not including the trailing '\0') which would have been
* written to the final string if enough space had been available.
* Thus, a return value of size or more means that the output was truncated.
*/
OSAPI_EXPORT int
os_vsnprintf(
char *str,
size_t size,
const char *format,
va_list args);
/** \brief fprintf wrapper with disabled broken pipe signals
*
* A fprintf can cause an broken pipe signal that can result in a deadlock
* if the interrupted thread is holding recourses needed by for example the
* signal handler thread.
*
* Precondition:
* None
* Postcondition:
* None
*
* Possible results:
* - return
* Upon successful completion will return the number of
* bytes written to file
* or a negative value if an error occurred.
* errno will be set in such case
* - Writes formatted output to file.
*/
int
os_vfprintfnosigpipe(
FILE *file,
const char *format,
va_list args);
/** \brief strtoll wrapper
*
* Translate string str to long long value considering base,
* and sign. If base is 0, base is determined from
* str ([1-9]+ base = 10, 0x[0-9]+ base = 16,
* 0X[0-9]+ base = 16, 0[0-9] base = 8).
*
* Precondition:
* errno is set to 0
*
* Possible results:
* - return 0 and errno == EINVAL in case of conversion error
* - return OS_LLONG_MIN and errno == ERANGE
* - return OS_LLONG_MAX and errno == ERANGE
* - return value(str)
*/
OSAPI_EXPORT long long
os_strtoll(
const char *str,
char **endptr,
int32_t base);
/** \brief strtoull wrapper
*
* Translate string str to unsigned long long value considering
* base. If base is 0, base is determined from
* str ([1-9]+ base = 10, 0x[0-9]+ base = 16,
* 0X[0-9]+ base = 16, 0[0-9] base = 8).
*
* Precondition:
* errno is set to 0
*
* Possible results:
* - return 0 and errno == EINVAL in case of conversion error
* - return OS_ULLONG_MIN and errno == ERANGE
* - return OS_ULLONG_MAX and errno == ERANGE
* - return value(str)
*/
OSAPI_EXPORT unsigned long long
os_strtoull(
const char *str,
char **endptr,
int32_t base);
/** \brief atoll wrapper
*
* Translate string to long long value considering base 10.
*
* Precondition:
* errno is set to 0
*
* Possible results:
* - return os_strtoll(str, 10)
*/
OSAPI_EXPORT long long
os_atoll(
const char *str);
/** \brief atoull wrapper
*
* Translate string to unsigned long long value considering base 10.
*
* Precondition:
* errno is set to 0
*
* Possible results:
* - return os_strtoll(str, 10)
*/
OSAPI_EXPORT unsigned long long
os_atoull(
const char *str);
/** \brief lltostr wrapper
*
* Translate long long value into string representation based
* on radix 10.
*
* Precondition:
* none
*
* Possible results:
* - return 0 and errno == EINVAL in case of conversion error
* - return value(str)
*/
OSAPI_EXPORT char *
os_lltostr(
long long num,
char *str,
size_t len,
char **endptr);
/** \brief ulltostr wrapper
*
* Translate unsigned long long value into string representation based
* on radix 10.
*
* Precondition:
* none
*
* Possible results:
* - return 0 and errno == EINVAL in case of conversion error
* - return value(str)
*/
OSAPI_EXPORT char *
os_ulltostr(
unsigned long long num,
char *str,
size_t len,
char **endptr);
/** \brief strtod wrapper
*
* Translate string to double value considering base 10.
*
* Normal strtod is locale dependent, meaning that if you
* provide "2.2" and lc_numeric is ',', then the result
* would be 2. This function makes sure that both "2.2"
* (which is mostly used) and "2,2" (which could be provided
* by applications) are translated to 2.2 when the locale
* indicates that lc_numeric is ','.
*
* Precondition:
* none
*
* Possible results:
* - return value(str)
*/
OSAPI_EXPORT double
os_strtod(const char *nptr, char **endptr);
/** \brief strtof wrapper
*
* Translate string to float value considering base 10.
*
* Normal strtof is locale dependent, meaning that if you
* provide "2.2" and lc_numeric is ',', then the result
* would be 2. This function makes sure that both "2.2"
* (which is mostly used) and "2,2" (which could be provided
* by applications) are translated to 2.2 when the locale
* indicates that lc_numeric is ','.
*
* Precondition:
* none
*
* Possible results:
* - return value(str)
*/
OSAPI_EXPORT float
os_strtof(const char *nptr, char **endptr);
/** \brief os_strtod mirror
*
* Translate double to string considering base 10.
*
* The function dtostr doesn't exists and can be done by
* snprintf((char*)dst, "%f", (double)src).
* But like strtod, snprint is locale dependent, meaning
* that if you provide 2.2 and lc_numeric is ',' then the
* result would be "2,2". This comma can cause problems
* when serializing data to other nodes with different
* locales.
* This function makes sure that 2.2 is translated into
* "2.2", whatever lc_numeric is set ('.' or ',').
*
* Precondition:
* none
*
* Possible results:
* - return value(str)
*/
OSAPI_EXPORT int
os_dtostr(double src, char *str, size_t size);
/** \brief os_strtof mirror
*
* Translate float to string considering base 10.
*
* The function ftostr doesn't exists and can be done by
* snprintf((char*)dst, "%f", (float)src).
* But like strtof, snprint is locale dependent, meaning
* that if you provide 2.2 and lc_numeric is ',' then the
* result would be "2,2". This comma can cause problems
* when serializing data to other nodes with different
* locales.
* This function makes sure that 2.2 is translated into
* "2.2", whatever lc_numeric is set ('.' or ',').
*
* Precondition:
* none
*
* Possible results:
* - return value(str)
*/
OSAPI_EXPORT int
os_ftostr(float src, char *str, size_t size);
/** \brief strcasecm wrapper
*
* Compare 2 strings conform strcasecmp
*
* Precondition:
* none
*
* Possible results:
* - return 0 and s1 equals s2
* - return <0 and s1 is less than s2
* - return >0 and s1 is greater than s2
*/
OSAPI_EXPORT int
os_strcasecmp(
const char *s1,
const char *s2);
/** \brief strncasecm wrapper
*
* Compare 2 strings conform strncasecmp
*
* Precondition:
* none
*
* Possible results:
* - return 0 and s1 equals s2 (maximum the first n characters)
* - return <0 and s1 is less than s2 (maximum the first n characters)
* - return >0 and s1 is greater than s2 (maximum the first n characters)
*/
OSAPI_EXPORT int
os_strncasecmp(
const char *s1,
const char *s2,
size_t n);
/** \brief strtok_r wrapper
*
* Tokenise strings based on delim
*
* Precondition:
* none
*
* Possible results:
* - return ptr to next token or NULL if there are no tokens left.
*/
OSAPI_EXPORT char *
os_strtok_r(char *str, const char *delim, char **saveptr);
struct os_stat {
/* The mode_t macro's (like OS_ISDIR) are defined in the platform specific header files! */
/* NEVER name these fields identical to the POSIX standard! Since e.g. the Linux implementation
has defined it as follows:
struct stat {
...
struct timespec st_mtim;
#define st_mtime st_mtim.tvsec
...
};
This results in the fact that our definition is also changed, causing compilation errors!
*/
os_mode_t stat_mode;
size_t stat_size;
os_time stat_mtime;
};
OSAPI_EXPORT os_result
os_stat(
const char *path,
struct os_stat *buf);
/** \brief Removes the file or directory given by name.
*
* This function is equivalent to POSIX remove(3)
*
*/
OSAPI_EXPORT os_result os_remove (const char *name);
/** \brief Renames a file or directory
*
* This function is equivalent to POSIX rename(3)
*
*/
OSAPI_EXPORT os_result os_rename (const char *oldpath, const char *newpath);
/** \brief Transforms the given filepath into a platform specific filepath.
*
* This translation function will replace any platform file seperator into
* the fileseperator of the current platform.
*
* Precondition:
* none
*
* Possible results:
* - returns normalized filepath conform current platform
* - return NULL if out of memory.
*/
_Ret_z_
_Must_inspect_result_
OSAPI_EXPORT char *
os_fileNormalize(
_In_z_ const char *filepath);
/**
* \brief Flushes the internal buffers associated with the file handle to disk
*
* Precondition:
* The file should be open.
*
* Possible results:
* - os_resultSuccess if function succeeded
* - os_resultFail if function failed
*/
OSAPI_EXPORT os_result
os_fsync(
FILE *fHandle);
/**
* \brief returns the location of the temporary files used by OpenSplice.
* This may be the key file describing the shared memory or the shared
* file itself depending on the operating system
*
* Precondition:
* none
*
* Possible results:
* - char * of the absolute path of the temporary location. This will return
* always return a valid value, using a default if necessary
*/
OSAPI_EXPORT _Ret_opt_z_ const char *
os_getTempDir(void);
/**
* \brief writes up to count bytes from the buffer pointed buf to the file referred to by the file descriptor fd.
*
*
* Precondition:
* none
*
* Possible results:
* - On success, the number of bytes written is returned (zero indicates
* nothing was written). On error, -1 is returned
*
*/
OSAPI_EXPORT ssize_t os_write(
_In_ int fd,
_In_reads_bytes_(count) void const* buf,
_In_ size_t count);
/**
* \brief the os_flockfile() function waits for *filehandle to be
* no longer locked by a different thread, then makes the current
* thread owner of *filehandle, and increments the lockcount.
* (not effective on VxWorks DKM platform)
*
* Precondition:
* none
*
* Possible results:
* - No error information is returned.
* The thread will block until the lock is acquired.
* An explicit call to os_funlockfile has to be used to release the lock.
*
*/
OSAPI_EXPORT void os_flockfile(
FILE *file);
/**
* \brief the os_funlockfile function decrements the lock count and releases
* the internal locking object of the *filehandle. The *filehandle must
* have been locked before by a call to os_flockfile.
* (not effective on VxWorks DKM platform)
*
* Precondition:
* none
*
* Possible results:
* - No error information is returned.
* The behaviour is undefined if a thread other than the current owner calls
* the os_funlockfile() function.
*
*/
OSAPI_EXPORT void os_funlockfile(
FILE *file);
/**
* \brief binary search algorithm on an already sorted list.
*
*
* Precondition:
* list must be sorted in ascending order
*
* Possible results:
* - On success, the number the matching item is returned. When the item
* does not exist, NULL is returned.
*
*/
OSAPI_EXPORT void *
os_bsearch(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar) (const void *, const void *));
/**
* \brief the os_getopt function gets the next option argument from the argument
* list specified by the argv and argc arguments. Normally these values come
* directly from the arguments received by main.
*
* The opts argument is a string that specifies the option characters that are
* valid for this program. An option character in this string can be followed
* by a colon (:) to indicate that it takes a required argument. If an option
* character is followed by two colons (::), its argument is optional;
*
*
* Precondition:
* none
*
* Possible results:
* - If an option was successfully found, then os_getopt() returns the option
* character. If all command-line options have been parsed, then
* os_getopt() returns -1. If os_getopt() encounters an option character that
* was not in opts, then '?' is returned. If os_getopt() encounters
* an option with a missing argument, then the return value depends on
* the first character in opts: if it is ':', then ':' is returned;
* otherwise '?' is returned.
*
*/
OSAPI_EXPORT int
os_getopt(
_In_range_(0, INT_MAX) int argc,
_In_reads_z_(argc) char **argv,
_In_z_ const char *opts);
/**
* \brief the os_set_opterr function sets the value of the opterr variable.
* opterr is used as a flag to suppress an error message generated by
* getopt. When opterr is set to 0, it suppresses the error message generated
* by getopt when that function does not recognize an option character.
*
* Precondition:
* none
*
* Possible results:
* - No error information is returned.
* Set the value of the opterr variable.
*
*/
OSAPI_EXPORT void
os_set_opterr(_In_range_(0, INT_MAX) int err);
/**
* \brief the os_get_opterr returns the value of the opterr variable.
* opterr is used as a flag to suppress an error message generated by
* getopt. When opterr is set to 0, it suppresses the error message generated
* by getopt when that function does not recognize an option character.
*
* Precondition:
* none
*
* Possible results:
* - return the value of the opterr variable.
*
*/
OSAPI_EXPORT int
os_get_opterr(void);
/**
* \brief the os_set_optind function sets the value of the optind variable.
*
* Precondition:
* none
*
* Possible results:
* - No error information is returned.
* Set the value of the optind variable.
*
*/
OSAPI_EXPORT void
os_set_optind(_In_range_(0, INT_MAX) int index);
/**
* \brief the os_get_optind function returns the value of the optind variable.
* optind is set by getopt to the index of the next element of the argv
* array to be processed. Once getopt has found all of the option arguments,
* this variable can be used to determine where the remaining non-option
* arguments begin. The initial value of this variable is 1.
*
* Precondition:
* none
*
* Possible results:
* - return the value of the optind variable.
*
*/
OSAPI_EXPORT int
os_get_optind(void);
/**
* \brief the os_get_optopt function returns the value of the optopt variable.
* optopt holds the unknown option character when that option
* character is not recognized by getopt.
*
* Precondition:
* none
*
* Possible results:
* - return the value of the optopt variable.
*
*/
OSAPI_EXPORT int
os_get_optopt(void);
/**
* \brief the os_get_optarg function returns the value of the optarg variable.
* optarg is set by getopt to point at the value of the option
* argument, for those options that accept arguments.
*
* Precondition:
* none
*
* Possible results:
* - return the value of the optarg variable.
*
*/
OSAPI_EXPORT char *
os_get_optarg(void);
#if defined (__cplusplus)
}
#endif
#endif /* OS_STDLIB_H */

367
src/os/include/os/os_sync.h Normal file
View file

@ -0,0 +1,367 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_SYNC_H
#define OS_SYNC_H
#if defined (__cplusplus)
extern "C" {
#endif
/** \brief Sets the priority inheritance mode for mutexes
* that are created after this call. (only effective on
* platforms that support priority inheritance)
*
* Possible Results:
* - returns os_resultSuccess if
* mutex is successfuly initialized
* - returns os_resultSuccess
*/
OSAPI_EXPORT os_result
os_mutexSetPriorityInheritanceMode(
bool enabled);
/** \brief Initialize the mutex
*
* Possible Results:
* - assertion failure: mutex = NULL
* - returns os_resultSuccess if
* mutex is successfuly initialized
* - returns os_resultFail if
* mutex is not initialized because of a failure
*/
OSAPI_EXPORT void
os_mutexInit(
_Out_ os_mutex *mutex)
__nonnull((1));
/** \brief Destroy the mutex
*
* Never returns on failure
*/
OSAPI_EXPORT void
os_mutexDestroy(
_Inout_ _Post_invalid_ os_mutex *mutex)
__nonnull_all__;
/** \brief Acquire the mutex.
*
* If you need to detect an error, use os_mutexLock_s instead.
*
* @see os_mutexLock_s
*/
_Acquires_nonreentrant_lock_(&mutex->lock)
OSAPI_EXPORT void
os_mutexLock(
_Inout_ os_mutex *mutex)
__nonnull_all__;
/**
* \brief Acquire the mutex. Returns whether the call succeeeded or an error
* occurred.
*
* Precondition:
* - mutex is not yet acquired by the calling thread
*
* Possible Results:
* - assertion failure: mutex = NULL
* - returns os_resultSuccess if
* mutex is acquired
* - returns os_resultFail if
* mutex is not acquired because of a failure
*/
_Check_return_
_When_(return == os_resultSuccess, _Acquires_nonreentrant_lock_(&mutex->lock))
OSAPI_EXPORT os_result
os_mutexLock_s(
_Inout_ os_mutex *mutex)
__nonnull_all__
__attribute_warn_unused_result__;
/** \brief Try to acquire the mutex, immediately return if the mutex
* is already acquired by another thread
*
* Precondition:
* - mutex is not yet acquired by the calling thread
*
* Possible Results:
* - assertion failure: mutex = NULL
* - returns os_resultSuccess if
* mutex is acquired
* - returns os_resultBusy if
* mutex is not acquired because it is already acquired
* by another thread
* - returns os_resultFail if
* mutex is not acquired because of a failure
*/
_Check_return_
_When_(return == os_resultSuccess, _Acquires_nonreentrant_lock_(&mutex->lock))
OSAPI_EXPORT os_result
os_mutexTryLock (
_Inout_ os_mutex *mutex)
__nonnull_all__
__attribute_warn_unused_result__;
/** \brief Release the acquired mutex
*/
_Releases_nonreentrant_lock_(&mutex->lock)
OSAPI_EXPORT void
os_mutexUnlock (
_Inout_ os_mutex *mutex)
__nonnull_all__;
/** \brief Initialize the condition variable
*
* Possible Results:
* - returns os_resultSuccess if
* cond is successfuly initialized
* - returns os_resultFail if
* cond is not initialized and can not be used
*/
OSAPI_EXPORT void
os_condInit(
_Out_ os_cond *cond,
_In_ os_mutex *mutex)
__nonnull((1,2));
/** \brief Destroy the condition variable
*/
OSAPI_EXPORT void
os_condDestroy(
_Inout_ _Post_invalid_ os_cond *cond)
__nonnull_all__;
/** \brief Wait for the condition
*
* Precondition:
* - mutex is acquired by the calling thread before calling
* os_condWait
*
* Postcondition:
* - mutex is still acquired by the calling thread and should
* be released by it
*/
OSAPI_EXPORT void
os_condWait(
os_cond *cond,
os_mutex *mutex)
__nonnull_all__;
/** \brief Wait for the condition but return when the specified
* time has expired before the condition is triggered
*
* Precondition:
* - mutex is acquired by the calling thread before calling
* os_condTimedWait
*
* Postcondition:
* - mutex is still acquired by the calling thread and should
* be released by it
*
* Possible Results:
* - assertion failure: cond = NULL || mutex = NULL ||
* time = NULL
* - returns os_resultSuccess if
* cond is triggered
* - returns os_resultTimeout if
* cond is timed out
* - returns os_resultFail if
* cond is not triggered nor is timed out but
* os_condTimedWait has returned because of a failure
*/
OSAPI_EXPORT os_result
os_condTimedWait(
os_cond *cond,
os_mutex *mutex,
const os_time *time)
__nonnull_all__;
/** \brief Signal the condition and wakeup one thread waiting
* for the condition
*
* Precondition:
* - the mutex used with the condition in general should be
* acquired by the calling thread before setting the
* condition state and signalling
*/
OSAPI_EXPORT void
os_condSignal(
os_cond *cond)
__nonnull_all__;
/** \brief Signal the condition and wakeup all thread waiting
* for the condition
*
* Precondition:
* - the mutex used with the condition in general should be
* acquired by the calling thread before setting the
* condition state and signalling
*/
OSAPI_EXPORT void
os_condBroadcast(
os_cond *cond)
__nonnull_all__;
/** \brief Initialize the rwloc
*
* Possible Results:
* - assertion failure: rwlock = NULL
* - returns os_resultSuccess if
* rwlock is successfuly initialized
* - returns os_resultFail
* rwlock is not initialized and can not be used
*/
OSAPI_EXPORT void
os_rwlockInit(
_Out_ os_rwlock *rwlock);
/** \brief Destroy the rwlock
*
* Possible Results:
* - assertion failure: rwlock = NULL
* - returns os_resultSuccess if
* rwlock is successfuly destroyed
* - returns os_resultBusy if
* rwlock is not destroyed because it is still claimed or referenced by a thread
* - returns os_resultFail if
* rwlock is not destroyed
*/
OSAPI_EXPORT void
os_rwlockDestroy(
_Inout_ _Post_invalid_ os_rwlock *rwlock);
/** \brief Acquire the rwlock while intending to read only
*
* Precondition:
* - rwlock is not yet acquired by the calling thread
*
* Postcondition:
* - The data related to the critical section is not changed
* by the calling thread
*
* Possible Results:
* - assertion failure: rwlock = NULL
* - returns os_resultSuccess if
* rwlock is acquired
* - returns os_resultFail if
* rwlock is not acquired because of a failure
*/
OSAPI_EXPORT void
os_rwlockRead(
os_rwlock *rwlock);
/** \brief Acquire the rwlock while intending to write
*
* Precondition:
* - rwlock is not yet acquired by the calling thread
*
* Possible Results:
* - assertion failure: rwlock = NULL
* - returns os_resultSuccess if
* rwlock is acquired
* - returns os_resultFail if
* rwlock is not acquired because of a failure
*/
OSAPI_EXPORT void
os_rwlockWrite(
os_rwlock *rwlock);
/** \brief Try to acquire the rwlock while intending to read only
*
* Try to acquire the rwlock while intending to read only,
* immediately return if the mutex is acquired by
* another thread with the intention to write
*
* Precondition:
* - rwlock is not yet acquired by the calling thread
*
* Postcondition:
* - The data related to the critical section is not changed
* by the calling thread
*
* Possible Results:
* - assertion failure: rwlock = NULL
* - returns os_resultSuccess if
* rwlock is acquired
* - returns os_resultBusy if
* rwlock is not acquired because it is already
* acquired by another thread with the intention to write
* - returns os_resultFail if
* rwlock is not acquired because of a failure
*/
OSAPI_EXPORT os_result
os_rwlockTryRead(
os_rwlock *rwlock);
/** \brief Try to acquire the rwlock while intending to write
*
* Try to acquire the rwlock while intending to write,
* immediately return if the mutex is acquired by
* another thread, either for read or for write
*
* Precondition:
* - rwlock is not yet acquired by the calling thread
*
* Possible Results:
* - assertion failure: rwlock = NULL
* - returns os_resultSuccess if
* rwlock is acquired
* - returns os_resultBusy if
* rwlock is not acquired because it is already
* acquired by another thread
* - returns os_resultFail if
* rwlock is not acquired because of a failure
*/
OSAPI_EXPORT os_result
os_rwlockTryWrite(
os_rwlock *rwlock);
/** \brief Release the acquired rwlock
*
* Precondition:
* - rwlock is already acquired by the calling thread
*
* Possible Results:
* - assertion failure: rwlock = NULL
* - returns os_resultSuccess if
* rwlock is released
* - returns os_resultFail if
* rwlock is not released because of a failure
*/
OSAPI_EXPORT void
os_rwlockUnlock(
os_rwlock *rwlock);
/* Initialization callback used by os_once */
typedef void (*os_once_fn)(void);
/** \brief Invoke init_fn exactly once for a given control
*
* The first thread calling os_once(...) with a given control will invoke the
* init_fn() with no arguments. Following calls with the same control will not
* invoke init_fn().
*
* Precondition:
* - The control parameter is properly initialized with OS_ONCE_T_STATIC_INIT
*
* Postcondition:
* - On return init_fn() has completed exactly once for the given control.
*/
OSAPI_EXPORT void
os_once(
_Inout_ os_once_t *control,
_In_ os_once_fn init_fn);
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,279 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/****************************************************************
* Interface definition for thread management of SPLICE-DDS *
****************************************************************/
#ifndef OS_THREAD_H
#define OS_THREAD_H
/** \file os_thread.h
* \brief Thread management - create threads
*/
#include "os/os_defs.h"
#if defined (__cplusplus)
extern "C" {
#endif
/* Number of slots in Thread Private Memory */
typedef enum os_threadMemoryIndex {
OS_THREAD_CLOCK_OFFSET,
OS_THREAD_UT_TRACE,
OS_THREAD_JVM,
OS_THREAD_PROTECT,
OS_THREAD_API_INFO,
OS_THREAD_WARNING,
OS_THREAD_ALLOCATOR_STATE,
OS_THREAD_NAME,
OS_THREAD_REPORT_STACK,
OS_THREAD_PROCESS_INFO,
OS_THREAD_STATE, /* Used for monitoring thread progress */
OS_THREAD_STR_ERROR,
OS_THREAD_MEM_ARRAY_SIZE /* Number of slots in Thread Private Memory */
} os_threadMemoryIndex;
/** \brief Definition for a thread routine invoked on thread create. */
typedef uint32_t (*os_threadRoutine)(void*);
/** \brief Definition of the scheduling class */
typedef enum os_schedClass {
/** Schedule processes and threads according a platform default.
* OS_SCHED_REALTIME for timesharing platforms and
* OS_SCHED_TIMESHARE for realtime platforms
*/
OS_SCHED_DEFAULT,
/** Schedule processes and threads on realtime basis,
* on most platforms implying:
* - Fixed Priority
* - Preemption
* - Either "First In First Out" or "Round Robin"
*/
OS_SCHED_REALTIME,
/** Schedule processes and threads on timesharing basis,
* on most platforms implying:
* - Dynamic Priority to guarantee fair share
* - Preemption
*/
OS_SCHED_TIMESHARE
} os_schedClass;
/** \brief Definition of the thread attributes
*/
typedef struct os_threadAttr {
/** Specifies the scheduling class */
os_schedClass schedClass;
/** Specifies the thread priority */
int32_t schedPriority;
/** Specifies the thread stack size */
uint32_t stackSize;
} os_threadAttr;
/** \brief Internal structure used to store cleanup handlers (private) */
typedef struct {
void (*func)(void *);
void *data;
} os_threadCleanup;
/** \brief Create a new thread
*
* Creates a new thread of control that executes concurrently with
* the calling thread. The new thread applies the function start_routine
* passing it arg as first argument.
*
* The new thread terminates by returning from the start_routine function.
* The created thread is identified by the returned threadId.
*
* Possible Results:
* - assertion failure: threadId = NULL || name = NULL ||
* threadAttr = NULL || start_routine = NULL
* - returns os_resultSuccess if
* the thread is successfuly created
* - returns os_resultFail if
* the thread is not created because of an failure
*/
OSAPI_EXPORT os_result
os_threadCreate(
_Out_ os_threadId *threadId,
_In_z_ const char *name,
_In_ const os_threadAttr *threadAttr,
_In_ os_threadRoutine start_routine,
_In_opt_ void *arg);
/** \brief Return the integer representation of the given thread ID
*
* Possible Results:
* - returns the integer representation of the given thread ID
*/
OSAPI_EXPORT uintmax_t
os_threadIdToInteger(
os_threadId id);
/** \brief Return the thread ID of the calling thread
*
* Possible Results:
* - returns the tread ID of the calling thread
*/
OSAPI_EXPORT os_threadId
os_threadIdSelf(void);
/** \brief Wait for the termination of the identified thread
*
* If the identified thread is still running, wait for its termination
* else return immediately. In thread_result it returns the exit status
* of the thread. If thread_result is passed as a NULL pointer,
* no exit status is returned, but os_threadWaitExit still waits for the
* thread to terminate.
*
* Possible Results:
* - assertion failure: threadId = 0
* - returns os_resultSuccess when
* the identified thread is not running
* - returns os_threadFail if
* the services is aborted because of a failure
*/
OSAPI_EXPORT os_result
os_threadWaitExit(
_In_ os_threadId threadId,
_Out_opt_ uint32_t *thread_result);
/** \brief Figure out the identity of the current thread
*
* Possible Results:
* - returns the actual length of threadIdentity
*
* Postcondition:
* - \b threadIdentity is ""
* the thread identity could not be determined
* - \b threadIdentity is "<decimal number>" | "0x<hexadecimal number>"
* only the thread numeric identity could be determined
* - \b threadIdentity is "<process name> (<decimal number>)" | "<process name> (0x<hexadecimal number>)"
* the thread name and numeric identity could be determined
*
* \b threadIdentity will not be filled beyond the specified \b threadIdentitySize
*/
OSAPI_EXPORT int32_t
os_threadFigureIdentity(
char *threadIdentity,
uint32_t threadIdentitySize);
/** \brief Get name of current thread
*
* Postcondition:
* - \b name is ""
* the thread name could not be determined
* - \b name is "<thread name>"
* the thread name could be determined
*
* \b name will not be filled beyond the specified \b length
*/
OSAPI_EXPORT int32_t
os_threadGetThreadName(
char *name,
uint32_t length);
/** \brief Set the default thread attributes
*
* Postcondition:
* - thread scheduling class is OS_SCHED_DEFAULT
* - thread priority is platform dependent
*
* Possible Results:
* - assertion failure: threadAttr = NULL
*/
OSAPI_EXPORT void
os_threadAttrInit(
os_threadAttr *threadAttr)
__nonnull_all__;
/** \brief Allocate thread private memory
*
* Allocate heap memory of the specified \b size and
* relate it to the thread by storing the memory
* reference in an thread specific reference array
* indexed by \b index. If the indexed thread reference
* array location already contains a reference, no
* memory will be allocated and NULL is returned.
*
* Possible Results:
* - returns NULL if
* index < 0 || index >= OS_THREAD_MEM_ARRAY_SIZE
* - returns NULL if
* no sufficient memory is available on heap
* - returns NULL if
* os_threadMemGet (index) returns != NULL
* - returns reference to allocated heap memory
* of the requested size if
* memory is successfully allocated
*/
OSAPI_EXPORT void *
os_threadMemMalloc(
int32_t index,
size_t size);
/** \brief Free thread private memory
*
* Free the memory referenced by the thread reference
* array indexed location. If this reference is NULL,
* or index is invalid, no action is taken.
* The reference is set to NULL after freeing the
* heap memory.
*
* Postcondition:
* - os_threadMemGet (index) = NULL and allocated
* heap memory is freed
*/
OSAPI_EXPORT void
os_threadMemFree(
int32_t index);
/** \brief Get thread private memory
*
* Possible Results:
* - returns NULL if
* index < 0 || index >= OS_THREAD_MEM_ARRAY_SIZE
* - returns NULL if
* No heap memory is related to the thread for
* the specified index
* - returns a reference to the allocated memory
*/
OSAPI_EXPORT void *
os_threadMemGet(
int32_t index);
/** \brief Pop cleanup handler from the top of thread's cleanup stack
*
* Remove routine at the top of the calling thread's cleanup stack and
* optionally invoke it (if execute is non-zero).
*/
OSAPI_EXPORT void
os_threadCleanupPop(
int32_t execute);
/** \brief Push cleanup handler onto thread's cleanup stack
*
* Push a cleanup handler onto the top of the calling thread's cleanup
* stack. The cleanup handler will be popped of the thread's cleanup stack
* and invoked with the specified argument when the thread exits.
*/
OSAPI_EXPORT void
os_threadCleanupPush(
void (*routine)(void*),
void *arg);
#if defined (__cplusplus)
}
#endif
#endif /* OS_THREAD_H */

276
src/os/include/os/os_time.h Normal file
View file

@ -0,0 +1,276 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/****************************************************************
* Interface definition for time management of SPLICE-DDS *
****************************************************************/
#ifndef OS_TIME_H
#define OS_TIME_H
#include "os/os_defs.h"
/* !!!!!!!!NOTE From here no more includes are allowed!!!!!!! */
#if defined (__cplusplus)
extern "C" {
#endif
/** \brief Specification of maximum time values (platform dependent)
*/
#define OS_TIME_INFINITE_SEC INT32_MAX
#define OS_TIME_INFINITE_NSEC INT32_MAX
#define os_timeIsInfinite(t) \
(((t).tv_sec == OS_TIME_INFINITE_SEC) && ((t).tv_nsec == OS_TIME_INFINITE_NSEC))
/** \brief Get the current time.
*
* The returned time represents the seconds and nanoseconds since the Unix Epoch
* (Thursday, 1 January 1970, 00:00:00 (UTC)).
*
* Possible Results:
* - returns "the current time"
*/
OSAPI_EXPORT os_time
os_timeGet(void);
os_time os__timeDefaultTimeGet(void);
/** \brief Get high resolution, monotonic time.
*
* The monotonic clock is a clock with near real-time progression and can be
* used when a high-resolution time is needed without the need for it to be
* related to the wall-clock. The resolution of the clock is typically the
* highest available on the platform.
*
* The clock is not guaranteed to be strictly monotonic, but on most common
* platforms it will be (based on performance-counters or HPET's).
*
* If no monotonic clock is available the real time clock is used.
*
* \return a high-resolution time with no guaranteed relation to wall-time
* when available
* \return wall-time, otherwise
*/
OSAPI_EXPORT os_time
os_timeGetMonotonic(void);
/** \brief Get high resolution, elapsed (and thus monotonic) time since some
* fixed unspecified past time.
*
* The elapsed time clock is a clock with near real-time progression and can be
* used when a high-resolution suspend-aware monotonic clock is needed, without
* having to deal with the complications of discontinuities if for example the
* time is changed. The fixed point from which the elapsed time is returned is
* not guaranteed to be fixed over reboots of the system.
*
* If no elapsed time clock is available, the os_timeGetMonotonic() is used as a
* fall-back.
*
* \return elapsed time since some unspecified fixed past time
* \return os_timeGetMonotonic() otherwise
*/
OSAPI_EXPORT os_time
os_timeGetElapsed(void);
/** \brief Add time t1 to time t2
*
* Possible Results:
* - returns t1 + t2 when
* the result fits within the time structure
* - returns an unspecified value when
* the result does not fit within the time structure
*/
OSAPI_EXPORT os_time
os_timeAdd(
os_time t1,
os_time t2);
/** \brief Subtract time t2 from time t1
*
* Possible Results:
* - returns t1 - t2 when
* the result fits within the time structure
* - returns an unspecified value when
* the result does not fit within the time structure
*/
OSAPI_EXPORT os_time
os_timeSub(
os_time t1,
os_time t2);
/** \brief Multiply time t with a real value
*
* Possible Results:
* - returns t * multiply when
* the result fits within the time structure
* - returns an unspecified value when
* the result does not fit within the time structure
*/
OSAPI_EXPORT os_time
os_timeMulReal(
os_time t1,
double multiply);
/** \brief Determine the absolute value of time t
*
* Possible Results:
* - returns |t| when
* the result fits within the time structure
* - returns an unspecified value when
* the result does not fit within the time structure
*/
OSAPI_EXPORT os_time
os_timeAbs(
os_time t);
/** \brief Compare time t1 with time t2
*
* Possible Results:
* - returns -1 when
* value t1 < value t2
* - returns 1 when
* value t1 > value t2
* - returns 0 when
* value t1 = value t2
*/
OSAPI_EXPORT int
os_timeCompare(
os_time t1,
os_time t2);
/** \brief Convert time t into a floating point representation of t
*
* Postcondition:
* - Due to the limited accuracy, the least significant part
* of the floating point time will be about 1 us.
*
* Possible Results:
* - returns floating point representation of t
*/
OSAPI_EXPORT os_timeReal
os_timeToReal(
os_time t);
/** \brief Convert a floating point time representation into time
*
* Possible Results:
* - returns t in os_time representation
*/
OSAPI_EXPORT os_time
os_realToTime(
os_timeReal t);
/** \brief Suspend the execution of the calling thread for the specified time
*
* Possible Results:
* - returns os_resultSuccess if
* the thread is suspended for the specified time
* - returns os_resultFail if
* the thread is not suspended for the specified time because of a failure,
* for example when a negative delay is supplied or when the ns-part is not
* normalized.
*/
OSAPI_EXPORT os_result
os_nanoSleep(
_In_ os_time delay);
/** \brief Translate calendar time into a readable string representation
*
* It converts the calendar time t into a '\0'-terminated string of the form:
*
* "Mon Feb 03 14:28:56 2014"
*
* The time-zone information may not be included on all platforms and may be a
* non-abbreviated string too. In order to obtain the time-zone, more room (at
* least 4 bytes more for an abbreviated, and unknown more for spelled out) needs
* to be provided in buf than the minimum of OS_CTIME_R_BUFSIZE. On Windows (if
* enough room is provided) it may for example expand to:
*
* "Wed Oct 01 15:59:53 W. Europe Daylight Time 2014"
*
* And on Linux to:
*
* "Wed Oct 01 15:59:53 CEST 2014"
*
* \param t the time to be translated
* \param buf a buffer to which the string must be written, with room for holding
* at least OS_CTIME_R_BUFSIZE (26) characters.
*
* Possible Results:
* If buf != NULL, buf contains a readable string representation of time t. The
* string is '\0'-terminated (and doesn't include a '\n' as the last character).
* \return The number of bytes written (not including the terminating \0) to buf
* and 0 if buf was NULL.
*/
OSAPI_EXPORT size_t
os_ctime_r(
os_time *t,
char *buf,
size_t bufsz);
/** Minimum capacity of buffer supplied to os_ctime_r
*
* Apparently, the French national representation of the abbreviated weekday
* name and month name is 4 characters, so therefore added 2 to the expected
* size of 26.
*/
#define OS_CTIME_R_BUFSIZE (28)
typedef struct os_timePowerEvents_s {
uint32_t suspendCount; /**< The number of detected suspends. */
os_time suspendLastDetected; /**< The time of the last detected suspend (real time). */
os_atomic_uint32_t resumeCount; /**< The number of detected resumes. */
os_time resumeLastDetected; /**< The time of the last detected resume (real time). */
} os_timePowerEvents;
/** \brief Query (and optionally synchronize) on the number of detected power events.
*
* This call can be used to retrieve the number of power events (suspend/resume) that were
* detected. It is possible to block on changes by specifying a maxBlockingTime.
*
* The lastDetected timestamps are retrieved with os_getTime() and are the times on which the
* event was detected (which may not be the exact time at which the events actually occurred).
* The reported counts are monotonically increased on detection of power events.
*
* There is no guarantee that suspends (either hibernate or sleep) are detected. In general not
* all events may be detectable. Only the last resume event is guaranteed to be detected.
*
* The initial state (when no events are detected yet) is all counts and times zeroed.
*
* \param [in,out] events Pointer to a struct in which the result of the call is returned.
* If maxBlockingTime == 0, events is an out-parameter, otherwise it
* is in/out. The call will block until the actual state is different
* from the state pointed to by events.
* \param [in] maxBlockingTime The maximum time the call may block for the state to change from
* the state specified in events. If 0, the call will not block and
* return immediately the current state.
* \retval os_resultSuccess When the call succeeded and the struct pointed to by events contains
* the new status.
* \retval os_resultTimeout Iff maxBlockingTime != 0 and maxBlockingTime elapsed before the state
* changed.
*
* \pre The parameter events is not NULL and points to a location sufficiently large to hold an
* os_powerEvents struct.
* \pre The parameter maxBlockingTime is a valid time representation.
* \post The struct pointed to by events contains the current values.
*/
OSAPI_EXPORT os_result
os_timeGetPowerEvents(
os_timePowerEvents *events,
os_time maxBlockingTime);
#if defined (__cplusplus)
}
#endif
#endif /* OS_TIME_H */

View file

@ -0,0 +1,24 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_PROCESS_H
#define OS_PLATFORM_PROCESS_H
#if defined (__cplusplus)
extern "C" {
#endif
void os_processModuleInit(void);
void os_processModuleExit(void);
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,25 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_PUBLIC_POSIX_H
#define OS_PLATFORM_PUBLIC_POSIX_H
#include <stdint.h>
#if defined (__cplusplus)
extern "C" {
#endif
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,80 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_SOCKET_H
#define OS_PLATFORM_SOCKET_H
#ifdef __VXWORKS__
#include <vxWorks.h>
#include <sockLib.h>
#include <ioLib.h>
#endif /* __VXWORKS__ */
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/select.h>
#ifdef __APPLE__
#include <sys/sockio.h>
#endif /* __APPLE__ */
#include <unistd.h>
#include <ifaddrs.h>
#if defined (__cplusplus)
extern "C" {
#endif
/* Keep defines before common header */
#define OS_SOCKET_HAS_IPV6 1
#define OS_IFNAMESIZE IF_NAMESIZE
#define OS_SOCKET_HAS_SA_LEN 1
#define OS_NO_SIOCGIFINDEX 1
#define OS_NO_NETLINK 1
#define OS_SOCKET_HAS_SSM 1
#define os_sockEAGAIN EAGAIN /* Operation would block, or a timeout expired before operation succeeded */
#define os_sockEWOULDBLOCK EWOULDBLOCK /* Operation would block */
#define os_sockEPERM EPERM /* Operation not permitted */
#define os_sockENOENT ENOENT /* No such file or directory */
#define os_sockEINTR EINTR /* Interrupted system call */
#define os_sockEBADF EBADF /* Bad file number */
#define os_sockENOMEM ENOMEM /* Out of memory */
#define os_sockEACCES EACCES /* Permission denied */
#define os_sockEINVAL EINVAL /* Invalid argument */
#define os_sockEMFILE EMFILE /* Too many open files */
#define os_sockENOSR ENOSR /* Out of streams resources */
#define os_sockENOTSOCK ENOTSOCK /* Socket operation on non-socket */
#define os_sockEMSGSIZE EMSGSIZE /* Message too long */
#define os_sockENOPROTOOPT ENOPROTOOPT /* Protocol not available */
#define os_sockEPROTONOSUPPORT EPROTONOSUPPORT /* Protocol not supported */
#define os_sockEADDRINUSE EADDRINUSE /* Address already in use */
#define os_sockEADDRNOTAVAIL EADDRNOTAVAIL /* Cannot assign requested address */
#define os_sockENETUNREACH ENETUNREACH /* Network is unreachable */
#define os_sockENOBUFS ENOBUFS /* No buffer space available */
#define os_sockECONNRESET ECONNRESET /* Connection reset by peer */
typedef int os_socket; /* signed */
#define PRIsock "d"
#define OS_SOCKET_INVALID (-1)
#if defined (__cplusplus)
}
#endif
#endif /* OS_PLATFORM_SOCKET_H */

View file

@ -0,0 +1,12 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "../../../src/snippets/include/os_posix_stdlib.h"

View file

@ -0,0 +1,59 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_SYNC_H
#define OS_PLATFORM_SYNC_H
#include <stdint.h>
#include <pthread.h>
#if HAVE_LKST
#include "lkst.h"
#endif
#if defined (__cplusplus)
extern "C" {
#endif
typedef struct os_cond {
#ifdef OSPL_STRICT_MEM
/* Used to identify initialized cond when memory is freed -
keep this first in the structure so its so its address is
the same as the os_cond */
uint64_t signature;
#endif
pthread_cond_t cond;
} os_cond;
typedef struct os_mutex {
#ifdef OSPL_STRICT_MEM
/* Used to identify initialized cond when memory is freed -
keep this first in the structure so its so its address is
the same as the os_cond */
uint64_t signature;
#endif
pthread_mutex_t mutex;
} os_mutex;
typedef struct os_rwlock {
os_mutex mutex;
} os_rwlock;
typedef pthread_once_t os_once_t;
#define OS_ONCE_T_STATIC_INIT PTHREAD_ONCE_INIT
void os_syncModuleInit(void);
void os_syncModuleExit(void);
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,33 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_THREAD_H
#define OS_PLATFORM_THREAD_H
#include <pthread.h>
#if defined (__cplusplus)
extern "C" {
#endif
/* Wrapped in a struct to help programmers conform to the abstraction. */
typedef struct os_threadId_s {
pthread_t v; /* Don't touch directly (except for maybe a test or the os-abstraction implementation itself). */
} os_threadId;
void os_threadModuleInit (void);
void os_threadModuleExit (void);
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,152 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_H
#define OS_PLATFORM_H
#include <vxWorks.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#define PRIdSIZE "zd"
#define PRIuSIZE "zu"
#define PRIxSIZE "zx"
#ifdef _WRS_KERNEL
/* inttypes.h does not exist in VxWorks DKM */
#include <st_inttypes.h>
#include <cafe/inttypes.h>
/* The above inttypes includes don't seem to define uintmax_t &c. */
#ifdef _WRS_CONFIG_LP64 /* Used in cafe/inttypes.h too */
#define _PFX_64 "l"
typedef unsigned long int uintmax_t;
#else
#define _PFX_64 "ll"
typedef unsigned long long int uintmax_t;
#endif
/* FIXME: Not a complete replacement for inttypes.h (yet); no SCN/PRI?LEAST/FAST/etc */
/* FIXME: Wrap all of them in #ifndefs */
#define PRId8 "d"
#define PRId16 "d"
#define PRId32 "d"
#define PRId64 _PFX_64 "d"
#define PRIi8 "i"
#define PRIi16 "i"
#define PRIi32 "i"
#define PRIi64 _PFX_64 "i"
#define PRIo8 "o"
#define PRIo16 "o"
#define PRIo32 "o"
#define PRIo64 _PFX_64 "o"
#define PRIu8 "u"
#define PRIu16 "u"
#define PRIu32 "u"
#define PRIu64 _PFX_64 "u"
#define PRIx8 "x"
#define PRIx16 "x"
#define PRIx32 "x"
/*#define PRIx64 _PFX_64 "x" // Defined in cafe/inttypes.h apparently */
#define PRIX8 "X"
#define PRIX16 "X"
#define PRIX32 "X"
#define PRIX64 _PFX_64 "X"
#define PRIdMAX _PFX_64 "d"
#define PRIiMAX _PFX_64 "i"
#define PRIoMAX _PFX_64 "o"
#define PRIuMAX _PFX_64 "u"
#define PRIxMAX _PFX_64 "x"
#define PRIXMAX _PFX_64 "X"
#define PRIdPTR _PFX_64 "d"
#define PRIiPTR _PFX_64 "i"
#define PRIoPTR _PFX_64 "o"
/*#define PRIuPTR _PFX_64 "u" // Defined in cafe/inttypes.h apparently */
/*#define PRIxPTR _PFX_64 "x" // Defined in cafe/inttypes.h apparently */
#define PRIXPTR _PFX_64 "X"
#define INFINITY infinity()
#define NAN ((float)(INFINITY * 0.0F))
#if !defined(__PPC) && !defined(__x64_64__)
/* FIXME: Is this still required for VxWorks 7? */
#define OS_USE_ALLIGNED_MALLOC
#endif
#else
#include <inttypes.h>
#endif /* _WRS_KERNEL */
#if defined (__cplusplus)
extern "C" {
#endif
#define OS_VXWORKS 1
#define OS_SOCKET_USE_FCNTL 0
#define OS_SOCKET_USE_IOCTL 1
#define OS_FILESEPCHAR '/'
#define OS_HAS_NO_SET_NAME_PRCTL 1 /* FIXME: Move to CMake */
#define OS_HAS_UCONTEXT_T 1
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ /* FIXME: Move to CMake */
#define OS_ENDIANNESS OS_BIG_ENDIAN
#else
#define OS_ENDIANNESS OS_LITTLE_ENDIAN
#endif
#if defined(__PPC) || defined(__x86_64__) /* FIXME: Move to CMake */
#define OS_64BIT
#endif
typedef double os_timeReal;
typedef int os_timeSec;
typedef uid_t os_uid;
typedef gid_t os_gid;
typedef mode_t os_mode_t;
#ifdef _WRS_KERNEL
typedef RTP_ID os_procId; /* typedef struct wind_rtp *RTP_ID */
#define PRIprocId "d"
#else
typedef pid_t os_procId;
#define PRIprocId "d"
/* If unistd.h is included after stdint.h, intptr_t will be defined twice.
* It seems like this is an issue with the VxWorks provided header-files. The
* define done by stdint.h is not checked in unistd.h. Below is a workaround
* for this issue. */
#if !defined _INTPTR_T && defined _INTPTR
# define _INTPTR_T _INTPTR
#endif
#endif
#include "os/posix/os_platform_socket.h"
#ifdef _WRS_KERNEL
/* Pulling in netinet/in.h automatically pulls in net/mbuf.h in VxWorks DKM */
#undef m_next
#undef m_flags
#endif
#include "os/posix/os_platform_sync.h"
#include "os/posix/os_platform_thread.h"
#include "os/posix/os_platform_stdlib.h"
#if defined (__cplusplus)
}
#endif
#endif /* OS_PLATFORM_H */

View file

@ -0,0 +1,72 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_H
#define OS_PLATFORM_H
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <VersionHelpers.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#define PRIdSIZE "zd"
#define PRIuSIZE "zu"
#define PRIxSIZE "zx"
#if defined (__cplusplus)
extern "C" {
#endif
#define OS_WIN32 1
#define OS_SOCKET_USE_FCNTL 0
#define OS_SOCKET_USE_IOCTL 1
#define OS_FILESEPCHAR '/'
#define OS_HAS_NO_SET_NAME_PRCTL 1
#define OS_HAS_UCONTEXT_T 0
#ifdef __BIG_ENDIAN
#define OS_ENDIANNESS OS_BIG_ENDIAN
#else
#define OS_ENDIANNESS OS_LITTLE_ENDIAN
#endif
#ifdef _WIN64
#define OS_64BIT
#endif
typedef double os_timeReal;
typedef int os_timeSec;
typedef DWORD os_procId;
#define PRIprocId "u"
/* keep in sync with st_mode field def in struct stat in sys/stat.h */
typedef unsigned short os_mode_t;
typedef SSIZE_T ssize_t;
#include "os/windows/os_platform_socket.h"
#include "os/windows/os_platform_sync.h"
#include "os/windows/os_platform_process.h"
#include "os/windows/os_platform_thread.h"
#include "os/windows/os_platform_stdlib.h"
#include "os/windows/os_platform_time.h"
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,24 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_PROCESS_H
#define OS_PLATFORM_PROCESS_H
#if defined (__cplusplus)
extern "C" {
#endif
void os_processModuleInit(void);
void os_processModuleExit(void);
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,25 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_PUBLIC_WIN_H
#define OS_PLATFORM_PUBLIC_WIN_H
#include <stdint.h>
#if defined (__cplusplus)
extern "C" {
#endif
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,73 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_SOCKET_H
#define OS_PLATFORM_SOCKET_H
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#if defined (__cplusplus)
extern "C" {
#endif
#define OS_SOCK_VERSION 2
#define OS_SOCK_REVISION 0
/* Keep defines before common header */
#define OS_SOCKET_HAS_IPV6 1
#define OS_IFNAMESIZE 128
#define OS_SOCKET_HAS_SA_LEN 0
#define OS_NO_SIOCGIFINDEX 1
#define OS_NO_NETLINK 1
#if defined NTDDI_VERSION && defined _WIN32_WINNT_WS03 && NTDDI_VERSION >= _WIN32_WINNT_WS03
#define OS_SOCKET_HAS_SSM 1
#else
#define OS_SOCKET_HAS_SSM 0
#endif
#define IFF_POINTOPOINT IFF_POINTTOPOINT
#define os_sockEAGAIN WSAEWOULDBLOCK /* Operation would block, or a timeout expired before operation succeeded */
#define os_sockEWOULDBLOCK WSAEWOULDBLOCK /* Operation would block */
#define os_sockENOMEM WSABASEERR
#define os_sockENOSR WSABASEERR
#define os_sockENOENT WSABASEERR
#define os_sockEPERM WSABASEERR
#define os_sockEINTR WSAEINTR
#define os_sockEBADF WSAEBADF
#define os_sockEACCES WSAEACCES
#define os_sockEINVAL WSAEINVAL
#define os_sockEMFILE WSAEMFILE
#define os_sockENOTSOCK WSAENOTSOCK
#define os_sockEMSGSIZE WSAEMSGSIZE
#define os_sockENOPROTOOPT WSAENOPROTOOPT
#define os_sockEPROTONOSUPPORT WSAEPROTONOSUPPORT
#define os_sockEADDRINUSE WSAEADDRINUSE
#define os_sockEADDRNOTAVAIL WSAEADDRNOTAVAIL
#define os_sockEHOSTUNREACH WSAEHOSTUNREACH
#define os_sockENOBUFS WSAENOBUFS
#define os_sockECONNRESET WSAECONNRESET /* Connection reset by peer */
typedef SOCKET os_socket;
#define PRIsock PRIuPTR
#define OS_SOCKET_INVALID (-1)
void os_socketModuleInit(void);
void os_socketModuleExit(void);
#if defined (__cplusplus)
}
#endif
#endif /* OS_PLATFORM_SOCKET_H */

View file

@ -0,0 +1,60 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_STDLIB_H
#define OS_PLATFORM_STDLIB_H
#include <sys/stat.h>
#include <io.h>
#if defined (__cplusplus)
extern "C" {
#endif
#define OS_OS_FILESEPCHAR '\\'
#define OS_OS_PATHSEPCHAR ';'
#define OS_OS_EXESUFFIX ".exe"
#define OS_OS_BATSUFFIX ".bat"
#define OS_OS_LIB_LOAD_PATH_VAR "PATH"
#define OS_ROK (_S_IREAD)
#define OS_WOK (_S_IWRITE)
#define OS_XOK (_S_IEXEC)
#define OS_FOK (0)
#define OS_ISDIR(mode) (mode & _S_IFDIR)
#define OS_ISREG(mode) (mode & _S_IFREG)
#define OS_ISLNK(mode) (0) /* not supported on this platform */
/* on this platform these permission masks are don't cares! */
#define S_IRWXU 00700
#define S_IRWXG 00070
#define S_IRWXO 00007
/* The value _POSIX_PATH_MAX is defined in limits.h, however you have
* to define _POSIX_ during compilation.This again will remove the
* _read, _open and _close prototypes!
*/
#define OS_PATH_MAX 255
typedef HANDLE os_os_dirHandle;
#define MAXHOSTNAMELEN MAX_HOSTNAME_LEN
#if _MSC_VER < 1900
extern int snprintf(char *s, size_t n, const char *format, ...);
#endif
#if defined (__cplusplus)
}
#endif
#endif /* OS_PLATFORM_STDLIB_H */

View file

@ -0,0 +1,57 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_SYNC_H
#define OS_PLATFORM_SYNC_H
#if defined (__cplusplus)
extern "C" {
#endif
typedef struct os_cond {
#ifdef OSPL_STRICT_MEM
/* Used to identify initialized cond when memory is freed -
keep this first in the structure so its so its address is
the same as the os_cond */
uint64_t signature;
#endif
CONDITION_VARIABLE cond;
} os_cond;
typedef struct os_mutex {
#ifdef OSPL_STRICT_MEM
/* Used to identify initialized cond when memory is freed -
keep this first in the structure so its so its address is
the same as the os_cond */
uint64_t signature;
#endif
SRWLOCK lock;
} os_mutex;
typedef struct os_rwlock {
#ifdef OSPL_STRICT_MEM
/* Used to identify initialized cond when memory is freed -
keep this first in the structure so its so its address is
the same as the os_cond */
uint64_t signature;
#endif
SRWLOCK lock;
int state; /* -1: exclusive, 0: free, 1: shared */
} os_rwlock;
typedef INIT_ONCE os_once_t;
#define OS_ONCE_T_STATIC_INIT INIT_ONCE_STATIC_INIT
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,33 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_THREAD_H
#define OS_PLATFORM_THREAD_H
#include "os/os_defs.h"
#if defined (__cplusplus)
extern "C" {
#endif
typedef struct os_threadInfo_s {
DWORD threadId;
HANDLE handle;
} os_threadId;
os_result os_threadModuleInit (void);
void os_threadModuleExit (void);
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,27 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_PLATFORM_TIME_H
#define OS_PLATFORM_TIME_H
#if defined (__cplusplus)
extern "C" {
#endif
void os_timeModuleInit(void);
void os_timeModuleExit(void);
#if defined (__cplusplus)
}
#endif
#endif

16
src/os/src/os_atomics.c Normal file
View file

@ -0,0 +1,16 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#define OS_HAVE_INLINE 0 /* override automatic determination of inlining */
#define VDDS_INLINE /* no "inline" in function defs (not really needed) */
#define OS_ATOMICS_OMIT_FUNCTIONS 0 /* force inclusion of functions defs */
#include "os/os.h"

100
src/os/src/os_errno.c Normal file
View file

@ -0,0 +1,100 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "os/os.h"
#include <assert.h>
#include <stddef.h>
#include <string.h>
#define MIN_BUFLEN (64)
#define MAX_BUFLEN (1024)
const char *
os_strerror(
_In_ int err)
{
char *mem;
char *ptr, *str = NULL;
size_t len = 0;
size_t tot;
int ret = 0;
/* os_threadMem* does not support destructors, but does free the memory
referred to by the index. To avoid memory leaks and extra work the
length of the string is placed in front of the string. */
if ((mem = os_threadMemGet(OS_THREAD_STR_ERROR)) == NULL) {
ret = ERANGE;
} else {
str = mem + sizeof(len);
memcpy(&len, mem, sizeof(len));
}
/* os_strerror_r returns ERANGE if the buffer is too small.
Iteratively increase the buffer and retry until MAX_BUFLEN is reached,
in which case, give up and print the error number as text. */
do {
if (ret == ERANGE && len < MAX_BUFLEN) {
os_threadMemFree(OS_THREAD_STR_ERROR);
if (len == 0) {
len = MIN_BUFLEN;
} else {
len *= 2;
}
tot = sizeof(len) + len + 1;
mem = os_threadMemMalloc(OS_THREAD_STR_ERROR, tot);
if (mem != NULL) {
memcpy(mem, &len, sizeof(len));
str = mem + sizeof(len);
} else {
ret = ENOMEM;
str = NULL;
len = 0;
}
}
if (str != NULL) {
assert(len != 0 && len >= MIN_BUFLEN && len <= MAX_BUFLEN);
assert((len % MIN_BUFLEN) == 0);
if (ret == ERANGE && len == MAX_BUFLEN) {
ret = 0;
(void)snprintf(str, len, "Error (%d)", err);
} else {
/* Solaris 10 does not populate buffer if it is too small */
memset(str, '\0', len + 1);
ret = os_strerror_r(err, str, len);
}
}
} while (str != NULL && ret == ERANGE);
switch(ret) {
case ENOMEM:
str = "Out of memory";
break;
case EINVAL:
(void)snprintf(str, len, "Unknown error (%d)", err);
break;
default:
assert(str != NULL);
/* strip newline and/or carriage return */
ptr = str;
while (*ptr != '\0' && *ptr != '\n' && *ptr != '\r') {
ptr++;
}
if (*ptr == '\n' || *ptr == '\r') {
*ptr = '\0';
}
break;
}
return str;
}

31
src/os/src/os_init.c Normal file
View file

@ -0,0 +1,31 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/****************************************************************
* Initialization / Deinitialization *
****************************************************************/
/** \file os/code/os_init.c
* \brief Initialization / Deinitialization
*
* Initialization / Deinitialization provides routines for
* initializing the OS layer claiming required resources
* and routines to deinitialize the OS layer, releasing
* all resources still claimed.
*/
#include "os/os.h"
const char *
os_versionString(void)
{
return OSPL_VERSION_STR;
}

228
src/os/src/os_iter.c Normal file
View file

@ -0,0 +1,228 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include "os/os.h"
typedef struct os_iterNode_s os_iterNode;
struct os_iterNode_s {
os_iterNode *next;
void *object;
};
struct os_iter_s {
uint32_t length;
os_iterNode *head;
os_iterNode *tail;
};
_Ret_range_(-1, iter->length) static int32_t
os__iterIndex(
_In_ const os_iter *iter,
_In_ int32_t index)
{
int32_t idx = 0;
assert(iter != NULL);
if (index == OS_ITER_LENGTH) {
idx = iter->length;
} else if (index < 0) {
index *= -1;
if ((uint32_t)index > iter->length) {
idx = -1;
} else {
idx = iter->length - index;
}
} else {
if ((uint32_t)index > iter->length) {
idx = iter->length;
} else {
idx = index;
}
}
return idx;
}
_Check_return_
_Ret_valid_
os_iter *
os_iterNew(
void)
{
os_iter *iter = os_malloc_0(sizeof *iter);
return iter;
}
void
os_iterFree(
_In_opt_ _Post_ptr_invalid_ os_iter *iter,
_In_opt_ void(*func)(_Inout_ void *))
{
os_iterNode *node, *next;
if (iter != NULL) {
node = iter->head;
while (node != NULL) {
next = node->next;
if (node->object != NULL && func != NULL) {
func(node->object);
}
os_free(node);
node = next;
}
os_free(iter);
}
}
_Success_(return >= 0) _Ret_range_(-1, INT32_MAX) int32_t
os_iterInsert(
_Inout_ os_iter *iter,
_In_opt_ void *object,
_In_ int32_t index)
{
int32_t cnt, idx = -1;
os_iterNode *node, *prev;
node = os_malloc_0(sizeof *node);
node->object = object;
idx = os__iterIndex(iter, index);
prev = NULL;
if (idx > 0) {
assert(iter->length != 0);
assert(iter->head != iter->tail || iter->length == 1);
if (idx == iter->length) {
prev = iter->tail;
iter->tail = node;
} else {
cnt = 1;
prev = iter->head;
while (cnt++ < idx) {
prev = prev->next;
}
assert(prev != iter->tail);
node->next = prev->next;
prev->next = node;
}
prev->next = node;
} else {
assert(idx == 0 || idx == -1);
idx = 0;
node->next = iter->head;
iter->head = node;
if (iter->tail == NULL) {
assert(iter->length == 0);
iter->tail = node;
}
}
iter->length++;
return idx;
}
_Ret_opt_valid_ void *
os_iterObject(
_In_ const os_iter *iter,
_In_range_(INT32_MIN+1, INT32_MAX) int32_t index)
{
os_iterNode *node;
int32_t cnt, idx;
void *obj = NULL;
assert(iter != NULL);
idx = os__iterIndex(iter, index);
if (idx >= 0 && (uint32_t)idx < iter->length) {
if (idx == (iter->length - 1)) {
node = iter->tail;
} else {
node = iter->head;
for (cnt = 0; cnt < idx; cnt++) {
node = node->next;
}
}
obj = node->object;
}
return obj;
}
_Ret_opt_valid_ void *
os_iterTake(
_Inout_ os_iter *iter,
_In_range_(INT32_MIN+1, INT32_MAX) int32_t index)
{
os_iterNode *node, *prev;
int32_t cnt, idx;
void *obj = NULL;
assert(iter != NULL);
idx = os__iterIndex(iter, index);
if (idx >= 0 && (uint32_t)idx < iter->length) {
prev = NULL;
node = iter->head;
for (cnt = 0; cnt < idx; cnt++) {
prev = node;
node = node->next;
}
if (node == iter->head) {
iter->head = node->next;
} else {
assert(prev != NULL);
prev->next = node->next;
}
if (node == iter->tail) {
iter->tail = prev;
}
obj = node->object;
os_free(node);
iter->length--;
}
return obj;
}
_Ret_range_(0, INT32_MAX) uint32_t
os_iterLength(
_In_ const os_iter *__restrict iter)
{
assert(iter != NULL);
return iter->length;
}
void
os_iterWalk(
_In_ const os_iter *iter,
_In_ void(*func)(_Inout_ void *obj, _Inout_opt_ void *arg),
_Inout_opt_ void *arg)
{
os_iterNode *node;
assert(iter != NULL);
assert(func != NULL);
node = iter->head;
while (node != NULL) {
if(node->object) {
func(node->object, arg);
}
node = node->next;
}
}

42
src/os/src/os_process.c Normal file
View file

@ -0,0 +1,42 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "os/os.h"
#include <stdlib.h>
#include <assert.h>
/** \brief Register an process exit handler
*
* \b os_procAtExit registers an process exit
* handler by calling \b atexit passing the \b function
* to be called when the process exits.
* The standard POSIX implementation guarantees the
* required order of execution of the exit handlers.
*/
os_result
os_procAtExit(
_In_ void (*function)(void))
{
int result;
os_result osResult;
assert (function != NULL);
result = atexit (function);
if(!result)
{
osResult = os_resultSuccess;
} else
{
osResult = os_resultFail;
}
return osResult;
}

911
src/os/src/os_report.c Normal file
View file

@ -0,0 +1,911 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifdef PIKEOS_POSIX
#include <lwip_config.h>
#endif
#include "os/os.h"
#include "os/os_project.h"
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#define OS_REPORT_TYPE_DEBUG (1u)
#define OS_REPORT_TYPE_WARNING (1u<<OS_REPORT_WARNING)
#define OS_REPORT_TYPE_ERROR (1u<<OS_REPORT_ERROR)
#define OS_REPORT_TYPE_CRITICAL (1u<<OS_REPORT_CRITICAL)
#define OS_REPORT_TYPE_FATAL (1u<<OS_REPORT_FATAL)
#define OS_REPORT_TYPE_INFO (1u<<OS_REPORT_INFO)
#define OS_REPORT_TYPE_FLAG(x) (1u<<(x))
#define OS_REPORT_IS_ALWAYS(x) ((x) & (OS_REPORT_TYPE_CRITICAL | OS_REPORT_TYPE_FATAL))
#define OS_REPORT_IS_WARNING(x) ((x) & OS_REPORT_TYPE_WARNING)
#define OS_REPORT_IS_ERROR(x) ((x) & (OS_REPORT_TYPE_ERROR | OS_REPORT_TYPE_CRITICAL | OS_REPORT_TYPE_FATAL))
#define OS_REPORT_FLAG_TYPE(x) (((x) & OS_REPORT_TYPE_FATAL) ? OS_REPORT_FATAL : \
((x) & OS_REPORT_TYPE_CRITICAL) ? OS_REPORT_CRITICAL : \
((x) & OS_REPORT_TYPE_ERROR) ? OS_REPORT_ERROR : \
((x) & OS_REPORT_TYPE_WARNING) ? OS_REPORT_WARNING : \
((x) & OS_REPORT_TYPE_INFO) ? OS_REPORT_INFO : \
((x) & OS_REPORT_TYPE_DEBUG) ? OS_REPORT_DEBUG : \
OS_REPORT_NONE)
#define MAX_FILE_PATH 2048
typedef struct os_reportStack_s {
int count;
unsigned typeset;
const char *file;
int lineno;
const char *signature;
os_iter *reports; /* os_reportEventV1 */
} *os_reportStack;
/**
* The information that is made available to a plugged in logger
* via its TypedReport symbol.
*/
struct os_reportEventV1_s
{
/** The version of this struct i.e. 1. */
uint32_t version;
/** The type / level of this report.
* @see os_reportType */
os_reportType reportType;
/** Context information relating to where the even was generated.
* May contain a function or compnent name or a stacktrace */
char* reportContext;
/** The source file name where the report even was generated */
char* fileName;
/** The source file line number where the report was generated */
int32_t lineNo;
/** An integer code associated with the event. */
int32_t code;
/** A description of the reported event */
char *description;
/** A string identifying the thread the event occurred in */
char* threadDesc;
/** A string identifying the process the event occurred in */
char* processDesc;
};
#define OS_REPORT_EVENT_V1 1
typedef struct os_reportEventV1_s* os_reportEventV1;
static void os__report_append(_Inout_ os_reportStack _this, _In_ const os_reportEventV1 report);
static void os__report_fprintf(_Inout_ FILE *file, _In_z_ _Printf_format_string_ const char *format, ...);
static void os__report_free(_In_ _Post_invalid_ os_reportEventV1 report);
static void os__report_dumpStack(_In_z_ const char *context, _In_z_ const char *path, _In_ int line);
static FILE* error_log = NULL;
static FILE* info_log = NULL;
static os_mutex reportMutex;
static os_mutex infologcreateMutex;
static os_mutex errorlogcreateMutex;
static bool inited = false;
static bool StaleLogsRemoved = false;
/**
* Process global verbosity level for OS_REPORT output. os_reportType
* values >= this value will be written.
* This value defaults to OS_REPORT_INFO, meaning that all types 'above' (i.e.
* other than) OS_REPORT_DEBUG will be written and OS_REPORT_DEBUG will not be.
*/
os_reportType os_reportVerbosity = OS_REPORT_INFO;
/**
* Labels corresponding to os_reportType values.
* @see os_reportType
*/
const char *os_reportTypeText [] = {
"DEBUG",
"INFO",
"WARNING",
"ERROR",
"CRITICAL",
"FATAL",
"NONE"
};
enum os_report_logType {
OS_REPORT_INFO_LOG,
OS_REPORT_ERROR_LOG
};
static char * os_report_defaultInfoFileName = OS_PROJECT_NAME_NOSPACE_SMALL"-info.log";
static char * os_report_defaultErrorFileName = OS_PROJECT_NAME_NOSPACE_SMALL"-error.log";
static const char os_env_logdir[] = OS_PROJECT_NAME_NOSPACE_CAPS"_LOGPATH";
static const char os_env_infofile[] = OS_PROJECT_NAME_NOSPACE_CAPS"_INFOFILE";
static const char os_env_errorfile[] = OS_PROJECT_NAME_NOSPACE_CAPS"_ERRORFILE";
static const char os_env_verbosity[] = OS_PROJECT_NAME_NOSPACE_CAPS"_VERBOSITY";
static const char os_env_append[] = OS_PROJECT_NAME_NOSPACE_CAPS"_LOGAPPEND";
#if defined _WRS_KERNEL
static const char os_default_logdir[] = "/tgtsvr";
#else
static const char os_default_logdir[] = ".";
#endif
static _Ret_maybenull_ FILE *
os__open_file (
_In_z_ const char * file_name)
{
FILE *logfile=NULL;
const char *dir = os_getenv (os_env_logdir);
char * nomalized_dir;
char *str;
size_t len;
os_result res = os_resultSuccess;
if (dir == NULL) {
dir = os_default_logdir;
}
len = strlen (dir) + 2; /* '/' + '\0' */
str = os_malloc (len);
if (str != NULL) {
(void)snprintf (str, len, "%s/", dir);
nomalized_dir = os_fileNormalize (str);
os_free (str);
if (nomalized_dir == NULL) {
res = os_resultFail;
}
os_free(nomalized_dir);
} else {
res = os_resultFail;
}
if (res == os_resultSuccess) {
logfile = fopen (file_name, "a");
}
return logfile;
}
static void
os__close_file (
_In_z_ const char * file_name,
_In_ _Post_invalid_ FILE *file)
{
if (strcmp(file_name, "<stderr>") != 0 && strcmp(file_name, "<stdout>") != 0)
{
fclose(file);
}
}
_Check_return_ _Ret_z_
static char *os__report_createFileNormalize(
_In_z_ const char *file_dir,
_In_z_ const char *file_name)
{
char file_path[MAX_FILE_PATH];
int len;
len = snprintf(file_path, MAX_FILE_PATH, "%s/%s", file_dir, file_name);
/* Note bug in glibc < 2.0.6 returns -1 for output truncated */
if ( len < MAX_FILE_PATH && len > -1 ) {
return (os_fileNormalize(file_path));
} else {
return os_strdup(file_name);
}
}
/**
* Return either a log file path string or a pseudo file name/path value
* like <stdout> or <stderr>.
* The result of os_report_file_path must be freed with os_free
* @param override_variable An environment variable name that may hold a filename
* or pseudo filename. If this var is set, and is not a pseudo filename,
* the value of this var will be added to the value of env variable
* {OS_PROJECT_NAME_NOSPACE_CAPS}_LOGPATH (if set or './' if not) to create the
* log file path.
* @param default_file If override_variable is not defined in the environment
* this is the filename used.
*/
_Ret_z_
_Check_return_
static char *
os__report_file_path(
_In_z_ const char * default_file,
_In_opt_z_ const char * override_variable,
_In_ enum os_report_logType type)
{
const char *file_dir;
const char *file_name = NULL;
if (override_variable != NULL)
{
file_name = os_getenv(override_variable);
}
if (!file_name)
{
file_name = default_file;
}
file_dir = os_getenv(os_env_logdir);
if (!file_dir)
{
file_dir = os_default_logdir;
}
else
{
/* We just need to check if a file can be written to the directory, we just use the
* default info file as there will always be one created, if we used the variables
* passed in we would create an empty error log (which is bad for testing) and we
* cannot delete it as we open the file with append
*/
if (type == OS_REPORT_INFO_LOG)
{
FILE *logfile;
char *full_file_path;
full_file_path = os_malloc(strlen(file_dir) + 1 + strlen(file_name) + 1);
strcpy(full_file_path, file_dir);
strcat(full_file_path, "/");
strcat(full_file_path, file_name);
logfile = fopen (full_file_path, "a");
if (logfile)
{
fclose(logfile);
}
os_free (full_file_path);
}
}
if (strcmp(file_name, "<stderr>") != 0 && strcmp(file_name, "<stdout>") != 0)
{
return (os__report_createFileNormalize(file_dir, file_name));
}
return os_strdup (file_name);
}
/**
* Overrides the current minimum output level to be reported from
* this process.
* @param newVerbosity String holding either an integer value corresponding
* to an acceptable (in range) log verbosity or a string verbosity 'name'
* like 'ERROR' or 'warning' or 'DEBUG' or somesuch.
* @return os_resultFail if the string contains neither of the above;
* os_resultSuccess otherwise.
*/
static os_result
os__determine_verbosity(
_In_z_ const char* newVerbosity)
{
long verbosityInt;
os_result result = os_resultFail;
verbosityInt = strtol(newVerbosity, NULL, 0);
if (verbosityInt == 0 && strcmp("0", newVerbosity)) {
/* Conversion from int failed. See if it's one of the string forms. */
while (verbosityInt < (long) (sizeof(os_reportTypeText) / sizeof(os_reportTypeText[0]))) {
if (os_strcasecmp(newVerbosity, os_reportTypeText[verbosityInt]) == 0) {
break;
}
++verbosityInt;
}
}
if (verbosityInt >= 0 && verbosityInt < (long) (sizeof(os_reportTypeText) / sizeof(os_reportTypeText[0]))) {
/* OS_API_INFO label is kept for backwards compatibility. */
os_reportVerbosity = (os_reportType)verbosityInt;
result = os_resultSuccess;
}
return result;
}
void os__set_verbosity(void)
{
const char * envValue = os_getenv(os_env_verbosity);
if (envValue != NULL)
{
if (os__determine_verbosity(envValue) == os_resultFail)
{
OS_WARNING("os_reportInit", 0,
"Cannot parse report verbosity %s value \"%s\","
" reporting verbosity remains %s", os_env_verbosity, envValue, os_reportTypeText[os_reportVerbosity]);
}
}
}
/**
* Get the destination for logging error reports. Env property {OS_PROJECT_NAME_NOSPACE_CAPS}_INFOFILE and
* {OS_PROJECT_NAME_NOSPACE_CAPS}_LOGPATH controls this value.
* If {OS_PROJECT_NAME_NOSPACE_CAPS}_INFOFILE is not set & this process is a service, default
* to logging to a file named {OS_PROJECT_NAME_NOSPACE_SMALL}-info.log, otherwise
* use standard out.
* @see os_report_file_path
*/
_Ret_z_
_Check_return_
static char *
os__get_info_file_name(void)
{
char * file_name;
os_mutexLock(&infologcreateMutex);
file_name = os__report_file_path (os_report_defaultInfoFileName, os_env_infofile, OS_REPORT_INFO_LOG);
os_mutexUnlock(&infologcreateMutex);
return file_name;
}
/**
* Get the destination for logging error reports. Env property {OS_PROJECT_NAME_NOSPACE_CAPS}_ERRORFILE and
* {OS_PROJECT_NAME_NOSPACE_CAPS}_LOGPATH controls this value.
* If {OS_PROJECT_NAME_NOSPACE_CAPS}_ERRORFILE is not set & this process is a service, default
* to logging to a file named {OS_PROJECT_NAME_NOSPACE_SMALL}-error.log, otherwise
* use standard error.
* @see os_report_file_path
*/
_Ret_z_
_Check_return_
static char *
os__get_error_file_name(void)
{
char * file_name;
os_mutexLock(&errorlogcreateMutex);
file_name = os__report_file_path (os_report_defaultErrorFileName, os_env_errorfile, OS_REPORT_ERROR_LOG);
os_mutexUnlock(&errorlogcreateMutex);
return file_name;
}
static void os__remove_stale_logs(void)
{
if (!StaleLogsRemoved) {
/* TODO: Only a single process or spliced (as 1st process) is allowed to
* delete the log files. */
/* Remove ospl-info.log and ospl-error.log.
* Ignore the result because it is possible that they don't exist yet. */
char * log_file_name;
log_file_name = os__get_error_file_name();
(void)os_remove(log_file_name);
os_free(log_file_name);
log_file_name = os__get_info_file_name();
(void)os_remove(log_file_name);
os_free(log_file_name);
StaleLogsRemoved = true;
}
}
static void os__check_removal_stale_logs(void)
{
const char * envValue = os_getenv(os_env_append);
if (envValue != NULL)
{
if (os_strcasecmp(envValue, "FALSE") == 0 ||
os_strcasecmp(envValue, "0") == 0 ||
- os_strcasecmp(envValue, "NO") == 0) {
os__remove_stale_logs();
}
}
}
/**
* Read environment properties. In particular ones that can't be left until
* there is a requirement to log.
*/
void os_reportInit(
_In_ bool forceReInit)
{
if (forceReInit) {
inited = false;
}
if (!inited)
{
os_mutexInit(&reportMutex);
os_mutexInit(&errorlogcreateMutex);
os_mutexInit(&infologcreateMutex);
os__check_removal_stale_logs();
os__set_verbosity();
}
inited = true;
}
void os_reportExit(void)
{
char *name;
os_reportStack reports;
reports = os_threadMemGet(OS_THREAD_REPORT_STACK);
if (reports) {
os__report_dumpStack(OS_FUNCTION, __FILE__, __LINE__);
os_iterFree(reports->reports, NULL);
os_threadMemFree(OS_THREAD_REPORT_STACK);
}
inited = false;
os_mutexDestroy(&reportMutex);
if (error_log)
{
name = os__get_error_file_name();
os__close_file(name, error_log);
os_free (name);
error_log = NULL;
}
if (info_log)
{
name = os__get_info_file_name();
os__close_file(name, info_log);
os_free (name);
info_log = NULL;
}
os_mutexDestroy(&errorlogcreateMutex);
os_mutexDestroy(&infologcreateMutex);
}
static void os__report_fprintf(
_Inout_ FILE *file,
_In_z_ _Printf_format_string_ const char *format, ...)
{
int BytesWritten = 0;
va_list args;
va_start(args, format);
BytesWritten = os_vfprintfnosigpipe(file, format, args);
va_end(args);
if (BytesWritten == -1) {
/* error occurred ?, try to write to stdout. (also with no sigpipe,
* stdout can also give broken pipe)
*/
va_start(args, format);
(void) os_vfprintfnosigpipe(stdout, format, args);
va_end(args);
}
}
static _Ret_notnull_ FILE* os__get_info_file (void)
{
if (info_log == NULL) {
char * name = os__get_info_file_name();
info_log = os__open_file(name);
if (!info_log)
{
info_log = stdout;
}
os_free (name);
}
return info_log;
}
static _Ret_notnull_ FILE* os__get_error_file (void)
{
if (error_log == NULL) {
char * name = os__get_error_file_name();
error_log = os__open_file(name);
if (!error_log)
{
error_log = stderr;
}
os_free (name);
}
return error_log;
}
static void os__sectionReport(
_Pre_notnull_ _Post_notnull_ os_reportEventV1 event,
_In_ bool useErrorLog)
{
os_time ostime;
FILE *log = useErrorLog ? os__get_error_file() : os__get_info_file();
ostime = os_timeGet();
os_mutexLock(&reportMutex);
os__report_fprintf(log,
"----------------------------------------------------------------------------------------\n"
"Report : %s\n"
"Internals : %s/%s/%d/%d/%d.%09d\n",
event->description,
event->reportContext,
event->fileName,
event->lineNo,
event->code,
ostime.tv_sec,
ostime.tv_nsec);
fflush (log);
os_mutexUnlock(&reportMutex);
}
static void os__headerReport(
_Pre_notnull_ _Post_notnull_ os_reportEventV1 event,
_In_ bool useErrorLog)
{
os_time ostime;
char node[64];
char date_time[128];
FILE *log = NULL;
if (useErrorLog)
log = os__get_error_file();
else log = os__get_info_file();
ostime = os_timeGet();
os_ctime_r(&ostime, date_time, sizeof(date_time));
if (os_gethostname(node, sizeof(node)-1) == os_resultSuccess)
{
node[sizeof(node)-1] = '\0';
}
else
{
strcpy(node, "UnkownNode");
}
os_mutexLock(&reportMutex);
os__report_fprintf(log,
"========================================================================================\n"
"ReportType : %s\n"
"Context : %s\n"
"Date : %s\n"
"Node : %s\n"
"Process : %s\n"
"Thread : %s\n"
"Internals : %s/%d/%s/%s/%s\n",
os_reportTypeText[event->reportType],
event->description,
date_time,
node,
event->processDesc,
event->threadDesc,
event->fileName,
event->lineNo,
OSPL_VERSION_STR,
OSPL_INNER_REV_STR,
OSPL_OUTER_REV_STR);
fflush (log);
os_mutexUnlock(&reportMutex);
}
static void os__defaultReport(
_Pre_notnull_ _Post_notnull_ os_reportEventV1 event)
{
os_time ostime;
char node[64];
char date_time[128];
FILE *log;
switch (event->reportType) {
case OS_REPORT_DEBUG:
case OS_REPORT_INFO:
case OS_REPORT_WARNING:
log = os__get_info_file();
break;
case OS_REPORT_ERROR:
case OS_REPORT_CRITICAL:
case OS_REPORT_FATAL:
default:
log = os__get_error_file();
break;
}
ostime = os_timeGet();
os_ctime_r(&ostime, date_time, sizeof(date_time));
if (os_gethostname(node, sizeof(node)-1) == os_resultSuccess)
{
node[sizeof(node)-1] = '\0';
}
else
{
strcpy(node, "UnkownNode");
}
os_mutexLock(&reportMutex);
os__report_fprintf (log,
"========================================================================================\n"
"Report : %s\n"
"Date : %s\n"
"Description : %s\n"
"Node : %s\n"
"Process : %s\n"
"Thread : %s\n"
"Internals : %s/%s/%s/%s/%s/%d/%d/%d.%09d\n",
os_reportTypeText[event->reportType],
date_time,
event->description,
node,
event->processDesc,
event->threadDesc,
OSPL_VERSION_STR,
OSPL_INNER_REV_STR,
OSPL_OUTER_REV_STR,
event->reportContext,
event->fileName,
event->lineNo,
event->code,
ostime.tv_sec,
ostime.tv_nsec);
fflush (log);
os_mutexUnlock(&reportMutex);
}
void os_report_message(
_In_ os_reportType type,
_In_z_ const char *context,
_In_z_ const char *path,
_In_ int32_t line,
_In_ int32_t code,
_In_z_ const char *message)
{
char *file;
char procid[256], thrid[64];
os_reportStack stack;
struct os_reportEventV1_s report = { OS_REPORT_EVENT_V1, /* version */
OS_REPORT_NONE, /* reportType */
NULL, /* reportContext */
NULL, /* fileName */
0, /* lineNo */
0, /* code */
NULL, /* description */
NULL, /* threadDesc */
NULL /* processDesc */
};
file = (char *)path;
/* Only figure out process and thread identities if the user requested an
entry in the default log file or registered a typed report plugin. */
os_procNamePid (procid, sizeof (procid));
os_threadFigureIdentity (thrid, sizeof (thrid));
report.reportType = type;
report.reportContext = (char *)context;
report.fileName = (char *)file;
report.lineNo = line;
report.code = code;
report.description = (char *)message;
report.threadDesc = thrid;
report.processDesc = procid;
stack = (os_reportStack)os_threadMemGet(OS_THREAD_REPORT_STACK);
if (stack && stack->count) {
if (report.reportType != OS_REPORT_NONE) {
os__report_append (stack, &report);
}
} else {
os__defaultReport (&report);
}
}
void os_report(
_In_ os_reportType type,
_In_z_ const char *context,
_In_z_ const char *path,
_In_ int32_t line,
_In_ int32_t code,
_In_z_ _Printf_format_string_ const char *format,
...)
{
char buf[OS_REPORT_BUFLEN];
va_list args;
if (!inited) {
return;
}
if (type < os_reportVerbosity) {
return;
}
va_start (args, format);
(void)os_vsnprintf (buf, sizeof(buf), format, args);
va_end (args);
os_report_message(type, context, path, line, code, buf);
}
/*****************************************
* Report-stack related functions
*****************************************/
void os_report_stack(void)
{
os_reportStack _this;
if (inited == false) {
return;
}
_this = (os_reportStack)os_threadMemGet(OS_THREAD_REPORT_STACK);
if (!_this) {
/* Report stack does not exist yet, so create it */
_this = os_threadMemMalloc(OS_THREAD_REPORT_STACK, sizeof(struct os_reportStack_s));
if (_this) {
_this->count = 1;
_this->typeset = 0;
_this->file = NULL;
_this->lineno = 0;
_this->signature = NULL;
_this->reports = os_iterNew();
} else {
OS_ERROR("os_report_stack", 0,
"Failed to initialize report stack (could not allocate thread-specific memory)");
}
} else {
/* Use previously created report stack */
if (_this->count == 0) {
_this->file = NULL;
_this->lineno = 0;
_this->signature = NULL;
}
_this->count++;
}
}
void os_report_stack_free(void)
{
os_reportStack _this;
os_reportEventV1 report;
_this = (os_reportStack)os_threadMemGet(OS_THREAD_REPORT_STACK);
if (_this) {
while((report = os_iterTake(_this->reports, -1))) {
os__report_free(report);
}
os_iterFree(_this->reports, NULL);
os_threadMemFree(OS_THREAD_REPORT_STACK);
}
}
static void
os__report_stack_unwind(
_Inout_ os_reportStack _this,
_In_ bool valid,
_In_z_ const char *context,
_In_z_ const char *path,
_In_ int line)
{
struct os_reportEventV1_s header;
os_reportEventV1 report;
char *file;
bool useErrorLog;
os_reportType reportType = OS_REPORT_ERROR;
if (!valid) {
if (OS_REPORT_IS_ALWAYS(_this->typeset)) {
valid = true;
}
} else {
reportType = OS_REPORT_FLAG_TYPE(_this->typeset);
}
useErrorLog = OS_REPORT_IS_ERROR(_this->typeset);
/* Typeset will be set when a report was appended. */
if (valid && (_this->typeset != 0)) {
char proc[256], procid[256];
char thr[64], thrid[64];
os_procId pid;
uintmax_t tid;
assert (context != NULL);
assert (path != NULL);
file = (char *)path;
pid = os_procIdSelf ();
tid = os_threadIdToInteger (os_threadIdSelf ());
os_procNamePid (procid, sizeof (procid));
os_procName (proc, sizeof (proc));
os_threadFigureIdentity (thrid, sizeof (thrid));
os_threadGetThreadName (thr, sizeof (thr));
header.reportType = reportType;
header.description = (char *)context;
header.processDesc = procid;
header.threadDesc = thrid;
header.fileName = file;
header.lineNo = line;
os__headerReport (&header, useErrorLog);
}
while ((report = os_iterTake(_this->reports, -1))) {
if (valid) {
os__sectionReport (report, useErrorLog);
}
os__report_free(report);
}
_this->typeset = 0;
}
static void
os__report_dumpStack(
_In_z_ const char *context,
_In_z_ const char *path,
_In_ int line)
{
os_reportStack _this;
if (inited == false) {
return;
}
_this = os_threadMemGet(OS_THREAD_REPORT_STACK);
if ((_this) && (_this->count > 0)) {
os__report_stack_unwind(_this, true, context, path, line);
}
}
void os_report_flush(
_In_ bool valid,
_In_z_ const char *context,
_In_z_ const char *path,
_In_ int line)
{
os_reportStack _this;
if (inited == false) {
return;
}
_this = os_threadMemGet(OS_THREAD_REPORT_STACK);
if ((_this) && (_this->count)) {
if (_this->count == 1) {
os__report_stack_unwind(_this, valid, context, path, line);
_this->file = NULL;
_this->signature = NULL;
_this->lineno = 0;
}
_this->count--;
}
}
#define OS__STRDUP(str) (str != NULL ? os_strdup(str) : os_strdup("NULL"))
static void
os__report_append(
_Inout_ os_reportStack _this,
_In_ const os_reportEventV1 report)
{
os_reportEventV1 copy;
copy = os_malloc(sizeof(*copy));
copy->code = report->code;
copy->description = OS__STRDUP(report->description);
copy->fileName = OS__STRDUP(report->fileName);
copy->lineNo = report->lineNo;
copy->processDesc = OS__STRDUP(report->processDesc);
copy->reportContext = OS__STRDUP(report->reportContext);
copy->reportType = report->reportType;
copy->threadDesc = OS__STRDUP(report->threadDesc);
copy->version = report->version;
_this->typeset |= OS_REPORT_TYPE_FLAG(report->reportType);
os_iterAppend(_this->reports, copy);
}
static void
os__report_free(
_In_ _Post_invalid_ os_reportEventV1 report)
{
os_free(report->description);
os_free(report->fileName);
os_free(report->processDesc);
os_free(report->reportContext);
os_free(report->threadDesc);
os_free(report);
}

511
src/os/src/os_socket.c Normal file
View file

@ -0,0 +1,511 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/****************************************************************
* Implementation for socket services conforming to *
* OpenSplice requirements *
****************************************************************/
/** \file os/code/os_socket.c
* \brief socket management
*/
#include <assert.h>
#include <string.h>
#include "os/os.h"
#if (OS_SOCKET_HAS_IPV6 == 1)
#ifndef _VXWORKS
const os_in6_addr os_in6addr_any = IN6ADDR_ANY_INIT;
const os_in6_addr os_in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
#else
const os_in6_addr os_in6addr_any = { { 0 } };
const os_in6_addr os_in6addr_loopback = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } };
#endif
#endif
#ifndef OS_INET_NTOP
#define OS_INET_NTOP inet_ntop
#endif
#ifndef OS_INET_PTON
#define OS_INET_PTON inet_pton
#endif
static
void os__sockaddrInit4(os_sockaddr* sa)
{
assert(sa);
/* 0 is a valid value for all members besides sa_family */
memset(sa, 0, sizeof(os_sockaddr_in));
sa->sa_family = AF_INET;
}
#if (OS_SOCKET_HAS_IPV6 == 1)
static
void os__sockaddrInit6(os_sockaddr* sa)
{
assert(sa);
/* 0 is a valid value for all members besides sa_family */
memset(sa, 0, sizeof(os_sockaddr_in6));
sa->sa_family = AF_INET6;
}
#endif
/**
* Initialises the memory pointed to by sa. The address family
* will be set correctly according to isIPv4.
* @param sa Pointer to the os_sockaddr to be initialised
* @param isIPv4 Flag indicating whether *sa will be IPv4 or IPv6. If
* IPv6 is not supported but this flag is FALSE, sa will be initialised
* as IPv4 and an API-warning is logged.
* @pre sa != NULL
* @return os_resultSuccess on successful initialisation, os_resultInvalid
* if isIPv4 was FALSE but IPv6 is not supported.
* @post sa is initialised
* @note Please be aware that the memory will be memset; make sure that
* enough memory for the requested address kind is available. Allocating
* os_sockaddr_storage always suffices.
*/
os_result
os_sockaddrInit(os_sockaddr* sa,
bool isIPv4)
{
os_result result = os_resultSuccess;
assert(sa);
if (!isIPv4)
{
#if (OS_SOCKET_HAS_IPV6 == 1)
os__sockaddrInit6(sa);
#else
OS_ERROR("os_sockaddrInit", 0,
"Unsupported parameter value: IPV6 address requested but not supported by this platform");
os__sockaddrInit4(sa);
result = os_resultInvalid;
#endif
}
else
{
os__sockaddrInit4(sa);
}
return result;
}
/**
* Compare two socket IP host addresses for equality - does not consider the port number.
* This is a 'straight' equal i.e. family must match and address bytes
* must correspond. So it will not consider the possibility of IPv6 mapped
* IPv4 addresses or anything arcane like that.
* @param thisSock First address
* @param thatSock Second address.
* @return true if equal, false otherwise.
*/
bool
os_sockaddrIPAddressEqual(const os_sockaddr* thisSock,
const os_sockaddr* thatSock)
{
bool result = false;
#if (OS_SOCKET_HAS_IPV6 == 1)
os_sockaddr_in6 * thisV6, * thatV6;
#endif
if (thisSock->sa_family == thatSock->sa_family)
{
if (thisSock->sa_family == AF_INET)
{
/* IPv4 */
result = (((os_sockaddr_in*)thisSock)->sin_addr.s_addr ==
((os_sockaddr_in*)thatSock)->sin_addr.s_addr ?
true: false);
}
#if (OS_SOCKET_HAS_IPV6 == 1)
else
{
/* IPv6 */
thisV6 = (os_sockaddr_in6*) thisSock;
thatV6 = (os_sockaddr_in6*) thatSock;
result = (memcmp(&thisV6->sin6_addr.s6_addr, &thatV6->sin6_addr.s6_addr, sizeof(unsigned char) * 16) ?
false : true);
}
#endif
}
return result;
}
int
os_sockaddrIpAddressCompare(const os_sockaddr* addr1,
const os_sockaddr* addr2)
{
int result = -1;
uint16_t port1, port2;
int r;
#if (OS_SOCKET_HAS_IPV6 == 1)
os_sockaddr_in6 * thisV6, * thatV6;
#endif
if (addr1->sa_family == addr2->sa_family)
{
if (addr1->sa_family == AF_INET)
{
/* IPv4 */
if (((os_sockaddr_in*)addr1)->sin_addr.s_addr ==
((os_sockaddr_in*)addr2)->sin_addr.s_addr) {
port1 = os_sockaddrGetPort(addr1);
port2 = os_sockaddrGetPort(addr2);
if (port1 == port2) {
result = 0;
} else {
if (port1 > port2) {
result = 1;
} else {
result = -1;
}
}
} else {
if (((os_sockaddr_in*)addr1)->sin_addr.s_addr >
((os_sockaddr_in*)addr2)->sin_addr.s_addr) {
result = 1;
} else {
result = -1;
}
}
}
#if (OS_SOCKET_HAS_IPV6 == 1)
else
{
/* IPv6 */
thisV6 = (os_sockaddr_in6*) addr1;
thatV6 = (os_sockaddr_in6*) addr2;
r = memcmp(&thisV6->sin6_addr.s6_addr, &thatV6->sin6_addr.s6_addr, sizeof(unsigned char) * 16);
if (r == 0) {
port1 = os_sockaddrGetPort(addr1);
port2 = os_sockaddrGetPort(addr2);
if (port1 == port2) {
result = 0;
} else {
if (port1 > port2) {
result = 1;
} else {
result = -1;
}
}
} else {
if (r > 0) {
result = 1;
} else {
result = -1;
}
}
}
#endif
}
return result;
}
/**
* Checks two socket IP host addresses for be on the same subnet, considering the given subnetmask.
* It will not consider the possibility of IPv6 mapped IPv4 addresses or anything arcane like that.
* @param thisSock First address
* @param thatSock Second address.
* @param mask Subnetmask.
* @return true if equal, false otherwise.
*/
bool
os_sockaddrSameSubnet(const os_sockaddr* thisSock,
const os_sockaddr* thatSock,
const os_sockaddr* mask)
{
bool result = false;
#if (OS_SOCKET_HAS_IPV6 == 1)
os_sockaddr_in6 thisV6, thatV6, *maskV6;
#endif
if (thisSock->sa_family == thatSock->sa_family &&
thisSock->sa_family == mask->sa_family)
{
if (thisSock->sa_family == AF_INET)
{
/* IPv4 */
result = ((((os_sockaddr_in*)thisSock)->sin_addr.s_addr & ((os_sockaddr_in*)mask)->sin_addr.s_addr ) ==
(((os_sockaddr_in*)thatSock)->sin_addr.s_addr & ((os_sockaddr_in*)mask)->sin_addr.s_addr) ?
true: false);
}
#if (OS_SOCKET_HAS_IPV6 == 1)
else
{
size_t i, size;
/* IPv6 */
memcpy(&thisV6, thisSock, sizeof(thisV6));
memcpy(&thatV6, thatSock, sizeof(thatV6));
maskV6 = (os_sockaddr_in6*) mask;
size = sizeof(thisV6.sin6_addr.s6_addr);
for (i=0; i < size; i++) {
thisV6.sin6_addr.s6_addr[i] &= maskV6->sin6_addr.s6_addr[i];
thatV6.sin6_addr.s6_addr[i] &= maskV6->sin6_addr.s6_addr[i];
}
result = (memcmp(&thisV6.sin6_addr.s6_addr, &thatV6.sin6_addr.s6_addr, size) ?
false : true);
}
#endif
}
return result;
}
#if WIN32
/*
* gai_strerror under Windows is not thread safe. See getaddrinfo on MSDN:
* https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520.aspx
*
* The error codes that getaddrinfo returns map directly onto WSA error codes.
* os_strerror_r can therefore safely be used to retrieve their description.
*/
#define os_gai_strerror(errnum) os_strerror(errnum)
#else
#define os_gai_strerror(errnum) gai_strerror(errnum)
#endif /* WIN32 */
_Success_(return) bool
os_sockaddrStringToAddress(
_In_z_ const char *addressString,
_When_(isIPv4, _Out_writes_bytes_(sizeof(os_sockaddr_in)))
_When_(!isIPv4, _Out_writes_bytes_(sizeof(os_sockaddr_in6)))
os_sockaddr *addressOut,
_In_ bool isIPv4)
{
int ret;
const char *fmt;
struct addrinfo hints;
struct addrinfo *res = NULL;
assert(addressString != NULL);
assert(addressOut != NULL);
memset(&hints, 0, sizeof(hints));
#if (OS_SOCKET_HAS_IPV6 == 1)
hints.ai_family = (isIPv4 ? AF_INET : AF_INET6);
#else
hints.ai_family = AF_INET;
OS_UNUSED_ARG(isIPv4);
#endif /* IPv6 */
hints.ai_socktype = SOCK_DGRAM;
ret = getaddrinfo(addressString, NULL, &hints, &res);
if (ret != 0) {
fmt = "getaddrinfo(\"%s\") failed: %s";
OS_DEBUG(OS_FUNCTION, 0, fmt, addressString, os_gai_strerror(ret));
} else if (res != NULL) {
memcpy(addressOut, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
} else {
fmt = "getaddrinfo(\"%s\") did not return any results";
OS_DEBUG(OS_FUNCTION, 0, fmt, addressString);
}
return (ret == 0 && res != NULL);
}
/**
* Check this address to see if it represents loopback.
* @return true if it does. false otherwise, or if unknown address type.
* @param thisSock A pointer to an os_sockaddr to be checked.
*/
bool
os_sockaddrIsLoopback(const os_sockaddr* thisSock)
{
bool result = false;
#if (OS_SOCKET_HAS_IPV6 == 1)
static os_sockaddr_storage linkLocalLoopback;
static os_sockaddr* linkLocalLoopbackPtr = NULL;
if (linkLocalLoopbackPtr == NULL)
{
/* Initialise once (where 'once' implies some small integer) */
os_sockaddrStringToAddress("fe80::1", (os_sockaddr*) &linkLocalLoopback, false /* ! ipv4 */ );
linkLocalLoopbackPtr = (os_sockaddr*) &linkLocalLoopback;
}
if (thisSock->sa_family == AF_INET6)
{
result = IN6_IS_ADDR_LOOPBACK(&((os_sockaddr_in6*)thisSock)->sin6_addr) ||
os_sockaddrIPAddressEqual(thisSock, linkLocalLoopbackPtr) ? true : false;
}
else
#endif
if (thisSock->sa_family == AF_INET)
{
result = (INADDR_LOOPBACK == ntohl(((os_sockaddr_in*)thisSock)->sin_addr.s_addr)) ? true : false;
}
return result;
}
size_t
os_sockaddrSizeof(
const os_sockaddr* sa)
{
size_t result;
assert(sa);
switch(sa->sa_family){
#if (OS_SOCKET_HAS_IPV6 == 1)
case AF_INET6:
result = sizeof(os_sockaddr_in6);
break;
#endif
case AF_INET:
result = sizeof(os_sockaddr_in);
break;
default:
#if (OS_SOCKET_HAS_IPV6 == 1)
OS_ERROR("os_sockaddrSizeof", 0,
"Unkown address family specified: %d. Should be AF_INET (%d) or AF_INET6 (%d)",
(int)sa->sa_family, AF_INET, AF_INET6);
#else
OS_ERROR("os_sockaddrSizeof", 0,
"Unkown address family specified: %d. Should be AF_INET (%d)",
(int)sa->sa_family, AF_INET);
#endif
result = 0;
break;
}
return result;
}
void
os_sockaddrSetInAddrAny(
os_sockaddr* sa)
{
assert(sa);
#if (OS_SOCKET_HAS_IPV6 == 1)
assert(sa->sa_family == AF_INET6 || sa->sa_family == AF_INET);
if (sa->sa_family == AF_INET6){
((os_sockaddr_in6*)sa)->sin6_addr = os_in6addr_any;
((os_sockaddr_in6*)sa)->sin6_scope_id = 0;
}
else
#else
assert(sa->sa_family == AF_INET);
#endif
if (sa->sa_family == AF_INET){
((os_sockaddr_in*)sa)->sin_addr.s_addr = htonl(INADDR_ANY);
}
}
void
os_sockaddrSetPort(
os_sockaddr* sa,
uint16_t port /* network byte order */)
{
assert(sa);
#if (OS_SOCKET_HAS_IPV6 == 1)
assert(sa->sa_family == AF_INET6 || sa->sa_family == AF_INET);
if (sa->sa_family == AF_INET6)
{
((os_sockaddr_in6*)sa)->sin6_port = port;
}
else
#else
assert(sa->sa_family == AF_INET);
#endif
if (sa->sa_family == AF_INET)
{
((os_sockaddr_in*)sa)->sin_port = port;
}
}
uint16_t /* network byte order */
os_sockaddrGetPort(
const os_sockaddr* const sa)
{
uint16_t port = 0;
assert(sa);
#if (OS_SOCKET_HAS_IPV6 == 1)
assert(sa->sa_family == AF_INET6 || sa->sa_family == AF_INET);
if (sa->sa_family == AF_INET6)
{
port = (uint16_t)((os_sockaddr_in6*)sa)->sin6_port;
}
else
#else
assert(sa->sa_family == AF_INET);
#endif
if (sa->sa_family == AF_INET)
{
port = (uint16_t)((os_sockaddr_in*)sa)->sin_port;
}
return port;
}
char*
os_sockaddrAddressToString(const os_sockaddr* sa,
char* buffer, size_t buflen)
{
assert (buflen <= 0x7fffffff);
switch(sa->sa_family) {
case AF_INET:
OS_INET_NTOP(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
buffer, (socklen_t) buflen);
break;
#if (OS_SOCKET_HAS_IPV6 == 1)
case AF_INET6:
OS_INET_NTOP(AF_INET6, &(((os_sockaddr_in6 *)sa)->sin6_addr),
buffer, (socklen_t) buflen);
break;
#endif
default:
(void) snprintf(buffer, buflen, "Unknown address family");
break;
}
return buffer;
}
char*
os_sockaddrAddressPortToString(
const os_sockaddr* sa,
char* buffer,
size_t buflen)
{
size_t pos;
switch (sa->sa_family)
{
case AF_INET:
os_sockaddrAddressToString (sa, buffer, buflen);
pos = strlen (buffer);
(void) snprintf (buffer + pos, buflen - pos, ":%hu", ntohs (((os_sockaddr_in *) sa)->sin_port));
break;
#if OS_SOCKET_HAS_IPV6
case AF_INET6:
if(buflen){
buffer[0] = '[';
os_sockaddrAddressToString (sa, buffer + 1, buflen - 1);
pos = strlen (buffer);
(void) snprintf (buffer + pos, buflen - pos, "]:%hu", ntohs (((os_sockaddr_in6 *) sa)->sin6_port));
}
break;
#endif
default:
(void) snprintf(buffer, buflen, "Unknown address family");
break;
}
return buffer;
}

39
src/os/src/os_thread.c Normal file
View file

@ -0,0 +1,39 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file os/common/code/os_thread_attr.c
* \brief Common thread attributes
*
* Implements os_threadAttrInit and sets attributes
* to platform independent values:
* - scheduling class is OS_SCHED_DEFAULT
* - thread priority is 0
*/
#include <assert.h>
#include "os/os.h"
/** \brief Initialize thread attributes
*
* - Set \b procAttr->schedClass to \b OS_SCHED_DEFAULT
* (take the platforms default scheduling class, Time-sharing for
* non realtime platforms, Real-time for realtime platforms)
* - Set \b procAttr->schedPriority to \b 0
*/
void
os_threadAttrInit (
os_threadAttr *threadAttr)
{
assert (threadAttr != NULL);
threadAttr->schedClass = OS_SCHED_DEFAULT;
threadAttr->schedPriority = 0;
threadAttr->stackSize = 0;
}

355
src/os/src/os_time.c Normal file
View file

@ -0,0 +1,355 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file os/common/code/os_time.c
* \brief Common time management services
*
* Implements os_timeAdd, os_timeSub, os_timeCompare,
* os_timeAbs, os_timeMulReal, os_timeToReal, os_realToTime
* which are platform independent
*/
#include <time.h>
#include <stdlib.h>
#include <assert.h>
#include "os/os.h"
/* double type definition for calculations in os_timeMulReal */
/* Can be adapted to available and required accuracy */
typedef double os_cdouble;
/** \brief return value of \b t1 + \b t2
*
* If the value \b t1 + \b t2 does not fit in os_time the value
* will be incorrect.
*/
os_time os_timeAdd(os_time t1, os_time t2)
{
os_time tr;
assert (t1.tv_nsec >= 0);
assert (t1.tv_nsec < 1000000000);
assert (t2.tv_nsec >= 0);
assert (t2.tv_nsec < 1000000000);
tr.tv_nsec = t1.tv_nsec + t2.tv_nsec;
tr.tv_sec = t1.tv_sec + t2.tv_sec;
if (tr.tv_nsec >= 1000000000) {
tr.tv_sec++;
tr.tv_nsec = tr.tv_nsec - 1000000000;
}
return tr;
}
/** \brief return value of \b t1 - \b t2
*
* If the value \b t1 - \b t2 does not fit in os_time the value
* will be incorrect.
*/
os_time os_timeSub(os_time t1, os_time t2)
{
os_time tr;
assert (t1.tv_nsec >= 0);
assert (t1.tv_nsec < 1000000000);
assert (t2.tv_nsec >= 0);
assert (t2.tv_nsec < 1000000000);
if (t1.tv_nsec >= t2.tv_nsec) {
tr.tv_nsec = t1.tv_nsec - t2.tv_nsec;
tr.tv_sec = t1.tv_sec - t2.tv_sec;
} else {
tr.tv_nsec = t1.tv_nsec - t2.tv_nsec + 1000000000;
tr.tv_sec = t1.tv_sec - t2.tv_sec - 1;
}
return tr;
}
/** \brief Compare \b t1 with \b t2
*
* - If the value of \b t1 < value of \b t2 return \b OS_LESS
* - If the value of \b t1 > value of \b t2 return \b OS_MORE
* - If the value of \b t1 equals the value of \b t2 return \b OS_EQUAL
*/
int
os_timeCompare(
os_time t1,
os_time t2)
{
int rv;
assert (t1.tv_nsec >= 0);
assert (t1.tv_nsec < 1000000000);
assert (t2.tv_nsec >= 0);
assert (t2.tv_nsec < 1000000000);
if (t1.tv_sec < t2.tv_sec) {
rv = -1;
} else if (t1.tv_sec > t2.tv_sec) {
rv = 1;
} else if (t1.tv_nsec < t2.tv_nsec) {
rv = -1;
} else if (t1.tv_nsec > t2.tv_nsec) {
rv = 1;
} else {
rv = 0;
}
return rv;
}
/** \brief return absolute value \b t
*
* If the value |\b t| does not fit in os_time the value
* will be incorrect.
*/
os_time
os_timeAbs(
os_time t)
{
os_time tr;
assert (t.tv_nsec >= 0);
assert (t.tv_nsec < 1000000000);
if (t.tv_sec < 0) {
tr.tv_sec = -t.tv_sec - 1;
tr.tv_nsec = 1000000000 - t.tv_nsec;
} else {
tr.tv_sec = t.tv_sec;
tr.tv_nsec = t.tv_nsec;
}
return tr;
}
/** \brief return value \b t * \b multiply
*
* if the result value does not fit in os_time the value
* will be incorrect.
*/
os_time
os_timeMulReal(
os_time t,
double multiply)
{
os_time tr;
os_cdouble trr;
os_cdouble sec;
os_cdouble nsec;
assert (t.tv_nsec >= 0);
assert (t.tv_nsec < 1000000000);
sec = (os_cdouble)t.tv_sec;
nsec = (os_cdouble)t.tv_nsec / (os_cdouble)1000000000.0;
trr = (sec + nsec) * multiply;
if (trr >= 0.0) {
tr.tv_sec = (os_timeSec)trr;
tr.tv_nsec = (int)((trr-(os_cdouble)tr.tv_sec) * (os_cdouble)1000000000.0);
} else {
tr.tv_sec = (os_timeSec)trr - 1;
tr.tv_nsec = (int)((trr-(os_cdouble)tr.tv_sec) * (os_cdouble)1000000000.0);
}
return tr;
}
/** \brief return floating point representation of \b t
*
* because of the limited floating point represenation (64 bits)
* the value will be limited to a resoltion of about 1 us.
*/
os_timeReal
os_timeToReal(
os_time t)
{
volatile os_timeReal tr; /* This var is volatile to bypass a GCC 3.x bug on X86 */
assert (t.tv_nsec >= 0);
assert (t.tv_nsec < 1000000000);
tr = (os_timeReal)t.tv_sec + (os_timeReal)t.tv_nsec / (os_timeReal)1000000000.0;
return tr;
}
/** \brief return os_time represenation of floating time \b t
*
* because of the limited floating point represenation (64 bits)
* the value will be limited to a resoltion of about 1 us.
*/
os_time
os_realToTime(
os_timeReal t)
{
os_time tr;
if (t >= 0.0) {
tr.tv_sec = (os_timeSec)t;
tr.tv_nsec = (int)((t-(os_timeReal)tr.tv_sec) * (os_timeReal)1000000000.0);
} else {
tr.tv_sec = (os_timeSec)t - 1;
tr.tv_nsec = (int)((t-(os_timeReal)tr.tv_sec) * (os_timeReal)1000000000.0);
}
assert(tr.tv_nsec >= 0 && tr.tv_nsec < 1000000000);
return tr;
}
#if 0
os_result
os_timeGetPowerEvents(
os_timePowerEvents *events,
os_time maxBlockingTime)
{
static os_time mt_el_offset; /* offset of os_timeGetElapsed() to os_timeGetMonotonic */
static int mt_el_offset_isset;
const os_time maxPowerEventDiffTime = { 3, 0 }; /* use 3 seconds as the threshold to determine whether a power event has occurred or not */
const os_time delay = { 0, 100000000 }; /* 100ms; seems a good balance between performance vs. reactivy */
static const os_time zeroTime = { 0, 0 };
os_time toBlock, delta, mt, el;
os_boolean stateEqualsEvents;
os_boolean timeoutDetected = OS_FALSE;
static os_timePowerEvents state;
assert(events);
toBlock = maxBlockingTime;
do {
/* TODO: When OSPL-4394 (clock-property querying) is done, this loop can
* be skipped when either of the clocks isn't available with the right
* properties. Perhaps the call should even return something to signal
* that this call isn't supported. */
mt = os_timeGetMonotonic();
el = os_timeGetElapsed(); /* Determine el last */
/* This isn't thread-safe, but since syncing should be more or less
* idempotent, this doesn't matter functionally. */
if(!mt_el_offset_isset){
mt_el_offset = os_timeSub(mt, el);
mt_el_offset_isset = 1;
}
/* A resume event is detected when the elapsed time differs from the
* monotonic time (expressed in elapsed-time) > maxPowerEventDiffTime. */
delta = os_timeSub(el, os_timeSub(mt, mt_el_offset));
if (os_timeCompare(delta, maxPowerEventDiffTime) == OS_MORE) {
pa_inc32_nv(&state.resumeCount);
/* Updating state.resumeLastDetected is NOT thread-safe! Consequently,
* these could be assigned an incorrect time value that does not
* reflect the actual time of occurrence of a power event when
* different threads are setting this value concurrently. The time
* value is (according to the interface) supposed to be used for
* logging only. */
state.resumeLastDetected = os_timeGet();
}
/* In all cases after the above check, the clocks can be re-synced. This
* isn't thread-safe, but since re-syncing should be more or less
* idempotent, this doesn't matter functionally. */
mt_el_offset = os_timeSub(mt, el);
/* If maxBlockingTime == 0, events is not an in-parameter, so its
* contents shouldn't be inspected. Furthermore, the function should
* never return os_resultTimeOut in this case, so break out of the loop. */
if(os_timeCompare(maxBlockingTime, zeroTime) == OS_EQUAL){
break;
}
stateEqualsEvents = (memcmp(&state, events, sizeof state) == 0) ? OS_TRUE : OS_FALSE;
if (stateEqualsEvents == OS_TRUE) {
if (os_timeCompare(toBlock, zeroTime) == OS_EQUAL) {
/* maxBlockingTime reached, break the loop */
timeoutDetected = OS_TRUE;
} else if (os_timeCompare(delay, toBlock) == OS_LESS) {
/* It is safe to sleep for delay */
os_nanoSleep(delay);
/* Set the new max blocking time and redo the loop. */
toBlock = os_timeSub(toBlock, delay);
} else {
/* The time to block is less than delay. */
os_nanoSleep(toBlock);
/* Set the resulting max blocking time zero to check for power
* events one more time. */
toBlock = zeroTime;
}
}
} while ( (stateEqualsEvents == OS_TRUE) && (timeoutDetected == OS_FALSE) );
/* Store current state in events */
*events = state;
return timeoutDetected ? os_resultTimeout : os_resultSuccess;
}
#endif
/* All implementations have to implement the os__timeDefaultTimeGet() function.
* This is the default clock that is used for os_timeGet(). This wrapper
* implements the ability to set a user-clock. */
/* Const-pointer to the default time implementation function. */
static os_time (*const os_time_clockGetDefaultFunc)(void) = os__timeDefaultTimeGet;
/* Pointer to the actual time implementation function. */
static os_time (*os_time_clockGetFunc)(void) = os__timeDefaultTimeGet;
/** \brief Set the user clock
*
* \b os_timeSetUserClock sets the current time source
* get function.
*/
void
os_timeSetUserClock(
os_time (*userClock)(void))
{
if (userClock) {
os_time_clockGetFunc = userClock;
} else {
os_time_clockGetFunc = os_time_clockGetDefaultFunc;
}
}
/** \brief Get the current time
*
* This common wrapper implements the user-clock overloading.
*/
os_time
os_timeGet (
void)
{
return os_time_clockGetFunc();
}
size_t os_ctime_r (os_time *t, char *buf, size_t bufsz)
{
size_t result = 0;
time_t tt = t->tv_sec;
assert(bufsz >= OS_CTIME_R_BUFSIZE);
if (buf) {
/* This should be common code. But unfortunately, VS2012 C Runtime contains
* a bug that causes a crash when using %Z with a buffer that is too small:
* https://connect.microsoft.com/VisualStudio/feedback/details/782889/
* So, don't execute strftime with %Z when VS2012 is the compiler. */
#if !(_MSC_VER == 1700)
result = strftime(buf, bufsz, "%a %b %d %H:%M:%S %Z %Y", localtime(&tt));
#endif
if(result == 0) {
/* If not enough room was available, the %Z (time-zone) is left out
* resulting in the output as expected from ctime_r. */
result = strftime(buf, bufsz, "%a %b %d %H:%M:%S %Y", localtime(&tt));
assert(result);
}
}
return result;
}

View file

@ -0,0 +1,12 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "../snippets/code/os_posix_errno.c"

View file

@ -0,0 +1,19 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file os/darwin/code/os_heap.c
* \brief Darwin heap memory management
*
* Implements heap memory management for Darwin
* by including the common implementation
*/
#include "../snippets/code/os_heap.c"

View file

@ -0,0 +1,87 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/****************************************************************
* Initialization / Deinitialization *
****************************************************************/
/** \file os/darwin/code/os_init.c
* \brief Initialization / Deinitialization
*/
#include <sys/utsname.h>
#include <assert.h>
#include "os/os.h"
/** \brief Counter that keeps track of number of times os-layer is initialized */
static os_atomic_uint32_t _ospl_osInitCount = OS_ATOMIC_UINT32_INIT(0);
/** \brief OS layer initialization
*
* \b os_osInit calls:
* - \b os_sharedMemoryInit
* - \b os_threadInit
*/
void os_osInit (void)
{
uint32_t initCount;
initCount = os_atomic_inc32_nv(&_ospl_osInitCount);
if (initCount == 1) {
os_syncModuleInit();
os_threadModuleInit();
os_processModuleInit();
os_reportInit(false);
}
return;
}
/** \brief OS layer deinitialization
*/
void os_osExit (void)
{
uint32_t initCount;
initCount = os_atomic_dec32_nv(&_ospl_osInitCount);
if (initCount == 0) {
os_reportExit();
os_processModuleExit();
os_threadModuleExit();
os_syncModuleExit();
} else if ((initCount + 1) < initCount){
/* The 0 boundary is passed, so os_osExit is called more often than
* os_osInit. Therefore undo decrement as nothing happened and warn. */
os_atomic_inc32(&_ospl_osInitCount);
OS_WARNING("os_osExit", 1, "OS-layer not initialized");
/* Fail in case of DEV, as it is incorrect API usage */
assert(0);
}
return;
}
/* This constructor is invoked when the library is loaded into a process. */
void __attribute__ ((constructor))
os__osInit(
void)
{
os_osInit();
}
/* This destructor is invoked when the library is unloaded from a process. */
void __attribute__ ((destructor))
os__osExit(
void)
{
os_osExit();
}

View file

@ -0,0 +1,53 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "os/os.h"
#include <unistd.h>
#include <stdlib.h>
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
#include "../snippets/code/os_posix_process.c"
#define _OS_PROCESS_DEFAULT_NAME_LEN_ (512)
int
os_procName(
char *procName,
size_t procNameSize)
{
#ifdef __APPLE__
char* exec, *processName = NULL;
int ret;
uint32_t usize = _OS_PROCESS_DEFAULT_NAME_LEN_;
processName = os_malloc(usize);
*processName = 0;
if (_NSGetExecutablePath(processName, &usize) != 0) {
/* processName is longer than allocated */
processName = os_realloc(processName, usize + 1);
if (_NSGetExecutablePath(processName, &usize) == 0) {
/* path set successful */
}
}
exec = strrchr(processName,'/');
if (exec) {
/* move everything following the last slash forward */
memmove (processName, exec+1, strlen (exec+1) + 1);
}
ret = snprintf(procName, procNameSize, "%s", processName);
os_free (processName);
return ret;
#else
return snprintf(procName, procNameSize, "bla%lu", (unsigned long)getpid());
#endif
}
#undef _OS_PROCESS_DEFAULT_NAME_LEN_

View file

@ -0,0 +1,327 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include <unistd.h>
#ifndef __VXWORKS__
#include <sys/fcntl.h>
#endif
#include "os/os.h"
os_socket
os_sockNew(
int domain,
int type)
{
return socket (domain, type, 0);
}
os_result
os_sockBind(
os_socket s,
const struct sockaddr *name,
uint32_t namelen)
{
os_result result = os_resultSuccess;
if (bind(s, (struct sockaddr *)name, (unsigned)namelen) == -1) {
result = os_resultFail;
}
return result;
}
os_result
os_sockGetsockname(
os_socket s,
const struct sockaddr *name,
uint32_t namelen)
{
os_result result = os_resultSuccess;
socklen_t len = namelen;
if (getsockname(s, (struct sockaddr *)name, &len) == -1) {
result = os_resultFail;
}
return result;
}
os_result
os_sockSendto(
os_socket s,
const void *msg,
size_t len,
const struct sockaddr *to,
size_t tolen,
size_t *bytesSent)
{
ssize_t res;
assert (tolen <= 0x7fffffff);
res = sendto(s, msg, len, 0, to, (socklen_t) tolen);
if (res < 0)
{
*bytesSent = 0;
return os_resultFail;
}
else
{
*bytesSent = (size_t) res;
return os_resultSuccess;
}
}
os_result
os_sockRecvfrom(
os_socket s,
void *buf,
size_t len,
struct sockaddr *from,
size_t *fromlen,
size_t *bytesRead)
{
ssize_t res;
socklen_t fl;
assert (*fromlen <= 0x7fffffff);
fl = (socklen_t) *fromlen;
res = recvfrom(s, buf, len, 0, from, &fl);
if (res < 0)
{
*bytesRead = 0;
return os_resultFail;
}
else
{
*fromlen=fl;
*bytesRead = (size_t)res;
return os_resultSuccess;
}
}
os_result
os_sockGetsockopt(
os_socket s,
int32_t level,
int32_t optname,
void *optval,
uint32_t *optlen)
{
int res;
socklen_t ol = *optlen;
res = getsockopt(s, level, optname, optval, &ol);
*optlen = ol;
return ( res == -1 ? os_resultFail : os_resultSuccess );
}
os_result
os_sockSetsockopt(
os_socket s,
int32_t level,
int32_t optname,
const void *optval,
uint32_t optlen)
{
os_result result = os_resultSuccess;
if (optname == SO_SNDBUF || optname == SO_RCVBUF)
{
if (optlen == 4 && *((unsigned *) optval) == 0)
{
/* We know this won't work */
return os_resultSuccess;
}
}
else if (optname == SO_DONTROUTE)
{
/* Enabling DONTROUTE gives nothing but grief on MacOS (e.g., no multicasting),
and I'm not aware of any serious use-case. */
return os_resultSuccess;
}
if (setsockopt(s, level, optname, optval, optlen) == -1) {
result = os_resultFail;
}
#ifdef __APPLE__
if (result == os_resultSuccess && level == SOL_SOCKET && optname == SO_REUSEADDR)
{
if (setsockopt(s, level, SO_REUSEPORT, optval, optlen) == -1)
{
result = os_resultFail;
}
}
#endif
return result;
}
os_result
os_sockSetNonBlocking(
os_socket s,
bool nonblock)
{
int oldflags;
os_result r;
assert(nonblock == false || nonblock == true);
oldflags = fcntl(s, F_GETFL, 0);
if(oldflags >= 0){
if (nonblock){
oldflags |= O_NONBLOCK;
} else {
oldflags &= ~O_NONBLOCK;
}
if(fcntl (s, F_SETFL, oldflags) == 0){
r = os_resultSuccess;
} else {
r = os_resultFail;
}
} else {
switch(os_getErrno()){
case EAGAIN:
r = os_resultBusy;
break;
case EBADF:
r = os_resultInvalid;
break;
default:
r = os_resultFail;
break;
}
}
return r;
}
os_result
os_sockFree(
os_socket s)
{
os_result result = os_resultSuccess;
if (close(s) == -1) {
result = os_resultFail;
}
return result;
}
int32_t
os_sockSelect(
int32_t nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *errorfds,
os_time *timeout)
{
struct timeval t;
int r;
t.tv_sec = timeout->tv_sec;
t.tv_usec = timeout->tv_nsec / 1000;
r = select(nfds, readfds, writefds, errorfds, &t);
return r;
}
_Check_return_
static os_result
os_queryInterfaceAttributesIPv4 (_In_ const struct ifaddrs *ifa, _Inout_ os_ifAttributes *ifElement)
{
os_result result = os_resultSuccess;
strncpy (ifElement->name, ifa->ifa_name, OS_IFNAMESIZE);
ifElement->name[OS_IFNAMESIZE - 1] = '\0';
memcpy (&ifElement->address, ifa->ifa_addr, sizeof (os_sockaddr_in));
ifElement->flags = ifa->ifa_flags;
if (ifElement->flags & IFF_BROADCAST)
memcpy (&ifElement->broadcast_address, ifa->ifa_broadaddr, sizeof (os_sockaddr_in));
else
memset (&ifElement->broadcast_address, 0, sizeof (ifElement->broadcast_address));
memcpy (&ifElement->network_mask, ifa->ifa_netmask, sizeof (os_sockaddr_in));
ifElement->interfaceIndexNo = (unsigned) if_nametoindex (ifa->ifa_name);
return result;
}
_Check_return_
static os_result
os_queryInterfaceAttributesIPv6 (_In_ const struct ifaddrs *ifa, _Inout_ os_ifAttributes *ifElement)
{
os_result result = os_resultSuccess;
strncpy (ifElement->name, ifa->ifa_name, OS_IFNAMESIZE);
ifElement->name[OS_IFNAMESIZE - 1] = '\0';
memcpy (&ifElement->address, ifa->ifa_addr, sizeof (os_sockaddr_in6));
ifElement->flags = ifa->ifa_flags;
memset (&ifElement->broadcast_address, 0, sizeof (ifElement->broadcast_address));
memset (&ifElement->network_mask, 0, sizeof (ifElement->network_mask));
ifElement->interfaceIndexNo = (unsigned) if_nametoindex (ifa->ifa_name);
return result;
}
os_result os_sockQueryInterfaces (os_ifAttributes *ifList, uint32_t listSize, uint32_t *validElements)
{
os_result result = os_resultSuccess;
unsigned int listIndex;
struct ifaddrs *ifa_first, *ifa;
if (getifaddrs (&ifa_first) != 0)
{
perror ("getifaddrs");
return os_resultFail;
}
listIndex = 0;
for (ifa = ifa_first; ifa && listIndex < listSize; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr && ((struct sockaddr_in *) ifa->ifa_addr)->sin_family == AF_INET)
{
/* Get other interface attributes */
result = os_queryInterfaceAttributesIPv4 (ifa, &ifList[listIndex]);
if (result == os_resultSuccess)
listIndex++;
}
if (result == os_resultSuccess)
*validElements = listIndex;
}
freeifaddrs (ifa_first);
return result;
}
os_result os_sockQueryIPv6Interfaces (os_ifAttributes *ifList, uint32_t listSize, uint32_t *validElements)
{
struct ifaddrs* interfaceList = NULL;
struct ifaddrs* nextInterface = NULL;
unsigned int listIndex = 0;
*validElements = 0;
if (getifaddrs (&interfaceList) != 0)
{
return os_resultFail;
}
nextInterface = interfaceList;
while (nextInterface != NULL && listIndex < listSize)
{
if (nextInterface->ifa_addr && nextInterface->ifa_addr->sa_family == AF_INET6)
{
os_sockaddr_in6 *v6Address = (os_sockaddr_in6 *) nextInterface->ifa_addr;
if (!IN6_IS_ADDR_UNSPECIFIED (&v6Address->sin6_addr))
{
os_result result = os_resultSuccess;
result = os_queryInterfaceAttributesIPv6 (nextInterface, &ifList[listIndex]);
if (result == os_resultSuccess)
listIndex++;
}
}
nextInterface = nextInterface->ifa_next;
}
*validElements = listIndex;
freeifaddrs(interfaceList);
return os_resultSuccess;
}

View file

@ -0,0 +1,22 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <unistd.h>
#include <sys/param.h>
#include "os/os.h"
#define OS_HAS_STRTOK_R 1
#include "../snippets/code/os_gethostname.c"
#include "../snippets/code/os_stdlib.c"
#include "../snippets/code/os_stdlib_bsearch.c"
#include "../snippets/code/os_stdlib_strtod.c"
#include "../snippets/code/os_stdlib_strtol.c"
#include "../snippets/code/os_stdlib_strtok_r.c"

View file

@ -0,0 +1,363 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include "os/os.h"
#if HAVE_LKST
#include "lkst.h"
#include "mach/mach_time.h"
extern int ospl_lkst_enabled;
#endif
static bool ospl_mtx_prio_inherit = false;
#if HAVE_LKST
int ospl_lkst_enabled;
#endif
#if defined __GLIBC_PREREQ
#if __GLIBC_PREREQ(2,5)
#define OSPL_PRIO_INHERIT_SUPPORTED
#endif
#endif
#if HAVE_LKST
static void random_delay(unsigned long long t)
{
unsigned z = (unsigned)((t * 16292676669999574021ull) >> 32);
struct timespec ts;
/* delay ~ 10% of the lock operations */
if ((z & 1023) < 900)
return;
/* delay by up to < 16ms */
ts.tv_sec = 0;
ts.tv_nsec = (z >> 10) & 16383;
(void) nanosleep (&ts, NULL);
}
#endif
void os_syncModuleInit(void)
{
#if HAVE_LKST
ospl_lkst_enabled = lkst_init (1);
#endif
ospl_mtx_prio_inherit = 0;
}
void os_syncModuleExit(void)
{
#if HAVE_LKST
if (ospl_lkst_enabled)
lkst_fini ();
#endif
}
os_result os_mutexSetPriorityInheritanceMode(bool enabled)
{
ospl_mtx_prio_inherit = enabled;
return os_resultSuccess;
}
void os_mutexInit (os_mutex *mutex)
{
int shared;
assert (mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert (mutex->signature != OS_MUTEX_MAGIC_SIG);
#endif
pthread_mutex_init (&mutex->mutex, NULL);
#if HAVE_LKST
if (ospl_lkst_enabled)
lkst_track_init (mutex, shared ? LKST_MF_SHARED : 0);
#else
(void)shared;
#endif
#ifdef OSPL_STRICT_MEM
mutex->signature = OS_MUTEX_MAGIC_SIG;
#endif
}
void os_mutexDestroy (os_mutex *mutex)
{
assert (mutex != NULL);
#if HAVE_LKST
if (ospl_lkst_enabled)
lkst_track_destroy (mutex);
#endif
#ifdef OSPL_STRICT_MEM
assert(mutex->signature == OS_MUTEX_MAGIC_SIG);
#endif
if (pthread_mutex_destroy (&mutex->mutex) != 0)
abort();
#ifdef OSPL_STRICT_MEM
mutex->signature = 0;
#endif
}
void os_mutexLock (os_mutex *mutex)
{
assert (mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert(mutex->signature == OS_MUTEX_MAGIC_SIG);
#endif
#if HAVE_LKST
if (!ospl_lkst_enabled)
#endif
{
if (pthread_mutex_lock (&mutex->mutex) != 0)
abort();
}
#if HAVE_LKST
else
{
unsigned long long t = mach_absolute_time (), dt;
if (ospl_lkst_enabled > 1)
random_delay (t);
if (pthread_mutex_trylock (&mutex->mutex) == 0)
dt = 0;
else
{
if (pthread_mutex_lock (&mutex->mutex) != 0)
abort();
dt = 1 | (mach_absolute_time () - t);
}
lkst_track_op (mutex, LKST_LOCK, t, dt);
}
#endif
}
os_result os_mutexLock_s (os_mutex *mutex)
{
int result;
assert (mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert(mutex->signature == OS_MUTEX_MAGIC_SIG);
#endif
#if HAVE_LKST
if (!ospl_lkst_enabled)
#endif
{
result = pthread_mutex_lock (&mutex->mutex);
}
#if HAVE_LKST
else
{
unsigned long long t = mach_absolute_time (), dt;
if (ospl_lkst_enabled > 1)
random_delay (t);
if ((result = pthread_mutex_trylock (&mutex->mutex)) == 0)
dt = 0;
else
{
result = pthread_mutex_lock (&mutex->mutex);
dt = 1 | (mach_absolute_time () - t);
}
lkst_track_op (mutex, LKST_LOCK, t, dt);
}
#endif
return (result == 0) ? os_resultSuccess : os_resultFail;
}
os_result os_mutexTryLock (os_mutex *mutex)
{
int result;
assert (mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert(mutex->signature == OS_MUTEX_MAGIC_SIG);
#endif
result = pthread_mutex_trylock (&mutex->mutex);
if (result != 0 && result != EBUSY)
abort();
#if HAVE_LKST
if (result == 0 && ospl_lkst_enabled)
lkst_track_op (mutex, LKST_LOCK, mach_absolute_time (), 0);
#endif
return (result == 0) ? os_resultSuccess : os_resultBusy;
}
void os_mutexUnlock (os_mutex *mutex)
{
assert (mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert(mutex->signature == OS_MUTEX_MAGIC_SIG);
#endif
#if HAVE_LKST
if (ospl_lkst_enabled)
lkst_track_op (mutex, LKST_UNLOCK, mach_absolute_time (), 0);
#endif
if (pthread_mutex_unlock (&mutex->mutex) != 0)
abort();
}
void os_condInit (os_cond *cond, os_mutex *dummymtx __attribute__ ((unused)))
{
assert (cond != NULL);
#ifdef OSPL_STRICT_MEM
assert(cond->signature != OS_COND_MAGIC_SIG);
#endif
pthread_cond_init (&cond->cond, NULL);
#ifdef OSPL_STRICT_MEM
cond->signature = OS_COND_MAGIC_SIG;
#endif
}
void os_condDestroy (os_cond *cond)
{
assert (cond != NULL);
#ifdef OSPL_STRICT_MEM
assert(cond->signature == OS_COND_MAGIC_SIG);
#endif
if (pthread_cond_destroy (&cond->cond) != 0)
abort();
#ifdef OSPL_STRICT_MEM
cond->signature = 0;
#endif
}
void os_condWait (os_cond *cond, os_mutex *mutex)
{
assert (cond != NULL);
assert (mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert( cond->signature == OS_COND_MAGIC_SIG );
assert( mutex->signature == OS_MUTEX_MAGIC_SIG );
#endif
#if HAVE_LKST
if (ospl_lkst_enabled)
lkst_track_op (mutex, LKST_UNLOCK, mach_absolute_time (), 0);
#endif
if (pthread_cond_wait (&cond->cond, &mutex->mutex) != 0)
abort();
#if HAVE_LKST
/* Have no way of determining whether it was uncontended or not, and
if not, how long the wait was. */
if (ospl_lkst_enabled)
lkst_track_op (mutex, LKST_LOCK, mach_absolute_time (), 0);
#endif
}
os_result os_condTimedWait (os_cond *cond, os_mutex *mutex, const os_time *time)
{
struct timespec t;
int result;
os_time wakeup_time;
struct timeval tv;
os_time rt;
assert (cond != NULL);
assert (mutex != NULL);
assert (time != NULL);
#ifdef OSPL_STRICT_MEM
assert( cond->signature == OS_COND_MAGIC_SIG );
assert( mutex->signature == OS_MUTEX_MAGIC_SIG );
#endif
(void) gettimeofday (&tv, NULL);
rt.tv_sec = (os_timeSec) tv.tv_sec;
rt.tv_nsec = tv.tv_usec*1000;
wakeup_time = os_timeAdd (rt, *time);
t.tv_sec = wakeup_time.tv_sec;
t.tv_nsec = wakeup_time.tv_nsec;
#if HAVE_LKST
if (ospl_lkst_enabled)
lkst_track_op (mutex, LKST_UNLOCK, mach_absolute_time (), 0);
#endif
/* By default Darwin uses the realtime clock in pthread_cond_timedwait().
* Unfortunately Darwin has not (yet) implemented
* pthread_condattr_setclock(), so we cannot tell it to use the
* the monotonic clock. */
result = pthread_cond_timedwait (&cond->cond, &mutex->mutex, &t);
if (result != 0 && result != ETIMEDOUT)
abort();
#if HAVE_LKST
/* Have no way of determining whether it was uncontended or not, and
if not, how long the wait was. */
if (ospl_lkst_enabled)
lkst_track_op (mutex, LKST_LOCK, mach_absolute_time (), 0);
#endif
return (result == ETIMEDOUT) ? os_resultTimeout : os_resultSuccess;
}
void os_condSignal (os_cond *cond)
{
assert (cond != NULL);
#ifdef OSPL_STRICT_MEM
assert( cond->signature == OS_COND_MAGIC_SIG );
#endif
if (pthread_cond_signal (&cond->cond) != 0)
abort();
}
void os_condBroadcast (os_cond *cond)
{
assert (cond != NULL);
#ifdef OSPL_STRICT_MEM
assert( cond->signature == OS_COND_MAGIC_SIG );
#endif
if (pthread_cond_broadcast (&cond->cond) != 0)
abort();
}
void os_rwlockInit (os_rwlock *rwlock)
{
os_mutexInit (&rwlock->mutex);
}
void os_rwlockDestroy (os_rwlock *rwlock)
{
assert (rwlock != NULL);
os_mutexDestroy (&rwlock->mutex);
}
void os_rwlockRead (os_rwlock *rwlock)
{
os_mutexLock (&rwlock->mutex);
}
void os_rwlockWrite (os_rwlock *rwlock)
{
os_mutexLock (&rwlock->mutex);
}
os_result os_rwlockTryRead (os_rwlock *rwlock)
{
return os_mutexTryLock (&rwlock->mutex);
}
os_result os_rwlockTryWrite (os_rwlock *rwlock)
{
return os_mutexTryLock (&rwlock->mutex);
}
void os_rwlockUnlock (os_rwlock *rwlock)
{
os_mutexUnlock (&rwlock->mutex);
}
void
os_once(
_Inout_ os_once_t *control,
_In_ os_once_fn init_fn)
{
/* There are no defined errors that can be returned by pthread_once */
(void)pthread_once(control, init_fn);
}

View file

@ -0,0 +1,12 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "../snippets/code/os_posix_thread.c"

View file

@ -0,0 +1,149 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file os/darwin/code/os_time.c
* \brief Darwin time management
*
* Implements time management for Darwin
*/
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
#include "os/os.h"
#ifndef __APPLE__
os_time os__timeDefaultTimeGet(void)
{
static int timeshift = INT_MAX;
struct timespec t;
os_time rt;
if(timeshift == INT_MAX) {
const char *p = getenv("OSPL_TIMESHIFT");
timeshift = (p == NULL) ? 0 : atoi(p);
}
(void) clock_gettime (CLOCK_REALTIME, &t);
rt.tv_sec = (os_timeSec) t.tv_sec + timeshift;
rt.tv_nsec = t.tv_nsec;
return rt;
}
os_time os_timeGetMonotonic (void)
{
struct timespec t;
os_time rt;
(void) clock_gettime (CLOCK_MONOTONIC, &t);
rt.tv_sec = (os_timeSec) t.tv_sec;
rt.tv_nsec = t.tv_nsec;
return rt;
}
os_time os_timeGetElapsed (void)
{
/* Elapsed time clock not worth the bother for now. */
return os_timeGetMonotonic();
}
#else /* MacOS */
#include <mach/mach_time.h>
os_time os__timeDefaultTimeGet(void)
{
static int timeshift = INT_MAX;
struct timeval tv;
os_time rt;
if(timeshift == INT_MAX) {
const char *p = getenv("OSPL_TIMESHIFT");
timeshift = (p == NULL) ? 0 : atoi(p);
}
(void) gettimeofday (&tv, NULL);
rt.tv_sec = (os_timeSec) tv.tv_sec + timeshift;
rt.tv_nsec = tv.tv_usec*1000;
return rt;
}
os_time os_timeGetMonotonic (void)
{
static mach_timebase_info_data_t timeInfo;
os_time t;
uint64_t mt;
uint64_t mtNano;
/* The Mach absolute time returned by mach_absolute_time is very similar to
* the QueryPerformanceCounter on Windows. The update-rate isn't fixed, so
* that information needs to be resolved to provide a clock with real-time
* progression.
*
* The mach_absolute_time does include time spent during sleep (on Intel
* CPU's, not on PPC), but not the time spent during suspend.
*
* The result is not adjusted based on NTP, so long-term progression by this
* clock may not match the time progression made by the real-time clock. */
mt = mach_absolute_time();
if( timeInfo.denom == 0) {
(void) mach_timebase_info(&timeInfo);
}
mtNano = mt * timeInfo.numer / timeInfo.denom;
t.tv_sec = (os_timeSec) (mtNano / 1000000000);
t.tv_nsec = (int32_t) (mtNano % 1000000000);
return t;
}
os_time os_timeGetElapsed (void)
{
/* Elapsed time clock not (yet) supported on this platform. */
return os_timeGetMonotonic();
}
#endif
os_result os_nanoSleep (os_time delay)
{
struct timespec t;
struct timespec r;
int result;
os_result rv;
if( delay.tv_sec >= 0 && delay.tv_nsec >= 0) {
/* Time should be normalized */
assert (delay.tv_nsec < 1000000000);
t.tv_sec = delay.tv_sec;
t.tv_nsec = delay.tv_nsec;
result = nanosleep (&t, &r);
while (result && os_getErrno() == EINTR) {
t = r;
result = nanosleep (&t, &r);
}
if (result == 0) {
rv = os_resultSuccess;
} else {
rv = os_resultFail;
}
} else {
rv = os_resultFail;
}
return rv;
}

View file

@ -0,0 +1,34 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <string.h>
os_result
os_gethostname(
char *hostname,
size_t buffersize)
{
os_result result;
char hostnamebuf[MAXHOSTNAMELEN];
if (gethostname (hostnamebuf, MAXHOSTNAMELEN) == 0) {
if ((strlen(hostnamebuf)+1) > buffersize) {
result = os_resultFail;
} else {
strncpy (hostname, hostnamebuf, buffersize);
result = os_resultSuccess;
}
} else {
result = os_resultFail;
}
return result;
}

View file

@ -0,0 +1,143 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file os/common/code/os_heap.c
* \brief Heap memory management service
*
* Implements functions for allocation and freeing
* memory from and to heap respectively.
*/
#include "os/os.h"
/** \brief Allocate memory from heap
*
*/
_Check_return_
_Ret_opt_bytecap_(size)
void *
os_malloc_s(
_In_ size_t size)
{
return malloc(size ? size : 1); /* Allocate memory even if size == 0 */
}
_Check_return_
_Ret_bytecap_(size)
void *
os_malloc(
_In_ size_t size)
{
void *ptr = os_malloc_s(size);
if(ptr == NULL) {
/* Heap exhausted */
abort();
}
return ptr;
}
_Check_return_
_Ret_bytecount_(size)
void *
os_malloc_0(_In_ size_t size)
{
return os_calloc(size, 1);
}
_Check_return_
_Ret_opt_bytecount_(size)
void *
os_malloc_0_s(_In_ size_t size)
{
return os_calloc_s(size, 1);
}
_Check_return_
_Ret_bytecount_(count * size)
void *
os_calloc(
_In_ size_t count,
_In_ size_t size)
{
char *ptr;
ptr = os_calloc_s(count, size);
if(ptr == NULL) {
/* Heap exhausted */
abort();
}
return ptr;
}
_Check_return_
_Ret_opt_bytecount_(count * size)
void *
os_calloc_s(
_In_ size_t count,
_In_ size_t size)
{
if(count == 0 || size == 0) {
count = size = 1;
}
return calloc(count, size);
}
_Check_return_
_Ret_bytecap_(size)
void *
os_realloc(
_Pre_maybenull_ _Post_ptr_invalid_ void *memblk,
_In_ size_t size)
{
void *ptr;
ptr = os_realloc_s(memblk, size);
if(ptr == NULL){
/* Heap exhausted */
abort();
}
return ptr;
}
_Success_(return != NULL)
_Check_return_
_Ret_opt_bytecap_(size)
void *
os_realloc_s(
_Pre_maybenull_ _Post_ptr_invalid_ void *memblk,
_In_ size_t size)
{
/* Even though newmem = realloc(mem, 0) is equivalent to calling free(mem), not all platforms
* will return newmem == NULL. We consistently do, so the result of a non-failing os_realloc_s
* always needs to be free'd, like os_malloc_s(0). */
return realloc(memblk, size ? size : 1);
}
/** \brief Free memory to heap
*
* \b os_free calls \b free which is a function pointer
* which defaults to \b free, but can be redefined via
* \b os_heapSetService.
*/
void
os_free (
_Pre_maybenull_ _Post_ptr_invalid_ void *ptr)
{
if (ptr) {
free (ptr);
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/* Make sure we get the XSI compliant version of strerror_r */
#undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE
#undef _GNU_SOURCE
#define _POSIX_C_SOURCE 200112L
#include <string.h>
#include <assert.h>
#include "os/os.h"
int
os_getErrno (void)
{
return errno;
}
void
os_setErrno (int err)
{
errno = err;
}
int
os_strerror_r (int err, char *str, size_t len)
{
int res;
assert(str != NULL);
assert(len > 0);
str[0] = '\0'; /* null-terminate in case nothing is written */
res = strerror_r(err, str, len);
str[len - 1] = '\0'; /* always null-terminate, just to be safe */
return res;
}

View file

@ -0,0 +1,120 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file os/posix/code/os_process.c
* \brief Posix process management
*
* Implements process management for POSIX
*/
#include "os/os.h"
#include <sys/types.h>
#ifndef OSPL_NO_VMEM
#include <sys/mman.h>
#endif
#ifndef PIKEOS_POSIX
#include <sys/wait.h>
#endif
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sched.h>
#ifndef INTEGRITY
#include <signal.h>
#endif
#include <stdio.h>
#include <pthread.h>
static os_atomic_voidp_t os_procname = OS_ATOMIC_VOIDP_INIT(0);
/** \brief pointer to environment variables */
#ifdef __APPLE__
//not available on iOS, but also not currently used
//#include <crt_externs.h>
#else
extern char **environ;
#endif
/* protected functions */
void
os_processModuleInit(void)
{
return;
}
void
os_processModuleExit(void)
{
void *pname;
do {
pname = os_atomic_ldvoidp(&os_procname);
} while (!os_atomic_casvoidp(&os_procname, pname, NULL));
os_free(pname);
}
/* public functions */
/** \brief Return the process ID of the calling process
*
* Possible Results:
* - returns the process ID of the calling process
*/
os_procId
os_procIdSelf(void)
{
return getpid();
}
/* _OS_PROCESS_DEFAULT_CMDLINE_LEN_ is defined as
* strlen("/proc/<max_pid>/cmdline" + 1, max_pid = 32768 on Linux, so a reason-
* able default is 20 */
#define _OS_PROCESS_DEFAULT_CMDLINE_LEN_ (20)
#define _OS_PROCESS_PROCFS_PATH_FMT_ "/proc/%d/cmdline"
#define _OS_PROCESS_DEFAULT_NAME_LEN_ (512)
/** \brief Figure out the identity of the current process
*
* os_procNamePid determines the numeric, and if possible named
* identity of a process. It will first check if the environment variable
* SPLICE_PROCNAME is set (which is always the case if the process is started
* via os_procCreate). If so, that value will be returned. Otherwise it will be
* attempted to determine the commandline which started the process through the
* procfs. If that fails, the PID will be returned.
*
* \param procIdentity Pointer to a char-buffer to which the result can be
* written. If a name could be resolved, the result will
* have the format "name <PID>". Otherwise it will just
* be "<PID>".
* \param procIdentitySize Size of the buffer pointed to by procIdentitySize
* \return same as snprintf returns
*/
int
os_procNamePid(
char *procIdentity,
size_t procIdentitySize)
{
int size;
char process_name[_OS_PROCESS_DEFAULT_NAME_LEN_];
size = os_procName(process_name, _OS_PROCESS_DEFAULT_NAME_LEN_);
if (size > 0) {
size = snprintf(procIdentity, procIdentitySize, "%s <%"PRIprocId">", (char *)os_atomic_ldvoidp(&os_procname), os_procIdSelf());
} else {
/* No processname could be determined, so default to PID */
size = snprintf(procIdentity, procIdentitySize, "<%"PRIprocId">", os_procIdSelf());
}
return size;
}
#undef _OS_PROCESS_DEFAULT_CMDLINE_LEN_
#undef _OS_PROCESS_PROCFS_PATH_FMT_
#undef _OS_PROCESS_DEFAULT_NAME_LEN_

View file

@ -0,0 +1,688 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file os/posix/code/os_thread.c
* \brief Posix thread management
*
* Implements thread management for POSIX
*/
#include "os/os.h"
#include <sys/types.h>
#include <pthread.h>
#include <assert.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
/* TODO: should introduce a HAVE_PRCTL define rather than blacklisting some platforms */
#if !defined __VXWORKS__ && !defined __APPLE__
#include <sys/prctl.h>
#endif
#include <limits.h>
typedef struct {
char *threadName;
void *arguments;
uint32_t (*startRoutine)(void *);
} os_threadContext;
static pthread_key_t os_threadNameKey;
static pthread_key_t os_threadMemKey;
static sigset_t os_threadBlockAllMask;
/** \brief Initialize the thread private memory array
*
* \b os_threadMemInit initializes the thread private memory array
* for the calling thread
*
* pre condition:
* os_threadMemKey is initialized
*
* post condition:
* pthreadMemArray is initialized
* or
* an appropriate error report is generated
*/
static void
os_threadMemInit (
void)
{
void *pthreadMemArray;
pthreadMemArray = os_malloc (sizeof(void *) * OS_THREAD_MEM_ARRAY_SIZE);
if (pthreadMemArray != NULL) {
memset (pthreadMemArray, 0, sizeof(void *) * OS_THREAD_MEM_ARRAY_SIZE);
if (pthread_setspecific (os_threadMemKey, pthreadMemArray) == EINVAL) {
OS_ERROR("os_threadMemInit", 4,
"pthread_setspecific failed with error EINVAL (%d), "
"invalid threadMemKey value", EINVAL);
os_free(pthreadMemArray);
}
} else {
OS_ERROR("os_threadMemInit", 3, "Out of heap memory");
}
}
/** \brief Initialize the thread private memory array
*
* \b os_threadMemInit releases the thread private memory array
* for the calling thread, the allocated private memory areas
* referenced by the array are also freed.
*
* pre condition:
* os_threadMemKey is initialized
*
* post condition:
* pthreadMemArray is released
* or
* an appropriate error report is generated
*/
static void
os_threadMemExit(
void)
{
void **pthreadMemArray;
int32_t i;
pthreadMemArray = pthread_getspecific (os_threadMemKey);
if (pthreadMemArray != NULL) {
for (i = 0; i < OS_THREAD_MEM_ARRAY_SIZE; i++) {
if (pthreadMemArray[i] != NULL) {
os_free (pthreadMemArray[i]);
}
}
os_free (pthreadMemArray);
pthreadMemArray = NULL;
if (pthread_setspecific (os_threadMemKey, pthreadMemArray) == EINVAL) {
OS_ERROR("os_threadMemExit", 4, "pthread_setspecific failed with error %d", EINVAL);
}
}
}
/** \brief Initialize the thread module
*
* \b os_threadModuleInit initializes the thread module for the
* calling process
*/
void
os_threadModuleInit (
void)
{
pthread_key_create (&os_threadNameKey, NULL);
pthread_key_create (&os_threadMemKey, NULL);
sigfillset(&os_threadBlockAllMask);
os_threadMemInit();
}
/** \brief Deinitialize the thread module
*
* \b os_threadModuleExit deinitializes the thread module for the
* calling process
*/
void
os_threadModuleExit(void)
{
os_threadMemExit();
pthread_key_delete(os_threadNameKey);
pthread_key_delete(os_threadMemKey);
}
/** \brief Wrap thread start routine
*
* \b os_startRoutineWrapper wraps a threads starting routine.
* before calling the user routine, it sets the threads name
* in the context of the thread. With \b pthread_getspecific,
* the name can be retreived for different purposes.
*/
static void *
os_startRoutineWrapper (
void *threadContext)
{
os_threadContext *context = threadContext;
uintptr_t resultValue;
os_threadId id;
resultValue = 0;
#if !defined(__VXWORKS__) && !defined(__APPLE__)
prctl(PR_SET_NAME, context->threadName);
#endif
/* store the thread name with the thread via thread specific data; failure isn't */
if (pthread_setspecific (os_threadNameKey, context->threadName) == EINVAL) {
OS_WARNING("os_startRoutineWrapper", 0,
"pthread_setspecific failed with error EINVAL (%d), "
"invalid os_threadNameKey value", EINVAL);
}
/* allocate an array to store thread private memory references */
os_threadMemInit ();
id.v = pthread_self();
/* Call the user routine */
resultValue = context->startRoutine (context->arguments);
os_report_stack_free();
/* Free the thread context resources, arguments is responsibility */
/* for the caller of os_procCreate */
os_free (context->threadName);
os_free (context);
/* deallocate the array to store thread private memory references */
os_threadMemExit ();
/* return the result of the user routine */
return (void *)resultValue;
}
/** \brief Create a new thread
*
* \b os_threadCreate creates a thread by calling \b pthread_create.
* But first it processes all thread attributes in \b threadAttr and
* sets the scheduling properties with \b pthread_attr_setscope
* to create a bounded thread, \b pthread_attr_setschedpolicy to
* set the scheduling class and \b pthread_attr_setschedparam to
* set the scheduling priority.
* \b pthread_attr_setdetachstate is called with parameter
* \PTHREAD_CREATE_JOINABLE to make the thread joinable, which
* is needed to be able to wait for the threads termination
* in \b os_threadWaitExit.
*/
os_result
os_threadCreate (
os_threadId *threadId,
const char *name,
const os_threadAttr *threadAttr,
uint32_t (* start_routine)(void *),
void *arg)
{
pthread_attr_t attr;
struct sched_param sched_param;
os_result rv = os_resultSuccess;
os_threadContext *threadContext;
os_threadAttr tattr;
int result, create_ret;
int policy;
assert (threadId != NULL);
assert (name != NULL);
assert (threadAttr != NULL);
assert (start_routine != NULL);
tattr = *threadAttr;
if (tattr.schedClass == OS_SCHED_DEFAULT) {
#if 0 /* FIXME! */
tattr.schedClass = os_procAttrGetClass ();
tattr.schedPriority = os_procAttrGetPriority ();
#endif
}
if (pthread_attr_init (&attr) != 0)
{
rv = os_resultFail;
}
else
{
#ifdef __VXWORKS__
/* PR_SET_NAME is not available on VxWorks. Use pthread_attr_setname
instead (proprietary VxWorks extension) */
(void)pthread_attr_setname(&attr, name);
#endif
if (pthread_getschedparam(pthread_self(), &policy, &sched_param) != 0 ||
#if !defined (OS_RTEMS_DEFS_H) && !defined (PIKEOS_POSIX)
pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM) != 0 ||
#endif
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE) != 0 ||
pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED) != 0)
{
rv = os_resultFail;
}
else
{
if (tattr.stackSize != 0) {
#ifdef PTHREAD_STACK_MIN
if ( tattr.stackSize < PTHREAD_STACK_MIN ) {
tattr.stackSize = PTHREAD_STACK_MIN;
}
#endif
#ifdef OSPL_STACK_MAX
if ( tattr.stackSize > OSPL_STACK_MAX ) {
tattr.stackSize = OSPL_STACK_MAX;
}
#endif
if (pthread_attr_setstacksize (&attr, tattr.stackSize) != 0) {
rv = os_resultFail;
}
}
}
if (rv == os_resultSuccess) {
if (tattr.schedClass == OS_SCHED_REALTIME) {
result = pthread_attr_setschedpolicy (&attr, SCHED_FIFO);
if (result != 0) {
char errmsg[64];
(void)os_strerror_r(result, errmsg, sizeof(errmsg));
OS_WARNING("os_threadCreate", 2,
"pthread_attr_setschedpolicy failed for SCHED_FIFO with "\
"error %d (%s) for thread '%s', reverting to SCHED_OTHER.",
result, errmsg, name);
result = pthread_attr_setschedpolicy (&attr, SCHED_OTHER);
if (result != 0) {
OS_WARNING("os_threadCreate", 2, "pthread_attr_setschedpolicy failed with error %d (%s)", result, name);
}
}
} else {
result = pthread_attr_setschedpolicy (&attr, SCHED_OTHER);
if (result != 0) {
OS_WARNING("os_threadCreate", 2,
"pthread_attr_setschedpolicy failed with error %d (%s)",
result, name);
}
}
pthread_attr_getschedpolicy(&attr, &policy);
if ((tattr.schedPriority < sched_get_priority_min(policy)) ||
(tattr.schedPriority > sched_get_priority_max(policy))) {
OS_WARNING("os_threadCreate", 2,
"scheduling priority outside valid range for the policy "\
"reverted to valid value (%s)", name);
sched_param.sched_priority = (sched_get_priority_min(policy) +
sched_get_priority_max(policy)) / 2;
} else {
sched_param.sched_priority = tattr.schedPriority;
}
/* Take over the thread context: name, start routine and argument */
threadContext = os_malloc (sizeof (os_threadContext));
threadContext->threadName = os_malloc (strlen (name)+1);
strncpy (threadContext->threadName, name, strlen (name)+1);
threadContext->startRoutine = start_routine;
threadContext->arguments = arg;
/* start the thread */
result = pthread_attr_setschedparam (&attr, &sched_param);
if (result != 0) {
OS_WARNING("os_threadCreate", 2,
"pthread_attr_setschedparam failed with error %d (%s)",
result, name);
}
create_ret = pthread_create(&threadId->v, &attr, os_startRoutineWrapper,
threadContext);
if (create_ret != 0) {
/* In case real-time thread creation failed due to a lack
* of permissions, try reverting to time-sharing and continue.
*/
if((create_ret == EPERM) && (tattr.schedClass == OS_SCHED_REALTIME))
{
OS_WARNING("os_threadCreate", 2,
"pthread_create failed with SCHED_FIFO " \
"for thread '%s', reverting to SCHED_OTHER.",
name);
(void) pthread_attr_setschedpolicy (&attr, SCHED_OTHER); /* SCHED_OTHER is always supported */
pthread_attr_getschedpolicy(&attr, &policy);
if ((tattr.schedPriority < sched_get_priority_min(policy)) ||
(tattr.schedPriority > sched_get_priority_max(policy)))
{
OS_WARNING("os_threadCreate", 2,
"scheduling priority outside valid range for the " \
"policy reverted to valid value (%s)", name);
sched_param.sched_priority =
(sched_get_priority_min(policy) +
sched_get_priority_max(policy)) / 2;
} else {
sched_param.sched_priority = tattr.schedPriority;
}
result = pthread_attr_setschedparam (&attr, &sched_param);
if (result != 0) {
OS_WARNING("os_threadCreate", 2,
"pthread_attr_setschedparam failed " \
"with error %d (%s)", result, name);
} else {
create_ret = pthread_create(&threadId->v, &attr,
os_startRoutineWrapper, threadContext);
}
}
} else {
rv = os_resultSuccess;
}
if(create_ret != 0){
os_free (threadContext->threadName);
os_free (threadContext);
OS_WARNING("os_threadCreate", 2, "pthread_create failed with error %d (%s)", create_ret, name);
rv = os_resultFail;
}
}
pthread_attr_destroy (&attr);
}
return rv;
}
/** \brief Return the integer representation of the given thread ID
*
* Possible Results:
* - returns the integer representation of the given thread ID
*/
uintmax_t
os_threadIdToInteger(os_threadId id)
{
return (uintmax_t)(uintptr_t)id.v;
}
/** \brief Return the thread ID of the calling thread
*
* \b os_threadIdSelf determines the own thread ID by
* calling \b pthread_self.
*/
os_threadId
os_threadIdSelf (void)
{
os_threadId id = {.v = pthread_self ()};
return id;
}
/** \brief Figure out the identity of the current thread
*
* \b os_threadFigureIdentity determines the numeric identity
* of a thread. POSIX does not identify threads by name,
* therefore only the numeric identification is returned,
*/
int32_t
os_threadFigureIdentity (
char *threadIdentity,
uint32_t threadIdentitySize)
{
int size;
char *threadName;
threadName = pthread_getspecific (os_threadNameKey);
if (threadName != NULL) {
size = snprintf (threadIdentity, threadIdentitySize, "%s 0x%"PRIxMAX, threadName, (uintmax_t)pthread_self ());
} else {
size = snprintf (threadIdentity, threadIdentitySize, "0x%"PRIxMAX, (uintmax_t)pthread_self ());
}
return size;
}
int32_t
os_threadGetThreadName (
char *buffer,
uint32_t length)
{
char *name;
assert (buffer != NULL);
if ((name = pthread_getspecific (os_threadNameKey)) == NULL) {
name = "";
}
return snprintf (buffer, length, "%s", name);
}
/** \brief Wait for the termination of the identified thread
*
* \b os_threadWaitExit wait for the termination of the
* thread \b threadId by calling \b pthread_join. The return
* value of the thread is passed via \b thread_result.
*/
os_result
os_threadWaitExit (
os_threadId threadId,
uint32_t *thread_result)
{
os_result rv;
int result;
void *vthread_result;
assert (threadId.v);
#if defined(__VXWORKS__) && !defined(_WRS_KERNEL)
struct sched_param sched_param;
int max, policy = 0;
/* There is a known issue in pthread_join on VxWorks 6.x RTP mode.
WindRiver: When pthread_join returns, it does not indicate end of a
thread in 100% of the situations. If the thread that calls pthread_join
has a higher priority than the thread that is currently terminating,
pthread_join could return before pthread_exit has finished. This
conflicts with the POSIX specification that dictates that pthread_join
must only return when the thread is really terminated. The workaround
suggested by WindRiver support is to increase the priority of the thread
(task) to be terminated before handing back the semaphore to ensure the
thread exits before pthread_join returns.
This bug was submitted to WindRiver as TSR 815826. */
/* Note that any possible errors raised here are not terminal since the
thread may have exited at this point anyway. */
if (pthread_getschedparam(threadId.v, &policy, &sched_param) == 0) {
max = sched_get_priority_max(policy);
if (max != -1) {
(void)pthread_setschedprio(threadId.v, max);
}
}
#endif
result = pthread_join (threadId.v, &vthread_result);
if (result != 0) {
/* NOTE: The below report actually is a debug output; makes no sense from
* a customer perspective. Made OS_INFO for now. */
OS_INFO("os_threadWaitExit", 2, "pthread_join(0x%"PRIxMAX") failed with error %d", os_threadIdToInteger(threadId), result);
rv = os_resultFail;
} else {
rv = os_resultSuccess;
}
if(thread_result){
uintptr_t res = (uintptr_t)vthread_result;
*thread_result = (uint32_t)res;
}
return rv;
}
/** \brief Allocate thread private memory
*
* Allocate heap memory of the specified \b size and
* relate it to the thread by storing the memory
* reference in an thread specific reference array
* indexed by \b index. If the indexed thread reference
* array location already contains a reference, no
* memory will be allocated and NULL is returned.
*
* Possible Results:
* - returns NULL if
* index < 0 || index >= OS_THREAD_MEM_ARRAY_SIZE
* - returns NULL if
* no sufficient memory is available on heap
* - returns NULL if
* os_threadMemGet (index) returns != NULL
* - returns reference to allocated heap memory
* of the requested size if
* memory is successfully allocated
*/
void *
os_threadMemMalloc (
int32_t index,
size_t size)
{
void **pthreadMemArray;
void *threadMemLoc = NULL;
if ((0 <= index) && (index < OS_THREAD_MEM_ARRAY_SIZE)) {
pthreadMemArray = pthread_getspecific (os_threadMemKey);
if (pthreadMemArray == NULL) {
os_threadMemInit ();
pthreadMemArray = pthread_getspecific (os_threadMemKey);
}
if (pthreadMemArray != NULL) {
if (pthreadMemArray[index] == NULL) {
threadMemLoc = os_malloc (size);
if (threadMemLoc != NULL) {
pthreadMemArray[index] = threadMemLoc;
}
}
}
}
return threadMemLoc;
}
/** \brief Free thread private memory
*
* Free the memory referenced by the thread reference
* array indexed location. If this reference is NULL,
* no action is taken. The reference is set to NULL
* after freeing the heap memory.
*
* Postcondition:
* - os_threadMemGet (index) = NULL and allocated
* heap memory is freed
*/
void
os_threadMemFree (
int32_t index)
{
void **pthreadMemArray;
void *threadMemLoc = NULL;
if ((0 <= index) && (index < OS_THREAD_MEM_ARRAY_SIZE)) {
pthreadMemArray = pthread_getspecific (os_threadMemKey);
if (pthreadMemArray != NULL) {
threadMemLoc = pthreadMemArray[index];
if (threadMemLoc != NULL) {
pthreadMemArray[index] = NULL;
os_free (threadMemLoc);
}
}
}
}
/** \brief Get thread private memory
*
* Possible Results:
* - returns NULL if
* 0 < index <= OS_THREAD_MEM_ARRAY_SIZE
* - returns NULL if
* No heap memory is related to the thread for
* the specified index
* - returns a reference to the allocated memory
*/
void *
os_threadMemGet (
int32_t index)
{
void **pthreadMemArray;
void *threadMemLoc = NULL;
if ((0 <= index) && (index < OS_THREAD_MEM_ARRAY_SIZE)) {
pthreadMemArray = pthread_getspecific (os_threadMemKey);
if (pthreadMemArray != NULL) {
threadMemLoc = pthreadMemArray[index];
}
}
return threadMemLoc;
}
static pthread_key_t cleanup_key;
static pthread_once_t cleanup_once = PTHREAD_ONCE_INIT;
static void
os_threadCleanupFini(
void *data)
{
os_iter *itr;
os_threadCleanup *obj;
if (data != NULL) {
itr = (os_iter *)data;
for (obj = (os_threadCleanup *)os_iterTake(itr, -1);
obj != NULL;
obj = (os_threadCleanup *)os_iterTake(itr, -1))
{
assert(obj->func != NULL);
obj->func(obj->data);
os_free(obj);
}
os_iterFree(itr, NULL);
}
}
static void
os_threadCleanupInit(
void)
{
(void)pthread_key_create(&cleanup_key, &os_threadCleanupFini);
}
/* os_threadCleanupPush and os_threadCleanupPop are mapped onto a destructor
registered with pthread_key_create in stead of being mapped directly onto
pthread_cleanup_push/pthread_cleanup_pop because the cleanup routines could
otherwise be popped of the stack by the user */
void
os_threadCleanupPush(
void (*func)(void*),
void *data)
{
os_iter *itr;
os_threadCleanup *obj;
assert(func != NULL);
(void)pthread_once(&cleanup_once, &os_threadCleanupInit);
itr = (os_iter *)pthread_getspecific(cleanup_key);
if (itr == NULL) {
itr = os_iterNew();
assert(itr != NULL);
if (pthread_setspecific(cleanup_key, itr) == EINVAL) {
OS_WARNING(OS_FUNCTION, 0, "pthread_setspecific failed with error EINVAL (%d)", EINVAL);
os_iterFree(itr, NULL);
itr = NULL;
}
}
if(itr) {
obj = os_malloc(sizeof(*obj));
obj->func = func;
obj->data = data;
os_iterAppend(itr, obj);
}
}
void
os_threadCleanupPop(
int execute)
{
os_iter *itr;
os_threadCleanup *obj;
(void)pthread_once(&cleanup_once, &os_threadCleanupInit);
if ((itr = (os_iter *)pthread_getspecific(cleanup_key)) != NULL) {
obj = (os_threadCleanup *)os_iterTake(itr, -1);
if (obj != NULL) {
if (execute) {
obj->func(obj->data);
}
os_free(obj);
}
}
}

View file

@ -0,0 +1,354 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "os/os.h"
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#ifndef PIKEOS_POSIX
#include <strings.h>
#endif
#include <string.h>
#include <ctype.h>
#include "os_stdlib_strsep.c"
_Ret_opt_z_ const char *
os_getenv(
_In_z_ const char *variable)
{
return getenv(variable);
}
os_result
os_putenv(
char *variable_definition)
{
os_result result;
if (putenv (variable_definition) == 0) {
result = os_resultSuccess;
} else {
result = os_resultFail;
}
return result;
}
const char *
os_fileSep(void)
{
return "/";
}
const char *
os_pathSep(void)
{
return ":";
}
os_result
os_access(
const char *file_path,
int32_t permission)
{
os_result result;
#ifdef VXWORKS_RTP
/* The access function is broken for vxworks RTP for some filesystems
so best ignore the result, and assume the user has correct permissions */
(void) file_path;
(void) permission;
result = os_resultSuccess;
#else
if (access (file_path, permission) == 0) {
result = os_resultSuccess;
} else {
result = os_resultFail;
}
#endif
return result;
}
char *
os_rindex(
const char *s,
int c)
{
char *last = NULL;
while (*s) {
if (*s == c) {
last = (char *)s;
}
s++;
}
return last;
}
_Ret_z_
_Check_return_
char *
os_strdup(
_In_z_ const char *s1)
{
size_t len;
char *dup;
len = strlen(s1) + 1;
dup = os_malloc(len);
memcpy(dup, s1, len);
return dup;
}
int
os_vsnprintf(
char *str,
size_t size,
const char *format,
va_list args)
{
return vsnprintf(str, size, format, args);
}
int
os_vfprintfnosigpipe(
FILE *file,
const char *format,
va_list args)
{
int result;
sigset_t sset_before, sset_omask, sset_pipe, sset_after;
sigemptyset(&sset_pipe);
sigaddset(&sset_pipe, SIGPIPE);
sigpending(&sset_before);
pthread_sigmask(SIG_BLOCK, &sset_pipe, &sset_omask);
result = vfprintf(file, format, args);
sigpending(&sset_after);
if (!sigismember(&sset_before, SIGPIPE) && sigismember(&sset_after, SIGPIPE)) {
/* sigtimedwait appears to be fairly well supported, just not by Mac OS. If other platforms prove to be a problem, we can do a proper indication of platform support in the os defs. The advantage of sigtimedwait is that it protects against a deadlock when SIGPIPE is sent from outside the program and all threads have it blocked. In any case, when SIGPIPE is sent in this manner and we consume the signal here, the signal is lost. Nobody should be abusing system-generated signals in this manner. */
#ifndef __APPLE__
struct timespec timeout = { 0, 0 };
sigtimedwait(&sset_pipe, NULL, &timeout);
#else
int sig;
sigwait(&sset_pipe, &sig);
#endif
#ifndef NDEBUG
sigpending(&sset_after);
assert(!sigismember(&sset_after, SIGPIPE));
#endif
os_setErrno(EPIPE);
result = -1;
}
pthread_sigmask(SIG_SETMASK, &sset_omask, NULL);
return result;
}
int
os_strcasecmp(
const char *s1,
const char *s2)
{
int cr;
while (*s1 && *s2) {
cr = tolower(*s1) - tolower(*s2);
if (cr) {
return cr;
}
s1++;
s2++;
}
cr = tolower(*s1) - tolower(*s2);
return cr;
}
int
os_strncasecmp(
const char *s1,
const char *s2,
size_t n)
{
int cr = 0;
while (*s1 && *s2 && n) {
cr = tolower(*s1) - tolower(*s2);
if (cr) {
return cr;
}
s1++;
s2++;
n--;
}
if (n) {
cr = tolower(*s1) - tolower(*s2);
}
return cr;
}
os_result
os_stat(
const char *path,
struct os_stat *buf)
{
os_result result;
struct stat _buf;
int r;
r = stat(path, &_buf);
if (r == 0) {
buf->stat_mode = _buf.st_mode;
buf->stat_size = (size_t) _buf.st_size;
buf->stat_mtime.tv_sec = (os_timeSec) _buf.st_mtime;
buf->stat_mtime.tv_nsec = 0;
result = os_resultSuccess;
} else {
result = os_resultFail;
}
return result;
}
os_result os_remove (const char *pathname)
{
return (remove (pathname) == 0) ? os_resultSuccess : os_resultFail;
}
os_result os_rename (const char *oldpath, const char *newpath)
{
return (rename (oldpath, newpath) == 0) ? os_resultSuccess : os_resultFail;
}
/* The result of os_fileNormalize should be freed with os_free */
char *
os_fileNormalize(
const char *filepath)
{
char *norm;
const char *fpPtr;
char *normPtr;
norm = NULL;
if ((filepath != NULL) && (*filepath != '\0')) {
norm = os_malloc(strlen(filepath) + 1);
/* replace any / or \ by OS_FILESEPCHAR */
fpPtr = (char *) filepath;
normPtr = norm;
while (*fpPtr != '\0') {
*normPtr = *fpPtr;
if ((*fpPtr == '/') || (*fpPtr == '\\')) {
*normPtr = OS_FILESEPCHAR;
normPtr++;
} else {
if (*fpPtr != '\"') {
normPtr++;
}
}
fpPtr++;
}
*normPtr = '\0';
}
return norm;
}
os_result
os_fsync(
FILE *fHandle)
{
os_result r;
if (fsync(fileno(fHandle)) == 0) {
r = os_resultSuccess;
} else {
r = os_resultFail;
}
return r;
}
_Ret_opt_z_ const char *
os_getTempDir(void)
{
const char * dir_name = NULL;
dir_name = os_getenv("OSPL_TEMP");
/* if OSPL_TEMP is not defined the default is /tmp */
if (dir_name == NULL || (strcmp (dir_name, "") == 0)) {
dir_name = "/tmp";
}
return dir_name;
}
ssize_t os_write(int fd, const void *buf, size_t count)
{
return write(fd, buf, count);
}
void os_flockfile(FILE *file)
{
/* flockfile is not supported on the VxWorks DKM platform.
* Therefore, this function block is empty on the VxWorks platform. */
#ifndef _WRS_KERNEL
flockfile (file);
#endif
}
void os_funlockfile(FILE *file)
{
/* funlockfile is not supported on the VxWorks DKM platform.
* Therefore, this function block is empty on the VxWorks platform. */
#ifndef _WRS_KERNEL
funlockfile (file);
#endif
}
int os_getopt(int argc, char **argv, const char *opts)
{
return getopt(argc, argv, opts);
}
void os_set_opterr(int err)
{
opterr = err;
}
int os_get_opterr(void)
{
return opterr;
}
void os_set_optind(int index)
{
optind = index;
}
int os_get_optind(void)
{
return optind;
}
int os_get_optopt(void)
{
return optopt;
}
char * os_get_optarg(void)
{
return optarg;
}

View file

@ -0,0 +1,17 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
void *
os_bsearch(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar) (const void *, const void *))
{
return bsearch (key,base,nmemb,size,compar);
}

View file

@ -0,0 +1,28 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "os/os_stdlib.h"
char *os_strsep (char **str, const char *sep)
{
char *ret;
if (**str == '\0')
return 0;
ret = *str;
while (**str && strchr (sep, **str) == 0)
(*str)++;
if (**str != '\0')
{
**str = '\0';
(*str)++;
}
return ret;
}

View file

@ -0,0 +1,190 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file os/common/code/os_stdlib_strtod.c
* \brief Double/Float to/from string conversions
*
* OSPL uses '.' as decimal point.
* Most stdlib like functions are locale dependent.
* This means that they can't be simply used when the
* LC_NUMERIC part of the locale is set to ',' like
* the locales nl_NL and fr_FR.
* This would clash with OSPL using '.'.
*
* The functions in this file provide locale
* independent conversions.
*/
#include "os/os_report.h"
/*
* Determine the maximum size that a string should have to be
* able to contain a double.
* See the following site for the calculation explanation:
* http://stackoverflow.com/questions/1701055/what-is-the-maximum-length-in-chars-needed-to-represent-any-double-value
*/
#include <float.h>
#define DOUBLE_STRING_MAX_LENGTH (3 + DBL_MANT_DIG - DBL_MIN_EXP)
/*
* VALID_DOUBLE_CHAR(c) is used to determine if the given char
* can be valid when it appears in a string that should represent
* a double.
* It is used to detect the end of a double string representation.
* Because it doesn't consider context, it is possible that more
* characters are detected after the double (fi. when a few white
* spaces tail the double). This isn't that bad, because the call
* to strtod itself will handle these extra characters properly.
*/
#define VALID_DOUBLE_CHAR(c) ( (isspace((unsigned char)(c))) || /* (leading) whitespaces */ \
(isxdigit((unsigned char)(c))) || /* (hexa)decimal digits */ \
((c) == '.') || /* ospl LC_NUMERIC */ \
((c) == os_lcNumericGet()) || /* locale LC_NUMERIC */ \
((c) == '+') || ((c) == '-') || /* signs */ \
((c) == 'x') || ((c) == 'X') || /* hexadecimal indication */ \
((c) == 'e') || ((c) == 'E') || /* exponent chars */ \
((c) == 'p') || ((c) == 'P') || /* binary exponent chars */ \
((c) == 'a') || ((c) == 'A') || /* char for NaN */ \
((c) == 'n') || ((c) == 'N') || /* char for NaN & INFINITY */ \
((c) == 'i') || ((c) == 'I') || /* char for INFINITY */ \
((c) == 'f') || ((c) == 'F') || /* char for INFINITY */ \
((c) == 't') || ((c) == 'T') || /* char for INFINITY */ \
((c) == 'y') || ((c) == 'Y')) /* char for INFINITY */
/** \brief Detect and return the LC_NUMERIC char of the locale.
*/
static char
os_lcNumericGet(void)
{
static char lcNumeric = ' ';
/* Detect lcNumeric only once. */
if (lcNumeric == ' ') {
/* There could be multiple threads here, but it is still save and works.
* Only side effect is that possibly multiple os_reports are traced. */
char num[] = { '\0', '\0', '\0', '\0' };
(void) snprintf(num, 4, "%3f", 2.2);
lcNumeric = num [1];
if (lcNumeric != '.') {
OS_WARNING("os_stdlib", 0,
"Locale with LC_NUMERIC \'%c\' detected, which is not '.'. This can decrease performance.",
lcNumeric);
}
}
return lcNumeric;
}
/** \brief Replace lcNumeric char with '.' in floating point string when locale dependent
* functions use a non '.' LC_NUMERIC, while we want locale indepenent '.'.
*/
static void
os_lcNumericReplace(char *str) {
/* We only need to replace when standard functions
* did not put a '.' in the result string. */
char lcNumeric = os_lcNumericGet();
if (lcNumeric != '.') {
str = os_index(str, lcNumeric);
if (str != NULL) {
*str = '.';
}
}
}
/** \brief Locale independent strtod wrapper.
*/
double
os_strtod(const char *nptr, char **endptr) {
double ret;
if (os_lcNumericGet() == '.') {
/* The current locale uses '.', so we can use the
* standard functions as is. */
ret = strtod(nptr, endptr);
} else {
/* The current locale uses ',', so we can not use the
* standard functions as is, but have to do extra work
* because ospl uses "x.x" doubles (notice the dot).
* Just copy the string and replace the LC_NUMERIC. */
char nptrCopy[DOUBLE_STRING_MAX_LENGTH];
char *nptrCopyIdx;
char *nptrCopyEnd;
char *nptrIdx;
/* It is possible that the given nptr just starts with a double
* representation but continues with other data.
* To be able to copy not too much and not too little, we have
* to scan across nptr until we detect the doubles' end. */
nptrIdx = (char*)nptr;
nptrCopyIdx = nptrCopy;
nptrCopyEnd = nptrCopyIdx + DOUBLE_STRING_MAX_LENGTH - 1;
while (VALID_DOUBLE_CHAR(*nptrIdx) && (nptrCopyIdx < nptrCopyEnd)) {
if (*nptrIdx == '.') {
/* Replace '.' with locale LC_NUMERIC to get strtod to work. */
*nptrCopyIdx = os_lcNumericGet();
} else {
*nptrCopyIdx = *nptrIdx;
}
nptrIdx++;
nptrCopyIdx++;
}
*nptrCopyIdx = '\0';
/* Now that we have a copy with the proper locale LC_NUMERIC,
* we can use strtod() for the conversion. */
ret = strtod(nptrCopy, &nptrCopyEnd);
/* Calculate the proper end char when needed. */
if (endptr != NULL) {
*endptr = (char*)nptr + (nptrCopyEnd - nptrCopy);
}
}
return ret;
}
/** \brief Locale independent strtof wrapper.
*/
float
os_strtof(const char *nptr, char **endptr) {
/* Just use os_strtod(). */
return (float)os_strtod(nptr, endptr);
}
/** \brief Locale independent snprintf wrapper, which mirrors os_strtod.
*/
int
os_dtostr(double src, char *str, size_t size) {
int i;
/* Use locale dependent standard function. */
i = snprintf(str, size, "%0.15g", src);
/* Make sure the result is a locale independent "x.x" double. */
os_lcNumericReplace(str);
return i;
}
/** \brief Locale independent snprintf wrapper, which mirrors os_strtof.
*/
int
os_ftostr(float src, char *str, size_t size) {
int i;
/* Use locale dependent standard function. */
i = snprintf(str, size, "%0.7g", src);
/* Make sure the result is a locale independent "x.x" float. */
os_lcNumericReplace(str);
return i;
}

View file

@ -0,0 +1,70 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
char *
os_index(
const char *s,
int c)
{
char *first = NULL;
while (*s) {
if (*s == c) {
first = (char *)s;
break;
}
s++;
}
return first;
}
char *os_strtok_r(char *str, const char *delim, char **saveptr)
{
#if OS_HAS_STRTOK_R == 1
return( strtok_r( str, delim, saveptr ) );
#else
char *ret;
int found = 0;
if ( str == NULL )
{
str = *saveptr;
}
ret = str;
if ( str != NULL )
{
/* Ignore delimiters at start */
while ( *str != '\0' && os_index( delim, *str ) != NULL )
{
str++;
ret++;
};
while ( *str != '\0' )
{
if ( os_index( delim, *str ) != NULL )
{
*str='\0';
*saveptr=(str+1);
found=1;
break;
}
str++;
}
if ( !found )
{
*saveptr=NULL;
}
}
return ( ret != NULL && *ret == '\0' ? NULL : ret );
#endif
}

View file

@ -0,0 +1,266 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <ctype.h>
#include <string.h>
#include "os/os.h"
int os_todigit (const int chr)
{
int num = -1;
if (chr >= '0' && chr <= '9') {
num = chr - '0';
} else if (chr >= 'a' && chr <= 'z') {
num = 10 + (chr - 'a');
} else if (chr >= 'A' && chr <= 'Z') {
num = 10 + (chr - 'A');
}
return num;
}
static unsigned long long
os__strtoull__ (
const char *str,
char **endptr,
int32_t base,
unsigned long long max)
{
int err = 0;
int num;
size_t cnt = 0;
unsigned long long tot = 0;
assert (str != NULL);
if (base == 0) {
if (str[0] == '0') {
if ((str[1] == 'x' || str[1] == 'X') && os_todigit (str[2]) < 16) {
base = 16;
cnt = 2;
} else {
base = 8;
}
} else {
base = 10;
}
} else if (base == 16) {
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
cnt = 2;
}
} else if (base < 2 || base > 36) {
err = EINVAL;
}
while (!err && (num = os_todigit (str[cnt])) >= 0 && num < base) {
if (tot <= (max / (unsigned) base)) {
tot *= (unsigned) base;
tot += (unsigned) num;
cnt++;
} else {
err = ERANGE;
tot = max;
}
}
if (endptr != NULL) {
*endptr = (char *)str + cnt;
}
if (err) {
os_setErrno(err);
}
return tot;
}
long long
os_strtoll(
const char *str,
char **endptr,
int32_t base)
{
size_t cnt = 0;
long long tot = 1;
unsigned long long max = INT64_MAX;
assert (str != NULL);
for (; isspace((unsigned char)str[cnt]); cnt++) {
/* ignore leading whitespace */
}
if (str[cnt] == '-') {
tot = -1;
max++;
cnt++;
} else if (str[cnt] == '+') {
cnt++;
}
tot *= (long long) os__strtoull__ (str + cnt, endptr, base, max);
if (endptr && *endptr == (str + cnt)) {
*endptr = (char *)str;
}
return tot;
}
unsigned long long
os_strtoull (
const char *str,
char **endptr,
int32_t base)
{
size_t cnt = 0;
unsigned long long tot = 1;
unsigned long long max = UINT64_MAX;
assert (str != NULL);
for (; isspace((unsigned char)str[cnt]); cnt++) {
/* ignore leading whitespace */
}
if (str[cnt] == '-') {
tot = (unsigned long long) -1;
cnt++;
} else if (str[cnt] == '+') {
cnt++;
}
tot *= os__strtoull__ (str + cnt, endptr, base, max);
if (endptr && *endptr == (str + cnt)) {
*endptr = (char *)str;
}
return tot;
}
long long
os_atoll(
const char *str)
{
return os_strtoll(str, NULL, 10);
}
unsigned long long
os_atoull(
const char *str)
{
return os_strtoull(str, NULL, 10);
}
char *
os_ulltostr (
unsigned long long num,
char *str,
size_t len,
char **endptr)
{
char chr, *ptr;
size_t cnt;
size_t lim = 0;
size_t tot = 0;
assert (str != NULL);
if (len > 1) {
lim = len - 1;
do {
str[tot] = (char)('0' + (int)(num % 10));
num /= 10;
if (tot == (lim - 1)) {
if (num > 0ULL) {
/* Simply using memmove would have been easier, but the
function is safe to use in asynchronous code like this.
Normally this code should not affect performance,
because ideally the buffer is sufficiently large
enough. */
for (cnt = 0; cnt < tot; cnt++) {
str[cnt] = str[cnt + 1];
}
}
} else if (num > 0ULL) {
tot++;
}
} while (num > 0ULL);
lim = tot + 1;
}
for (cnt = 0; cnt < (tot - cnt); cnt++) {
chr = str[tot - cnt];
str[tot - cnt] = str[cnt];
str[cnt] = chr;
}
if (len == 0) {
str = NULL;
ptr = NULL;
} else {
str[lim] = '\0';
ptr = str + lim;
}
if (endptr != NULL) {
*endptr = ptr;
}
return str;
}
char *
os_lltostr (
long long num,
char *str,
size_t len,
char **endptr)
{
unsigned long long pos;
char *ptr;
size_t cnt = 0;
assert (str != NULL);
if (len == 0) {
str = NULL;
ptr = NULL;
} else if (len == 1) {
str[0] = '\0';
ptr = str;
} else {
if (num < 0LL) {
if (num == INT64_MIN) {
pos = (unsigned long long)INT64_MAX + 1;
} else {
pos = (unsigned long long) -num;
}
str[cnt++] = '-';
} else {
pos = (unsigned long long) num;
}
(void)os_ulltostr (pos, str + cnt, len - cnt, &ptr);
}
if (endptr != NULL) {
*endptr = ptr;
}
return str;
}

View file

@ -0,0 +1,63 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_POSIX_STDLIB_H
#define OS_POSIX_STDLIB_H
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <limits.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __VXWORKS__
void os_stdlibInitialize(void);
#endif
#ifdef OSPL_VERSION
#ifdef PIKEOS_POSIX
#include <lwip/netdb.h>
#else
#include <netdb.h>
#endif
#endif
#if defined (__cplusplus)
extern "C" {
#endif
#define OS_OS_FILESEPCHAR '/'
#define OS_OS_PATHSEPCHAR ':'
#define OS_OS_EXESUFFIX ""
#define OS_OS_BATSUFFIX ""
#define OS_OS_LIB_LOAD_PATH_VAR "LD_LIBRARY_PATH"
#define OS_ROK R_OK
#define OS_WOK W_OK
#define OS_XOK X_OK
#define OS_FOK F_OK
#define OS_ISDIR S_ISDIR
#define OS_ISREG S_ISREG
#define OS_ISLNK S_ISLNK
#define OS_PATH_MAX _POSIX_PATH_MAX
typedef DIR *os_os_dirHandle;
#if defined (__cplusplus)
}
#endif
#endif /* OS_POSIX_STDLIB_H */

View file

@ -0,0 +1,82 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <limits.h>
#include <string.h>
#include "os/os.h"
int
os_getErrno(void)
{
return errno;
}
void
os_setErrno(int err)
{
errno = err;
}
#ifdef _WRS_KERNEL
extern char *
strerrorIf(
int errcode);
/* VxWorks has a non-compliant strerror_r in kernel mode which only takes a
buffer and an error number. Providing a buffer smaller than NAME_MAX + 1
(256) may result in a buffer overflow. See target/src/libc/strerror.c for
details. NAME_MAX is defined in limits.h. */
int
os_strerror_r(int err, char *str, size_t len)
{
int res = EINVAL;
assert(str != NULL);
if (len < (NAME_MAX + 1)) {
res = ERANGE;
} else if (strerrorIf(err) != NULL) {
(void)strerror_r(err, str);
}
return res;
}
#else
int
os_strerror_r(int err, char *str, size_t len)
{
int res = 0;
assert(str != NULL);
/* VxWorks's strerror_r always returns 0 (zero), so the only way to decide
if the error was truncated is to check if the last position in the
buffer is overwritten by strerror_r. */
str[len - 1] = 'x';
(void)strerror_r (err, str, len);
if (str[len - 1] != 'x') {
res = ERANGE;
}
str[len - 1] = '\0'; /* always null terminate, just to be safe */
return res;
}
#endif /* _WRS_KERNEL */

View file

@ -0,0 +1,147 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
/** \file os/vxworks/os_platform_heap.c
* \brief VxWorks heap memory management
*
* Implements heap memory management for VxWorks
* by including the common implementation
*/
#if defined(OS_USE_ALLIGNED_MALLOC)
#ifndef NDEBUG
#include "os/os.h"
atomic_t os__reallocdoublecopycount = 0;
#endif
void *
os_malloc(
size_t size)
{
void *ptr;
void *origptr;
origptr = malloc(size+12);
ptr=origptr;
if (!ptr)
{
return NULL;
}
assert ( ((char *)ptr - (char *)0) % 4 == 0 );
if ( ((char *)ptr - (char *)0) % 8 != 0 )
{
/* malloc returned memory not 8 byte aligned */
/* move pointer by 4 so that it will be aligned again */
ptr=((uint32_t *)ptr) + 1;
}
/* Store requested size */
/* 8 bytes before the pointer we return */
*(((size_t *)ptr)) = size;
ptr=((size_t *)ptr) + 1;
/* Store pointer to result of malloc "before" the allocation */
/* 4 bytes before the pointer we return */
*((void **)ptr)= origptr;
ptr=((uint32_t *)ptr) + 1;
assert ( ((char *)ptr - (char *)0) % 8 == 0 );
return ptr;
}
void *os_realloc(
void *ptr,
size_t size)
{
void *newptr; /* Address returned from system realloc */
void *origptr; /* Address returned by previous *alloc */
void *olddata; /* Address of original user data immediately after realloc. */
void *newdata; /* Address user data will be at on return. */
size_t origsize; /* Size before realloc */
if ( ptr == NULL )
{
return (os_malloc(size));
}
assert ( ((char *)ptr - (char *)0) % 8 == 0 );
origptr = *(((void **)ptr)-1);
if ( size == 0 )
{
/* really a free */
realloc(origptr, size);
return NULL;
}
origsize = *(((size_t *)ptr)-2);
newptr = realloc(origptr, size+12);
if ( newptr == NULL )
{
/* realloc failed, everything is left untouched */
return NULL;
}
olddata = (char *)newptr + ((char *)ptr - (char *)origptr);
assert ( ((char *)newptr - (char *)0) % 4 == 0 );
if ( ((char *)newptr - (char *)0) % 8 == 0 )
{
/* Allow space for size and pointer */
newdata = ((uint32_t *)newptr)+2;
}
else
{
/* malloc returned memory not 8 byte aligned */
/* realign, and Allow space for size and pointer */
newdata = ((uint32_t *)newptr)+3;
}
assert ( ((char *)newdata - (char *)0) % 8 == 0 );
if ( (((char *)newptr - (char *)0) % 8) != (((char *)origptr - (char *)0) % 8) )
{
/* realloc returned memory with different alignment */
assert ( ((char *)newdata)+4 == ((char *)olddata)
||((char *)olddata)+4 == ((char *)newdata));
#ifndef NDEBUG
vxAtomicInc( &os__reallocdoublecopycount);
#endif
memmove(newdata, olddata, origsize < size ? origsize : size);
}
/* Store requested size */
/* 8 bytes before the pointer we return */
*(((size_t *)newdata)-2) = size;
/* Store pointer to result of realloc "before" the allocation */
/* 4 bytes before the pointer we return */
*(((void **)newdata)-1) = newptr;
return newdata;
}
void
os_free(
void *ptr)
{
assert ( ((char *)ptr - (char *)0) % 8 == 0 );
free(*(((void **)ptr)-1));
}
#else
/* For 64bit use the native ops align to 8 bytes */
#include "../snippets/code/os_heap.c"
#endif /* OS_USE_ALLIGNED_MALLOC */

View file

@ -0,0 +1,129 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/****************************************************************
* Initialization / Deinitialization *
****************************************************************/
/** \file os/vxworks/os_platform_init.c
* \brief Initialization / Deinitialization
*/
#include <assert.h>
#include "os/os.h"
#if defined(OS_USE_ALLIGNED_MALLOC) && !defined(NDEBUG)
#include "os/os_atomics.h"
extern atomic_t os__reallocdoublecopycount ;
#endif
/** \brief Counter that keeps track of number of times os-layer is initialized */
static os_atomic_uint32_t _ospl_osInitCount = OS_ATOMIC_UINT32_INIT(0);
/* Check expression is true at compile time ( no code generated )
- will get negative sized array on failure */
#define EXPRCHECK(expr) (void)sizeof(char[1-(signed int)(2*(unsigned int)!(expr))]);
/** \brief OS layer initialization
*
* \b os_osInit calls:
* - \b os_sharedMemoryInit
* - \b os_threadInit
*/
void os_osInit (void)
{
uint32_t initCount;
/* Sanity checks, don't remove, they don't generate any code anyway. */
EXPRCHECK(sizeof(char)==1)
EXPRCHECK(sizeof(unsigned char)==1)
EXPRCHECK(sizeof(short)==2)
EXPRCHECK(sizeof(unsigned short)==2)
EXPRCHECK(sizeof(int32_t)==4)
EXPRCHECK(sizeof(uint32_t)==4)
EXPRCHECK(sizeof(int64_t)==8)
EXPRCHECK(sizeof(uint64_t)==8)
EXPRCHECK(sizeof(float)==4)
EXPRCHECK(sizeof(double)==8)
#ifdef OS_USE_ALLIGNED_MALLOC
/* Check for heap realignment code which needs types below being 32bit */
EXPRCHECK(sizeof(size_t)==4)
EXPRCHECK(sizeof(void *)==4)
#endif
initCount = os_atomic_inc32_nv(&_ospl_osInitCount);
if (initCount == 1) {
/* init for programs using data base threads */
os_threadModuleInit();
os_reportInit(false);
#ifdef _WRS_KERNEL
os_stdlibInitialize();
#endif
}
return;
}
/** \brief OS layer deinitialization
*/
void os_osExit (void)
{
uint32_t initCount;
#if defined(OS_USE_ALLIGNED_MALLOC) && !defined(NDEBUG)
OS_INFO("os__reallocdoublecopycount", 0, "count=%d", vxAtomicGet(&os__reallocdoublecopycount));
#endif
initCount = os_atomic_dec32_nv(&_ospl_osInitCount);
if (initCount == 0) {
os_reportExit();
os_threadModuleExit();
os_syncModuleExit();
} else if ((initCount + 1) < initCount){
/* The 0 boundary is passed, so os_osExit is called more often than
* os_osInit. Therefore undo decrement as nothing happened and warn. */
initCount = os_atomic_inc32_nv(&_ospl_osInitCount);
OS_WARNING("os_osExit", 1, "OS-layer not initialized");
/* Fail in case of DEV, as it is incorrect API usage */
assert(0);
}
return;
}
#ifdef _WRS_KERNEL
/* This constructor is invoked when the library is loaded into a process. */
void __attribute__ ((constructor))
os__osInit(
void)
{
os_osInit();
}
/* This destructor is invoked when the library is unloaded from a process. */
void __attribute__ ((destructor))
os__osExit(
void)
{
os_osExit();
}
#else
/* This constructor is invoked when the library is loaded into a process. */
_WRS_CONSTRUCTOR(os__osInit, 100) {
os_osInit();
atexit(&os_osExit); /* There is no _WRS_DESTRUCTOR, use atexit instead */
return;
}
#endif

View file

@ -0,0 +1,29 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifdef _WRS_KERNEL
#include "os/os.h"
/** \brief Return the process ID of the calling process
*
* Possible Results:
* - returns the process ID of the calling process
*/
os_procId
os_procIdSelf(void)
{
return getpid(); /* Mapped to taskIdSelf() in kernel mode */
}
#else
#include "../posix/os_platform_process.c"
#endif /* _WRS_KERNEL */

View file

@ -0,0 +1,12 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "../posix/os_platform_socket.c"

View file

@ -0,0 +1,50 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <string.h>
#include <unistd.h>
#include <hostLib.h> /* MAXHOSTNAMELEN */
#include "os/os.h"
#ifdef _WRS_KERNEL
#include <envLib.h>
extern char *os_environ[];
void
os_stdlibInitialize(
void)
{
char **varset;
for ( varset = &os_environ[0]; *varset != NULL; varset++ )
{
char *savePtr=NULL;
char *varName;
char *tmp = os_strdup( *varset );
varName = strtok_r( tmp, "=", &savePtr );
if ( os_getenv( varName ) == NULL )
{
os_putenv( *varset );
}
os_free(tmp);
}
}
#endif
#define OS_HAS_STRTOK_R 1 /* FIXME: Should be handled by CMake */
#include "../snippets/code/os_gethostname.c"
#include "../snippets/code/os_stdlib.c"
#include "../snippets/code/os_stdlib_bsearch.c"
#include "../snippets/code/os_stdlib_strtod.c"
#include "../snippets/code/os_stdlib_strtol.c"
#include "../snippets/code/os_stdlib_strtok_r.c"

View file

@ -0,0 +1,12 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "../posix/os_platform_sync.c"

View file

@ -0,0 +1,12 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "../snippets/code/os_posix_thread.c"

View file

@ -0,0 +1,12 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "../posix/os_platform_time.c"

View file

@ -0,0 +1,93 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "os/os.h"
#include <assert.h>
/* WSAGetLastError, GetLastError and errno
Windows supports errno (The Microsoft c Run-Time Library for Windows CE
does so since version 15 (Visual Studio 2008)). Error codes set by the
Windows Sockets implementation, however, are NOT made available via the
errno variable.
WSAGetLastError used to be the thread-safe version of GetLastError, but
nowadays is just an an alias for GetLastError as intended by Microsoft:
http://www.sockets.com/winsock.htm#Deviation_ErrorCodes
There is no relationship between GetLastError and errno.
GetLastError returns the last error that occurred in a Windows API function
(for the current thread). errno contains the last error that occurred in the C
runtime library. Normally if a WinAPI call fails, e.g. CreateFile, GetLastError
should be used to retrieve the error. If a C runtime library function fails,
e.g. fopen, errno contains the error number.
*/
int
os_getErrno(void)
{
DWORD err = GetLastError();
if (err != 0) {
errno = (int)err;
}
return errno;
}
void
os_setErrno(int err)
{
SetLastError(err);
errno = err;
}
int
os_strerror_r(
_In_ int err,
_Out_writes_z_(len) char *str,
_In_ size_t len)
{
int res = 0, errs[2];
DWORD cnt;
assert(str != NULL);
assert(len > 0);
str[0] = '\0'; /* null-terminate in case nothing is written */
errs[0] = os_getErrno();
cnt = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)str,
(DWORD)len,
NULL);
errs[1] = os_getErrno();
if (cnt == 0) {
if (errs[1] == ERROR_MORE_DATA) {
res = ERANGE;
} else {
res = EINVAL;
}
}
/* os_strerror_r should not modify errno itself */
if (errs[0] != errs[1]) {
os_setErrno(errs[0]);
}
str[len - 1] = '\0'; /* always null-terminate, just to be safe */
return res;
}

View file

@ -0,0 +1,19 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file os/darwin/code/os_heap.c
* \brief Darwin heap memory management
*
* Implements heap memory management for Darwin
* by including the common implementation
*/
#include "../snippets/code/os_heap.c"

View file

@ -0,0 +1,106 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/****************************************************************
* Initialization / Deinitialization *
****************************************************************/
/** \file os/darwin/code/os_init.c
* \brief Initialization / Deinitialization
*/
#include <assert.h>
#include "os/os.h"
/** \brief Counter that keeps track of number of times os-layer is initialized */
static os_atomic_uint32_t _ospl_osInitCount = OS_ATOMIC_UINT32_INIT(0);
/** \brief OS layer initialization
*
* \b os_osInit calls:
* - \b os_sharedMemoryInit
* - \b os_threadInit
*/
void os_osInit (void)
{
uint32_t initCount;
initCount = os_atomic_inc32_nv(&_ospl_osInitCount);
if (initCount == 1) {
os_processModuleInit();
os_threadModuleInit();
os_timeModuleInit();
os_reportInit(false);
os_socketModuleInit();
}
return;
}
/** \brief OS layer deinitialization
*/
void os_osExit (void)
{
uint32_t initCount;
initCount = os_atomic_dec32_nv(&_ospl_osInitCount);
if (initCount == 0) {
os_socketModuleExit();
os_reportExit();
os_timeModuleExit();
os_threadModuleExit();
os_processModuleExit();
} else if ((initCount + 1) < initCount){
/* The 0 boundary is passed, so os_osExit is called more often than
* os_osInit. Therefore undo decrement as nothing happened and warn. */
os_atomic_inc32(&_ospl_osInitCount);
OS_WARNING("os_osExit", 1, "OS-layer not initialized");
/* Fail in case of DEV, as it is incorrect API usage */
assert(0);
}
return;
}
/* We need this on windows to make sure the main thread of MFC applications
* calls os_osInit().
*/
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, /* handle to DLL module */
DWORD fdwReason, /* reason for calling function */
LPVOID lpReserved ) /* reserved */
{
/* Perform actions based on the reason for calling.*/
switch( fdwReason ) {
case DLL_PROCESS_ATTACH:
/* Initialize once for each new process.
* Return FALSE to fail DLL load.
*/
os_osInit();
break;
case DLL_THREAD_ATTACH:
/* Do thread-specific initialization.
*/
break;
case DLL_THREAD_DETACH:
/* Do thread-specific cleanup.
*/
break;
case DLL_PROCESS_DETACH:
/* Perform any necessary cleanup.
*/
os_osExit();
break;
}
return TRUE; /* Successful DLL_PROCESS_ATTACH.*/
}

View file

@ -0,0 +1,144 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file os/win32/code/os_process.c
* \brief WIN32 process management
*
* Implements process management for WIN32
*/
#include "os/os.h"
#include <process.h>
#include <assert.h>
#include <stdlib.h>
/* #642 fix : define mapping between scheduling abstraction and windows
* Windows provides 6 scheduling classes for the process
* IDLE_PRIORITY_CLASS
* BELOW_NORMAL_PRIORITY_CLASS
* NORMAL_PRIORITY_CLASS
* ABOVE_NORMAL_PRIORITY_CLASS
* HIGH_PRIORITY_CLASS
* REALTIME_PRIORITY_CLASS */
/* These defaults should be modifiable through configuration */
static const os_schedClass TIMESHARE_DEFAULT_SCHED_CLASS = NORMAL_PRIORITY_CLASS;
static const os_schedClass REALTIME_DEFAULT_SCHED_CLASS = REALTIME_PRIORITY_CLASS;
static os_atomic_voidp_t os_procname = OS_ATOMIC_VOIDP_INIT(0);
/* Protected functions */
void
os_processModuleInit(void)
{
return;
}
void
os_processModuleExit(void)
{
void *pname;
do {
pname = os_atomic_ldvoidp(&os_procname);
} while (!os_atomic_casvoidp(&os_procname, pname, NULL));
os_free(pname);
}
/** \brief Return the process ID of the calling process
*
* Possible Results:
* - returns the process ID of the calling process
*/
os_procId
os_procIdSelf(void)
{
/* returns a pseudo HANDLE to process, no need to close it */
return GetProcessId (GetCurrentProcess());
}
/** \brief Figure out the identity of the current process
*
* Possible Results:
* - returns the actual length of procIdentity
*
* Postcondition:
* - \b procIdentity is ""
* the process identity could not be determined
* - \b procIdentity is "<decimal number>"
* only the process numeric identity could be determined
* - \b procIdentity is "name <pid>"
* the process name and numeric identity could be determined
*
* \b procIdentity will not be filled beyond the specified \b procIdentitySize
*/
#define _OS_PROC_PROCES_NAME_LEN (512)
int
os_procNamePid(
_Out_writes_z_(procIdentitySize) char *procIdentity,
_In_ size_t procIdentitySize)
{
int size;
char process_name[_OS_PROC_PROCES_NAME_LEN];
size = os_procName(process_name, sizeof(process_name));
if (size > 0) {
size = snprintf(procIdentity, procIdentitySize, "%s <%"PRIprocId">", process_name, os_procIdSelf());
} else {
/* No processname could be determined, so default to PID */
size = snprintf(procIdentity, procIdentitySize, "<%"PRIprocId">", os_procIdSelf());
}
return size;
}
int
os_procName(
_Out_writes_z_(procNameSize) char *procName,
_In_ size_t procNameSize)
{
char *process_name;
if ((process_name = os_atomic_ldvoidp(&os_procname)) == NULL) {
char *exec, *pname;
DWORD nSize, allocated = 0;
do {
/* While procNameSize could be used (since the caller cannot
* store more data anyway, it is not used. This way the amount that
* needs to be allocated to get the full-name can be determined. */
allocated++;
process_name = os_realloc(process_name, allocated * _OS_PROC_PROCES_NAME_LEN);
/* First parameter NULL retrieves module-name of executable */
nSize = GetModuleFileNameA(NULL, process_name, allocated * _OS_PROC_PROCES_NAME_LEN);
/* process_name will only be guaranteed to be NULL-terminated if nSize <
* (allocated * _OS_PROC_PROCES_NAME_LEN), so continue until that's true */
} while (nSize >= (allocated * _OS_PROC_PROCES_NAME_LEN));
exec = strrchr(process_name, '\\');
if (exec) {
/* skip all before the last '\' */
exec++;
memmove(process_name, exec, strlen(exec) + 1);
/* Could potentially realloc; can't be bothered */
}
do {
pname = os_atomic_ldvoidp(&os_procname);
} while (pname == NULL && !os_atomic_casvoidp(&os_procname, NULL, process_name));
if(pname) {
os_free(process_name);
process_name = pname;
}
}
return snprintf(procName, procNameSize, "%s", process_name);
}
#undef _OS_PROC_PROCES_NAME_LEN

View file

@ -0,0 +1,898 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file
* \brief WIN32 socket management
*
* Implements socket management for WIN32
*/
#include "os/os.h"
#include <Qos2.h>
#include <assert.h>
#define WORKING_BUFFER_SIZE 15000
#define MAX_TRIES 3
typedef BOOL (WINAPI *qwaveQOSCreateHandleFuncT) (_In_ PQOS_VERSION Version, _Out_ PHANDLE QOSHandle);
typedef BOOL (WINAPI *qwaveQOSCloseHandleFuncT) (_In_ HANDLE QOSHandle);
typedef BOOL (WINAPI *qwaveQOSAddSocketToFlowFuncT) (
_In_ HANDLE QOSHandle,
_In_ SOCKET Socket,
_In_opt_ PSOCKADDR DestAddr,
_In_ QOS_TRAFFIC_TYPE TrafficType,
_In_opt_ DWORD Flags,
_Inout_ PQOS_FLOWID FlowId
);
typedef BOOL (WINAPI *qwaveQOSSetFlowFuncT) (
_In_ HANDLE QOSHandle,
_In_ QOS_FLOWID FlowId,
_In_ QOS_SET_FLOW Operation,
_In_ ULONG Size,
_In_ PVOID Buffer,
_Reserved_ DWORD Flags,
_Out_opt_ LPOVERLAPPED Overlapped
);
static qwaveQOSCreateHandleFuncT qwaveQOSCreateHandleFunc;
static qwaveQOSCloseHandleFuncT qwaveQOSCloseHandleFunc;
static qwaveQOSAddSocketToFlowFuncT qwaveQOSAddSocketToFlowFunc;
static qwaveQOSSetFlowFuncT qwaveQOSSetFlowFunc;
static HANDLE qwaveDLLModuleHandle = NULL;
static HANDLE qwaveDLLModuleLock = NULL;
void
os_socketModuleInit()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD (OS_SOCK_VERSION, OS_SOCK_REVISION);
err = WSAStartup (wVersionRequested, &wsaData);
if (err != 0) {
OS_FATAL("os_socketModuleInit", 0, "WSAStartup failed, no compatible socket implementation available");
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
return;
}
/* Confirm that the WinSock DLL supports 2.0. */
/* Note that if the DLL supports versions greater */
/* than 2.0 in addition to 2.0, it will still return */
/* 2.0 in wVersion since that is the version we */
/* requested. */
if ((LOBYTE(wsaData.wVersion) != OS_SOCK_VERSION) ||
(HIBYTE(wsaData.wVersion) != OS_SOCK_REVISION)) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
OS_FATAL("os_socketModuleInit", 1, "WSAStartup failed, no compatible socket implementation available");
WSACleanup();
return;
}
qwaveDLLModuleLock = CreateMutex(NULL, FALSE, NULL);
if (qwaveDLLModuleLock == NULL) {
OS_ERROR("os_socketModuleInit", 0, "Failed to create mutex");
}
}
void
os_socketModuleExit(void)
{
if (qwaveDLLModuleHandle) {
FreeLibrary(qwaveDLLModuleHandle);
}
if (qwaveDLLModuleLock) {
CloseHandle(qwaveDLLModuleLock);
}
WSACleanup();
return;
}
os_socket
os_sockNew(
int domain,
int type)
{
return socket(domain, type, 0);
}
os_result
os_sockBind(
os_socket s,
const struct sockaddr *name,
uint32_t namelen)
{
os_result result = os_resultSuccess;
if (bind(s, (struct sockaddr *)name, namelen) == SOCKET_ERROR) {
result = os_resultFail;
}
return result;
}
os_result
os_sockGetsockname(
os_socket s,
const struct sockaddr *name,
uint32_t namelen)
{
os_result result = os_resultSuccess;
int len = namelen;
if (getsockname(s, (struct sockaddr *)name, &len) == SOCKET_ERROR) {
result = os_resultFail;
}
return result;
}
os_result
os_sockSendto(
os_socket s,
const void *msg,
size_t len,
const struct sockaddr *to,
size_t tolen,
size_t *bytesSent)
{
int res = sendto(s, msg, (int)len, 0, to, (int)tolen); /* The parameter len with type of size_t causes the possible loss of data. So type casting done */
if (res < 0)
{
*bytesSent = 0;
return os_resultFail;
}
else
{
*bytesSent = res;
return os_resultSuccess;
}
}
os_result
os_sockRecvfrom(
os_socket s,
void *buf,
size_t len,
struct sockaddr *from,
size_t *fromlen,
size_t *bytesRead)
{
int res;
res = recvfrom(s, buf, (int)len, 0, from, (int *)fromlen);
if (res == SOCKET_ERROR)
{
*bytesRead = 0;
return os_resultFail;
}
else
{
*bytesRead = (size_t)res;
return os_resultSuccess;
}
}
os_result
os_sockGetsockopt(
os_socket s,
int32_t level,
int32_t optname,
void *optval,
uint32_t *optlen)
{
os_result result = os_resultSuccess;
/* On win32 IP_MULTICAST_TTL and IP_MULTICAST_LOOP take DWORD * param
rather than char * */
if ( level == IPPROTO_IP
&& ( optname == IP_MULTICAST_TTL
|| optname == IP_MULTICAST_LOOP ) )
{
int dwoptlen = sizeof( DWORD );
DWORD dwoptval = *((unsigned char *)optval);
if (getsockopt(s, level, optname, (char *)&dwoptval, &dwoptlen) == SOCKET_ERROR)
{
result = os_resultFail;
}
assert( dwoptlen == sizeof( DWORD ) );
*((unsigned char *)optval) = (unsigned char)dwoptval;
*optlen = sizeof( unsigned char );
}
else
{
if (getsockopt(s, level, optname, optval, (int *)optlen) == SOCKET_ERROR)
{
result = os_resultFail;
}
}
return result;
}
static os_result
os_sockSetDscpValueWithTos(
os_socket sock,
DWORD value)
{
os_result result = os_resultSuccess;
if (setsockopt(sock, IPPROTO_IP, IP_TOS, (char *)&value, (int)sizeof(value)) == SOCKET_ERROR) {
char errmsg[1024];
int errNo = os_getErrno();
(void) os_strerror_r(errNo, errmsg, sizeof errmsg);
OS_WARNING("os_sockSetDscpValue", 0, "Failed to set diffserv value to %lu: %d %s", value, errNo, errmsg);
result = os_resultFail;
}
return result;
}
static os_result
os_sockLoadQwaveLibrary(void)
{
if (qwaveDLLModuleLock == NULL) {
OS_WARNING("os_sockLoadQwaveLibrary", 0,
"Failed to load QWAVE.DLL for using diffserv on outgoing IP packets");
goto err_lock;
}
WaitForSingleObject(qwaveDLLModuleLock, INFINITE);
if (qwaveDLLModuleHandle == NULL) {
if ((qwaveDLLModuleHandle = LoadLibrary("QWAVE.DLL")) == NULL) {
OS_WARNING("os_sockLoadQwaveLibrary", 0,
"Failed to load QWAVE.DLL for using diffserv on outgoing IP packets");
goto err_load_lib;
}
qwaveQOSCreateHandleFunc = (qwaveQOSCreateHandleFuncT) GetProcAddress(qwaveDLLModuleHandle, "QOSCreateHandle");
qwaveQOSCloseHandleFunc = (qwaveQOSCloseHandleFuncT) GetProcAddress(qwaveDLLModuleHandle, "QOSCloseHandle");
qwaveQOSAddSocketToFlowFunc = (qwaveQOSAddSocketToFlowFuncT) GetProcAddress(qwaveDLLModuleHandle, "QOSAddSocketToFlow");
qwaveQOSSetFlowFunc = (qwaveQOSSetFlowFuncT) GetProcAddress(qwaveDLLModuleHandle, "QOSSetFlow");
if ((qwaveQOSCreateHandleFunc == 0) || (qwaveQOSCloseHandleFunc == 0) ||
(qwaveQOSAddSocketToFlowFunc == 0) || (qwaveQOSSetFlowFunc == 0)) {
OS_WARNING("os_sockLoadQwaveLibrary", 0,
"Failed to resolve entry points for using diffserv on outgoing IP packets");
goto err_find_func;
}
}
ReleaseMutex(qwaveDLLModuleLock);
return os_resultSuccess;
err_find_func:
err_load_lib:
ReleaseMutex(qwaveDLLModuleLock);
err_lock:
return os_resultFail;
}
/* To set the DSCP value on Windows 7 or higher the following functions are used.
*
* - BOOL QOSCreateHandle(PQOS_VERSION Version, PHANDLE QOSHandle)
* - BOOL QOSCloseHandle(HANDLE QOSHandle)
* - BOOL WINAPI QOSAddSocketToFlow(HANDLE QOSHandle, SOCKET Socket,
* PSOCKADDR DestAddr, QOS_TRAFFIC_TYPE TrafficType,
* DWORD Flags, PQOS_FLOWID FlowId)
* - BOOL WINAPI QOSSetFlow(HANDLE QOSHandle, QOS_FLOWID FlowId,
* QOS_SET_FLOW Operation, ULONG Size, PVOID Buffer,
* DWORD Flags, LPOVERLAPPED Overlapped)
*/
/* QOS_TRAFFIC_TYPE
* - QOSTrafficTypeBestEffort = 0
* - QOSTrafficTypeBackground = 1
* - QOSTrafficTypeExcellentEffort = 2
* - QOSTrafficTypeAudioVideo = 3
* - QOSTrafficTypeVoice = 4
* - QOSTrafficTypeControl = 5
*/
#define OS_SOCK_QOS_TRAFFIC_TYPE_BEST_EFFORT 0
#define OS_SOCK_QOS_TRAFFIC_TYPE_BACKGROUND 1
#define OS_SOCK_QOS_TRAFFIC_TYPE_EXCELLENT_EFFORT 2
#define OS_SOCK_QOS_TRAFFIC_TYPE_AUDIO_VIDEO 3
#define OS_SOCK_QOS_TRAFFIC_TYPE_VOICE 4
#define OS_SOCK_QOS_TRAFFIC_TYPE_CONTROL 5
/* Default DSCP values set by QOSAddSocketToFlow
* 0 : QOSTrafficTypeBestEffort dscp 0
* 1 - 8 : QOSTrafficTypeBackground dscp 8
* 9 - 40 : QOSTrafficTypeExcellentEffort dscp 40
* 41 - 55 : QOSTrafficTypeAudioVideo dscp 40
* 56 : QOSTrafficTypeVoice dscp 56
* 57 - 63 : QOSTrafficTypeControl dscp 56
*/
#define OS_SOCK_BESTEFFORT_DSCP_VALUE 0
#define OS_SOCK_BACKGROUND_DSCP_VALUE 8
#define OS_SOCK_EXCELLENT_EFFORT_DSCP_VALUE 40
#define OS_SOCK_VOICE_DSCP_VALUE 56
/* QOS_NON_ADAPTIVE_FLOW */
#define OS_SOCK_QOS_NON_ADAPTIVE_FLOW 0x00000002
/* QOSSetOutgoingDSCPValue */
#define OS_SOCK_QOS_SET_OUTGOING_DSCP_VALUE 2
static void
os_sockGetTrafficType(
DWORD value,
PLONG trafficType,
PLONG defaultValue)
{
if (value == 0) {
*trafficType = OS_SOCK_QOS_TRAFFIC_TYPE_BEST_EFFORT;
*defaultValue = OS_SOCK_BESTEFFORT_DSCP_VALUE;
} else if (value <= OS_SOCK_BACKGROUND_DSCP_VALUE) {
*trafficType = OS_SOCK_QOS_TRAFFIC_TYPE_BACKGROUND;
*defaultValue = OS_SOCK_BACKGROUND_DSCP_VALUE;
} else if (value <= OS_SOCK_EXCELLENT_EFFORT_DSCP_VALUE) {
*trafficType = OS_SOCK_QOS_TRAFFIC_TYPE_EXCELLENT_EFFORT;
*defaultValue = OS_SOCK_EXCELLENT_EFFORT_DSCP_VALUE;
} else if (value < OS_SOCK_VOICE_DSCP_VALUE) {
*trafficType = OS_SOCK_QOS_TRAFFIC_TYPE_AUDIO_VIDEO;
*defaultValue = OS_SOCK_EXCELLENT_EFFORT_DSCP_VALUE;
} else if (value == OS_SOCK_VOICE_DSCP_VALUE) {
*trafficType = OS_SOCK_QOS_TRAFFIC_TYPE_VOICE;
*defaultValue = OS_SOCK_VOICE_DSCP_VALUE;
} else {
*trafficType = OS_SOCK_QOS_TRAFFIC_TYPE_CONTROL;
*defaultValue = OS_SOCK_VOICE_DSCP_VALUE;
}
}
static os_result
os_sockSetDscpValueWithQos(
os_socket sock,
DWORD value,
BOOL setDscpSupported)
{
os_result result = os_resultSuccess;
QOS_VERSION version;
HANDLE qosHandle = NULL;
ULONG qosFlowId = 0; /* Flow Id must be 0. */
BOOL qosResult;
LONG trafficType;
LONG defaultDscp;
int errNo;
SOCKADDR_IN sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
/* version must be 1.0 */
version.MajorVersion = 1;
version.MinorVersion = 0;
/* Get a handle to the QoS subsystem. */
qosResult = qwaveQOSCreateHandleFunc(&version, &qosHandle);
if (!qosResult) {
char errmsg[1024];
errNo = os_getErrno();
(void)os_strerror_r(errNo, errmsg, sizeof errmsg);
OS_ERROR("os_sockSetDscpValue", 0, "QOSCreateHandle failed: %d %s", errNo, errmsg);
goto err_create_handle;
}
os_sockGetTrafficType(value, &trafficType, &defaultDscp);
/* Add socket to flow. */
qosResult = qwaveQOSAddSocketToFlowFunc(qosHandle, sock, (PSOCKADDR)&sin,
trafficType, OS_SOCK_QOS_NON_ADAPTIVE_FLOW, &qosFlowId);
if (!qosResult) {
char errmsg[1024];
errNo = os_getErrno();
(void)os_strerror_r(errNo, errmsg, sizeof errmsg);
OS_ERROR("os_sockSetDscpValue", 0, "QOSAddSocketToFlow failed: %d %s", errNo, errmsg);
qwaveQOSCloseHandleFunc(qosHandle);
goto err_add_flow;
}
if (value != defaultDscp) {
if (!setDscpSupported) {
OS_WARNING("os_sockSetDscpValue", 0,
"Failed to set diffserv value to %lu value used is %d, not supported on this platform",
value, defaultDscp);
goto err_set_flow;
}
/* Try to set DSCP value. Requires administrative rights to succeed */
qosResult = qwaveQOSSetFlowFunc(qosHandle, qosFlowId, OS_SOCK_QOS_SET_OUTGOING_DSCP_VALUE,
sizeof(value), &value, 0, NULL);
if (!qosResult) {
errNo = os_getErrno();
if ((errNo == ERROR_ACCESS_DENIED) || (errNo == ERROR_ACCESS_DISABLED_BY_POLICY)) {
OS_WARNING("os_sockSetDscpValue", 0,
"Failed to set diffserv value to %lu value used is %d, not enough privileges",
value, defaultDscp);
} else {
char errmsg[1024];
errNo = os_getErrno();
(void)os_strerror_r(errNo, errmsg, sizeof errmsg);
OS_ERROR("os_sockSetDscpValue", 0, "QOSSetFlow failed: %d %s", errNo, errmsg);
}
goto err_set_flow;
}
}
return result;
err_set_flow:
err_add_flow:
err_create_handle:
return result;
}
static os_result
os_sockSetDscpValue(
os_socket sock,
DWORD value)
{
os_result result;
if (IsWindowsVistaOrGreater() && (os_sockLoadQwaveLibrary() == os_resultSuccess)) {
result = os_sockSetDscpValueWithQos(sock, value, IsWindows7OrGreater());
} else {
result = os_sockSetDscpValueWithTos(sock, value);
}
return result;
}
os_result
os_sockSetsockopt(
os_socket s,
int32_t level,
int32_t optname,
const void *optval,
uint32_t optlen)
{
os_result result = os_resultSuccess;
DWORD dwoptval;
if ((level == IPPROTO_IP) && (optname == IP_TOS)) {
dwoptval = *((unsigned char *)optval);
if (dwoptval != 0) {
result = os_sockSetDscpValue(s, dwoptval);
}
} else if ((optname == IP_MULTICAST_TTL) || (optname == IP_MULTICAST_LOOP)) {
/* On win32 IP_MULTICAST_TTL and IP_MULTICAST_LOOP take DWORD * param
rather than char * */
dwoptval = *((unsigned char *)optval);
optval = &dwoptval;
optlen = sizeof( DWORD );
if (setsockopt(s, level, optname, optval, (int)optlen) == SOCKET_ERROR) {
result = os_resultFail;
}
} else {
if (setsockopt(s, level, optname, optval, (int)optlen) == SOCKET_ERROR) {
result = os_resultFail;
}
}
return result;
}
os_result
os_sockSetNonBlocking(
os_socket s,
bool nonblock)
{
int result;
u_long mode;
os_result r;
/* If mode = 0, blocking is enabled,
* if mode != 0, non-blocking is enabled. */
mode = nonblock ? 1 : 0;
result = ioctlsocket(s, FIONBIO, &mode);
if (result != SOCKET_ERROR){
r = os_resultSuccess;
} else {
switch(os_getErrno()){
case WSAEINPROGRESS:
r = os_resultBusy;
break;
case WSAENOTSOCK:
r = os_resultInvalid;
break;
case WSANOTINITIALISED:
OS_FATAL("os_sockSetNonBlocking", 0, "Socket-module not initialised; ensure os_socketModuleInit is performed before using the socket module.");
default:
r = os_resultFail;
break;
}
}
return r;
}
os_result
os_sockFree(
os_socket s)
{
os_result result = os_resultSuccess;
if (closesocket(s) == -1) {
result = os_resultFail;
}
return result;
}
int32_t
os__sockSelect(
fd_set *readfds,
fd_set *writefds,
fd_set *errorfds,
os_time *timeout)
{
struct timeval t;
int r;
t.tv_sec = (long)timeout->tv_sec;
t.tv_usec = (long)(timeout->tv_nsec / 1000);
r = select(-1, readfds, writefds, errorfds, &t);
return r;
}
static unsigned int
getInterfaceFlags(PIP_ADAPTER_ADDRESSES pAddr)
{
unsigned int flags = 0;
if (pAddr->OperStatus == IfOperStatusUp) {
flags |= IFF_UP;
}
if (pAddr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
flags |= IFF_LOOPBACK;
}
if (!(pAddr->Flags & IP_ADAPTER_NO_MULTICAST)) {
flags |= IFF_MULTICAST;
}
switch (pAddr->IfType) {
case IF_TYPE_ETHERNET_CSMACD:
case IF_TYPE_IEEE80211:
case IF_TYPE_IEEE1394:
case IF_TYPE_ISO88025_TOKENRING:
flags |= IFF_BROADCAST;
break;
default:
flags |= IFF_POINTTOPOINT;
break;
}
return flags;
}
static os_result
addressToIndexAndMask(struct sockaddr *addr, unsigned int *ifIndex, struct sockaddr *mask )
{
os_result result = os_resultSuccess;
bool found = FALSE;
PMIB_IPADDRTABLE pIPAddrTable = NULL;
DWORD dwSize = 0;
DWORD i;
int errNo;
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
pIPAddrTable = (MIB_IPADDRTABLE *) os_malloc(dwSize);
if (pIPAddrTable != NULL) {
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) != NO_ERROR) {
errNo = os_getErrno();
OS_ERROR("addressToIndexAndMask", 0, "GetIpAddrTable failed: %d", errNo);
result = os_resultFail;
}
} else {
OS_ERROR("addressToIndexAndMask", 0, "Failed to allocate %lu bytes for IP address table", dwSize);
result = os_resultFail;
}
} else {
errNo = os_getErrno();
OS_ERROR("addressToIndexAndMask", 0, "GetIpAddrTable failed: %d", errNo);
result = os_resultFail;
}
if (result == os_resultSuccess) {
for (i = 0; !found && i < pIPAddrTable->dwNumEntries; i++ ) {
if (((struct sockaddr_in* ) addr )->sin_addr.s_addr == pIPAddrTable->table[i].dwAddr) {
*ifIndex = pIPAddrTable->table[i].dwIndex;
((struct sockaddr_in*) mask)->sin_addr.s_addr= pIPAddrTable->table[i].dwMask;
found = TRUE;
}
}
}
if (pIPAddrTable) {
os_free(pIPAddrTable);
}
if (!found) {
result = os_resultFail;
}
return result;
}
#define MAX_INTERFACES 64
#define INTF_MAX_NAME_LEN 16
os_result
os_sockQueryInterfaces(
os_ifAttributes *ifList,
unsigned int listSize,
unsigned int *validElements)
{
os_result result = os_resultSuccess;
DWORD filter;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
PIP_ADAPTER_ADDRESSES pCurrAddress = NULL;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
unsigned long outBufLen = WORKING_BUFFER_SIZE;
int retVal;
int iterations = 0;
int listIndex = 0;
filter = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
do {
pAddresses = (IP_ADAPTER_ADDRESSES *) os_malloc(outBufLen);
if (!pAddresses) {
OS_ERROR("os_sockQueryInterfaces", 0, "Failed to allocate %lu bytes for Adapter addresses", outBufLen);
return os_resultFail;
}
retVal = GetAdaptersAddresses(AF_INET, filter, NULL, pAddresses, &outBufLen);
if (retVal == ERROR_BUFFER_OVERFLOW) {
os_free(pAddresses);
pAddresses = NULL;
outBufLen <<= 1; /* double the buffer just to be save.*/
} else {
break;
}
iterations++;
} while ((retVal == ERROR_BUFFER_OVERFLOW) && (iterations < MAX_TRIES));
if (retVal != ERROR_SUCCESS) {
if (pAddresses) {
os_free(pAddresses);
pAddresses = NULL;
}
OS_ERROR("os_sockQueryInterfaces", 0, "Failed to GetAdaptersAddresses");
return os_resultFail;
}
for (pCurrAddress = pAddresses; pCurrAddress; pCurrAddress = pCurrAddress->Next) {
IP_ADAPTER_PREFIX *firstPrefix = NULL;
if (pCurrAddress->Length >= sizeof(IP_ADAPTER_ADDRESSES)) {
firstPrefix = pCurrAddress->FirstPrefix;
}
if (pCurrAddress->OperStatus != IfOperStatusUp) {
continue;
}
for (pUnicast = pCurrAddress->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) {
unsigned int ipv4Index;
struct sockaddr_in ipv4Netmask;
if (pUnicast->Address.lpSockaddr->sa_family != AF_INET) {
continue;
}
ipv4Index = 0;
memset(&ipv4Netmask, 0, sizeof(ipv4Netmask));
if (addressToIndexAndMask((struct sockaddr *) pUnicast->Address.lpSockaddr,
&ipv4Index, (struct sockaddr *) &ipv4Netmask) != os_resultSuccess) {
continue;
}
(void)snprintf(ifList[listIndex].name, OS_IFNAMESIZE, "%wS", pCurrAddress->FriendlyName);
/* Get interface flags. */
ifList[listIndex].flags = getInterfaceFlags(pCurrAddress);
ifList[listIndex].interfaceIndexNo = ipv4Index;
memcpy(&ifList[listIndex].address, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
memcpy(&ifList[listIndex].broadcast_address, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
memcpy(&ifList[listIndex].network_mask, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
((struct sockaddr_in *)(&(ifList[listIndex].broadcast_address)))->sin_addr.s_addr =
((struct sockaddr_in *)(&(ifList[listIndex].address)))->sin_addr.s_addr | ~(ipv4Netmask.sin_addr.s_addr);
((struct sockaddr_in *)&(ifList[listIndex].network_mask))->sin_addr.s_addr = ipv4Netmask.sin_addr.s_addr;
listIndex++;
}
}
for (pCurrAddress = pAddresses; pCurrAddress; pCurrAddress = pCurrAddress->Next) {
if (pCurrAddress->OperStatus != IfOperStatusUp) {
(void)snprintf(ifList[listIndex].name, OS_IFNAMESIZE, "%wS", pCurrAddress->FriendlyName);
/* Get interface flags. */
ifList[listIndex].flags = getInterfaceFlags(pCurrAddress);
ifList[listIndex].interfaceIndexNo = 0;
memset (&ifList[listIndex].address, 0, sizeof(ifList[listIndex].address));
memset (&ifList[listIndex].broadcast_address, 0, sizeof (ifList[listIndex].broadcast_address));
memset (&ifList[listIndex].network_mask, 0, sizeof (ifList[listIndex].network_mask));
listIndex++;
}
}
if (pAddresses) {
os_free(pAddresses);
}
*validElements = listIndex;
return result;
}
os_result
os_sockQueryIPv6Interfaces (
os_ifAttributes *ifList,
unsigned int listSize,
unsigned int *validElements)
{
os_result result = os_resultSuccess;
ULONG filter;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
PIP_ADAPTER_ADDRESSES pCurrAddress = NULL;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
ULONG outBufLen = WORKING_BUFFER_SIZE;
ULONG retVal;
int iterations = 0;
int listIndex = 0;
filter = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
do {
pAddresses = (IP_ADAPTER_ADDRESSES *) os_malloc(outBufLen);
if (!pAddresses) {
OS_ERROR("os_sockQueryIPv6Interfaces", 0, "Failed to allocate %lu bytes for Adapter addresses", outBufLen);
return os_resultFail;
}
retVal = GetAdaptersAddresses(AF_INET6, filter, NULL, pAddresses, &outBufLen);
if (retVal == ERROR_BUFFER_OVERFLOW) {
os_free(pAddresses);
pAddresses = NULL;
outBufLen <<= 1; /* double the buffer just to be save.*/
} else {
break;
}
iterations++;
} while ((retVal == ERROR_BUFFER_OVERFLOW) && (iterations < MAX_TRIES));
if (retVal != ERROR_SUCCESS) {
if (pAddresses) {
os_free(pAddresses);
pAddresses = NULL;
}
OS_ERROR("os_sockQueryIPv6Interfaces", 0, "Failed to GetAdaptersAddresses");
return os_resultFail;
}
for (pCurrAddress = pAddresses; pCurrAddress; pCurrAddress = pCurrAddress->Next) {
DWORD ipv6IfIndex = 0;
IP_ADAPTER_PREFIX *firstPrefix = NULL;
if (pCurrAddress->Length >= sizeof(IP_ADAPTER_ADDRESSES)) {
ipv6IfIndex = pCurrAddress->Ipv6IfIndex;
firstPrefix = pCurrAddress->FirstPrefix;
}
if (((ipv6IfIndex == 1) && (pCurrAddress->IfType != IF_TYPE_SOFTWARE_LOOPBACK)) || (pCurrAddress->IfType == IF_TYPE_TUNNEL)) {
continue;
}
if (pCurrAddress->OperStatus != IfOperStatusUp) {
continue;
}
for (pUnicast = pCurrAddress->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) {
IP_ADAPTER_PREFIX *prefix;
IN6_ADDR mask;
struct sockaddr_in6 *sa6;
struct sockaddr_in6 ipv6Netmask;
if (pUnicast->Address.lpSockaddr->sa_family != AF_INET6) {
continue;
}
(void)snprintf(ifList[listIndex].name, OS_IFNAMESIZE, "%wS", pCurrAddress->FriendlyName);
/* Get interface flags. */
ifList[listIndex].flags = getInterfaceFlags(pCurrAddress);
ifList[listIndex].interfaceIndexNo = (uint32_t) pCurrAddress->Ipv6IfIndex;
memcpy(&ifList[listIndex].address, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
memcpy(&ifList[listIndex].broadcast_address, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
memcpy(&ifList[listIndex].network_mask, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
sa6 = (struct sockaddr_in6 *)&ifList[listIndex].network_mask;
memset(&sa6->sin6_addr.s6_addr, 0xFF, sizeof(sa6->sin6_addr.s6_addr));
for (prefix = firstPrefix; prefix; prefix = prefix->Next) {
unsigned int l, i;
if ((prefix->PrefixLength == 0) || (prefix->PrefixLength > 128) ||
(pUnicast->Address.iSockaddrLength != prefix->Address.iSockaddrLength) ||
(memcmp(pUnicast->Address.lpSockaddr, prefix->Address.lpSockaddr, pUnicast->Address.iSockaddrLength) == 0)){
continue;
}
memset(&ipv6Netmask, 0, sizeof(ipv6Netmask));
ipv6Netmask.sin6_family = AF_INET6;
l = prefix->PrefixLength;
for (i = 0; l > 0; l -= 8, i++) {
ipv6Netmask.sin6_addr.s6_addr[i] = (l >= 8) ? 0xFF : ((0xFF << (8-l)) & 0xFF);
}
for (i = 0; i < 16; i++) {
mask.s6_addr[i] =
((struct sockaddr_in6 *)pUnicast->Address.lpSockaddr)->sin6_addr.s6_addr[i] & ipv6Netmask.sin6_addr.s6_addr[i];
}
if (memcmp(((struct sockaddr_in6 *)prefix->Address.lpSockaddr)->sin6_addr.s6_addr,
mask.s6_addr, sizeof(ipv6Netmask.sin6_addr)) == 0) {
memcpy(&sa6->sin6_addr.s6_addr, &ipv6Netmask.sin6_addr.s6_addr, sizeof(sa6->sin6_addr.s6_addr));
}
}
listIndex++;
}
}
for (pCurrAddress = pAddresses; pCurrAddress; pCurrAddress = pCurrAddress->Next) {
if (pCurrAddress->OperStatus != IfOperStatusUp) {
(void) snprintf(ifList[listIndex].name, OS_IFNAMESIZE, "%wS", pCurrAddress->FriendlyName);
/* Get interface flags. */
ifList[listIndex].flags = getInterfaceFlags(pCurrAddress);
ifList[listIndex].interfaceIndexNo = 0;
memset (&ifList[listIndex].address, 0, sizeof(ifList[listIndex].address));
memset (&ifList[listIndex].broadcast_address, 0, sizeof (ifList[listIndex].broadcast_address));
memset (&ifList[listIndex].network_mask, 0, sizeof (ifList[listIndex].network_mask));
listIndex++;
}
}
if (pAddresses) {
os_free(pAddresses);
}
*validElements = listIndex;
return result;
}
#undef MAX_INTERFACES

View file

@ -0,0 +1,539 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include "os/os.h"
#include "../snippets/code/os_stdlib_getopt.c"
#include "../snippets/code/os_stdlib_bsearch.c"
#include "../snippets/code/os_stdlib_strtod.c"
#include "../snippets/code/os_stdlib_strtol.c"
#include "../snippets/code/os_stdlib_strtok_r.c"
static int32_t
os__ensurePathExists(
_In_z_ const char* dir_name);
/**
* \brief create a directory with default
* security descriptor. The mode parameter
* is ignored for this Operating System.
*
*/
int32_t
os_mkdir(
const char *path,
os_mode_t mode)
{
int32_t result = 0;
if (CreateDirectory(path, NULL)) {
result = 0;
}
else {
result = -1;
}
return result;
}
os_result
os_gethostname(
char *hostname,
size_t buffersize)
{
os_result result;
char hostnamebuf[MAXHOSTNAMELEN];
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(OS_SOCK_VERSION, OS_SOCK_REVISION);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
OS_FATAL("os_gethostname", 0, "WSAStartup failed, no compatible socket implementation available");
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
return os_resultFail;
}
if (gethostname(hostnamebuf, MAXHOSTNAMELEN) == 0) {
if ((strlen(hostnamebuf) + 1) > (size_t)buffersize) {
result = os_resultFail;
}
else {
strcpy(hostname, hostnamebuf);
result = os_resultSuccess;
}
}
else {
result = os_resultFail;
}
return result;
}
#pragma warning( disable : 4996 )
_Ret_opt_z_ const char *
os_getenv(
_In_z_ const char *variable)
{
const char * result;
result = getenv(variable);
return result;
}
#pragma warning( default : 4996 )
os_result
os_putenv(
char *variable_definition)
{
os_result result;
if (_putenv(variable_definition) == 0) {
result = os_resultSuccess;
}
else {
result = os_resultFail;
}
return result;
}
const char *
os_fileSep(void)
{
return "\\";
}
const char *
os_pathSep(void)
{
return ";";
}
os_result
os_access(
const char *file_path,
int32_t permission)
{
struct _stat statbuf;
os_result result;
result = os_resultFail;
if (file_path) {
if (_stat(file_path, &statbuf) == 0) {
if ((statbuf.st_mode & permission) == permission) {
result = os_resultSuccess;
}
}
}
return result;
}
char *
os_rindex(
const char *s,
int c)
{
char *last = NULL;
while (*s) {
if (*s == c) {
last = (char *)s;
}
s++;
}
return last;
}
_Ret_z_
_Check_return_
char *
os_strdup(
_In_z_ const char *s1)
{
size_t len;
char *dup;
len = strlen(s1) + 1;
dup = os_malloc(len);
memcpy(dup, s1, len);
return dup;
}
char *
os_strsep(char **str, const char *sep)
{
char *ret;
if (**str == '\0')
return 0;
ret = *str;
while (**str && strchr(sep, **str) == 0)
(*str)++;
if (**str != '\0')
{
**str = '\0';
(*str)++;
}
return ret;
}
#pragma warning( disable : 4996 )
int
os_vfprintfnosigpipe(
FILE *file,
const char *format,
va_list args)
{
return vfprintf(file, format, args);
}
#pragma warning( default : 4996 )
int
os_strcasecmp(
const char *s1,
const char *s2)
{
int cr;
while (*s1 && *s2) {
cr = tolower(*s1) - tolower(*s2);
if (cr) {
return cr;
}
s1++;
s2++;
}
cr = tolower(*s1) - tolower(*s2);
return cr;
}
int
os_strncasecmp(
const char *s1,
const char *s2,
size_t n)
{
int cr = 0;
while (*s1 && *s2 && n) {
cr = tolower(*s1) - tolower(*s2);
if (cr) {
return cr;
}
s1++;
s2++;
n--;
}
if (n) {
cr = tolower(*s1) - tolower(*s2);
}
return cr;
}
os_result
os_stat(
const char *path,
struct os_stat *buf)
{
os_result result;
struct _stat32 _buf;
int r;
r = _stat32(path, &_buf);
if (r == 0) {
buf->stat_mode = _buf.st_mode;
buf->stat_size = _buf.st_size;
buf->stat_mtime.tv_sec = _buf.st_mtime;
buf->stat_mtime.tv_nsec = 0;
result = os_resultSuccess;
}
else {
result = os_resultFail;
}
return result;
}
os_result os_remove(const char *pathname)
{
return (remove(pathname) == 0) ? os_resultSuccess : os_resultFail;
}
os_result os_rename(const char *oldpath, const char *newpath)
{
(void)os_remove(newpath);
return (rename(oldpath, newpath) == 0) ? os_resultSuccess : os_resultFail;
}
/* The result of os_fileNormalize should be freed with os_free */
_Ret_z_
_Must_inspect_result_
char *
os_fileNormalize(
_In_z_ const char *filepath)
{
char *norm;
const char *fpPtr;
char *normPtr;
norm = os_malloc(strlen(filepath) + 1);
fpPtr = filepath;
normPtr = norm;
while (*fpPtr != '\0') {
*normPtr = *fpPtr;
if ((*fpPtr == '/') || (*fpPtr == '\\')) {
*normPtr = OS_FILESEPCHAR;
normPtr++;
} else {
if (*fpPtr != '\"') {
normPtr++;
}
}
fpPtr++;
}
*normPtr = '\0';
return norm;
}
os_result
os_fsync(
FILE *fHandle)
{
os_result r;
if (FlushFileBuffers((HANDLE)fHandle)) {
r = os_resultSuccess;
}
else {
r = os_resultFail;
}
return r;
}
_Ret_opt_z_ const char *
os_getTempDir(void)
{
const char * dir_name = NULL;
dir_name = os_getenv("OSPL_TEMP");
/* if OSPL_TEMP is not defined use the TEMP variable */
if (dir_name == NULL || (strcmp(dir_name, "") == 0)) {
dir_name = os_getenv("TEMP");
}
/* if TEMP is not defined use the TMP variable */
if (dir_name == NULL || (strcmp(dir_name, "") == 0)) {
dir_name = os_getenv("TMP");
}
/* Now we need to verify if we found a temp directory path, and if we did
* we have to make sure all the (sub)directories in the path exist.
* This is needed to prevent any other operations from using the directory
* path while it doesn't exist and therefore running into errors.
*/
if (dir_name == NULL || (strcmp(dir_name, "") == 0)) {
OS_ERROR("os_getTempDir", 0,
"Could not retrieve temporary directory path - "
"neither of environment variables TEMP, TMP, OSPL_TEMP were set");
}
else if (os__ensurePathExists(dir_name) != 0)
{
OS_ERROR("os_getTempDir", 0,
"Could not ensure all (sub)directories of the temporary directory\n"
"path '%s' exist.\n"
"This has consequences for the ability of OpenSpliceDDS to run\n"
"properly, as the directory path must be accessible to create\n"
"database and key files in. Without this ability OpenSpliceDDS can\n"
"not start.\n",
dir_name);
}
return dir_name;
}
int32_t
os__ensurePathExists(
_In_z_ const char* dir_name)
{
char* tmp;
char* ptr;
char ptrTmp;
struct os_stat statBuf;
os_result status;
int32_t result = 0;
int32_t cont = 1;
tmp = os_strdup(dir_name);
for (ptr = tmp; cont; ptr++)
{
if (*ptr == '\\' || *ptr == '/' || *ptr == '\0')
{
ptrTmp = ptr[0];
ptr[0] = '\0';
status = os_stat(tmp, &statBuf);
if (status != os_resultSuccess)
{
os_mkdir(tmp, 0);
status = os_stat(tmp, &statBuf);
}
if (!OS_ISDIR(statBuf.stat_mode))
{
if ((strlen(tmp) == 2) && (tmp[1] == ':')) {
/*This is a device like for instance: 'C:'*/
}
else
{
OS_ERROR("os_ensurePathExists", 0,
"Unable to create directory '%s' within path '%s'. Errorcode: %d",
tmp,
dir_name,
os_getErrno());
result = -1;
}
}
ptr[0] = ptrTmp;
}
if (*ptr == '\0' || result == -1)
{
cont = 0;
}
}
os_free(tmp);
return result;
}
#pragma warning( disable : 4996 )
int
os_vsnprintf(
char *str,
size_t size,
const char *format,
va_list args)
{
int result;
/* Return-values of _vsnprintf don't match the output on posix platforms,
* so this extra code is needed to bring it in accordance. It is made to
* behave as follows (copied from printf man-pages):
* Upon successful return, this function returns the number of characters
* printed (not including the trailing '\0' used to end output to strings).
* The function does not write more than size bytes (including the trailing
* '\0'). If the output was truncated due to this limit then the return
* value is the number of characters (not including the trailing '\0') which
* would have been written to the final string if enough space had been
* available. Thus, a return value of size or more means that the output was
* truncated. If an output error is encountered, a negative value is
* returned. */
result = _vsnprintf(str, size, format, args);
if (result == -1) {
/* vsnprintf will return the length that would be written for the given
* formatting arguments if invoked with NULL and 0 as the first two arguments.
*/
result = _vsnprintf(NULL, 0, format, args);
}
/* Truncation occurred, so we need to guarantee that the string is NULL-
* terminated. */
if ((size_t)result >= size) {
str[size - 1] = '\0';
}
return result;
}
#pragma warning( default : 4996 )
#if _MSC_VER < 1900
int
snprintf(
char *s,
size_t size,
const char *format,
...)
{
int result;
va_list args;
va_start(args, format);
result = os_vsnprintf(s, size, format, args);
va_end(args);
return result;
}
#endif
ssize_t os_write(
_In_ int fd,
_In_reads_bytes_(count) void const* buf,
_In_ size_t count)
{
return _write(fd, buf, (unsigned int)count); /* Type casting is done for the warning of conversion from 'size_t' to 'unsigned int', which may cause possible loss of data */
}
void os_flockfile(FILE *file)
{
_lock_file (file);
}
void os_funlockfile(FILE *file)
{
_unlock_file (file);
}
int os_getopt(
_In_range_(0, INT_MAX) int argc,
_In_reads_z_(argc) char **argv,
_In_z_ const char *opts)
{
return getopt(argc, argv, opts);
}
void os_set_opterr(_In_range_(0, INT_MAX) int err)
{
opterr = err;
}
int os_get_opterr(void)
{
return opterr;
}
void os_set_optind(_In_range_(0, INT_MAX) int index)
{
optind = index;
}
int os_get_optind(void)
{
return optind;
}
int os_get_optopt(void)
{
return optopt;
}
char * os_get_optarg(void)
{
return optarg;
}

View file

@ -0,0 +1,276 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include "os/os.h"
void os_mutexInit(
_Out_ os_mutex *mutex)
{
assert(mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert(mutex->signature != OS_MUTEX_MAGIC_SIG);
#endif
InitializeSRWLock(&mutex->lock);
#ifdef OSPL_STRICT_MEM
mutex->signature = OS_MUTEX_MAGIC_SIG;
#endif
}
void os_mutexDestroy(
_Inout_ _Post_invalid_ os_mutex *mutex)
{
assert(mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert(mutex->signature == OS_MUTEX_MAGIC_SIG);
mutex->signature = 0;
#endif
}
_Acquires_nonreentrant_lock_(&mutex->lock)
void os_mutexLock(
_Inout_ os_mutex *mutex)
{
assert(mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert(mutex->signature == OS_MUTEX_MAGIC_SIG);
#endif
AcquireSRWLockExclusive(&mutex->lock);
}
_Check_return_
_When_(return == os_resultSuccess, _Acquires_nonreentrant_lock_(&mutex->lock))
os_result os_mutexLock_s(
_Inout_ os_mutex *mutex)
{
os_mutexLock(mutex);
return os_resultSuccess;
}
_Check_return_
_When_(return == os_resultSuccess, _Acquires_nonreentrant_lock_(&mutex->lock))
os_result
os_mutexTryLock(
_Inout_ os_mutex *mutex)
{
assert(mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert(mutex->signature == OS_MUTEX_MAGIC_SIG);
#endif
return TryAcquireSRWLockExclusive(&mutex->lock) ? os_resultSuccess : os_resultBusy;
}
_Releases_nonreentrant_lock_(&mutex->lock)
void os_mutexUnlock(
_Inout_ os_mutex *mutex)
{
assert(mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert(mutex->signature == OS_MUTEX_MAGIC_SIG);
#endif
ReleaseSRWLockExclusive(&mutex->lock);
}
void os_condInit(
_Out_ os_cond *cond,
_In_ os_mutex *dummymtx)
{
assert(cond != NULL);
assert(dummymtx != NULL);
#ifdef OSPL_STRICT_MEM
assert(cond->signature != OS_COND_MAGIC_SIG);
#endif
(void)dummymtx;
InitializeConditionVariable(&cond->cond);
#ifdef OSPL_STRICT_MEM
cond->signature = OS_COND_MAGIC_SIG;
#endif
}
void os_condDestroy(
_Inout_ _Post_invalid_ os_cond *cond)
{
assert(cond != NULL);
#ifdef OSPL_STRICT_MEM
assert(cond->signature == OS_COND_MAGIC_SIG);
cond->signature = 0;
#endif
}
void os_condWait(os_cond *cond, os_mutex *mutex)
{
assert(cond != NULL);
assert(mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert(cond->signature == OS_COND_MAGIC_SIG);
assert(mutex->signature == OS_MUTEX_MAGIC_SIG);
#endif
if (!SleepConditionVariableSRW(&cond->cond, &mutex->lock, INFINITE, 0)) {
abort();
}
}
os_result os_condTimedWait(os_cond *cond, os_mutex *mutex, const os_time *time)
{
DWORD timems;
assert(cond != NULL);
assert(mutex != NULL);
#ifdef OSPL_STRICT_MEM
assert(cond->signature == OS_COND_MAGIC_SIG);
assert(mutex->signature == OS_MUTEX_MAGIC_SIG);
#endif
timems = time->tv_sec * 1000 + (time->tv_nsec + 999999999) / 1000000;
if (SleepConditionVariableSRW(&cond->cond, &mutex->lock, timems, 0))
return os_resultSuccess;
else if (GetLastError() != ERROR_TIMEOUT)
abort();
else if (timems != INFINITE)
return os_resultTimeout;
else
return os_resultSuccess;
}
void os_condSignal(os_cond *cond)
{
assert(cond != NULL);
#ifdef OSPL_STRICT_MEM
assert(cond->signature == OS_COND_MAGIC_SIG);
#endif
WakeConditionVariable(&cond->cond);
}
void os_condBroadcast(os_cond *cond)
{
assert(cond != NULL);
#ifdef OSPL_STRICT_MEM
assert(cond->signature == OS_COND_MAGIC_SIG);
#endif
WakeAllConditionVariable(&cond->cond);
}
void os_rwlockInit(_Out_ os_rwlock *rwlock)
{
assert(rwlock);
#ifdef OSPL_STRICT_MEM
assert(rwlock->signature != OS_RWLOCK_MAGIC_SIG);
#endif
InitializeSRWLock(&rwlock->lock);
rwlock->state = 0;
#ifdef OSPL_STRICT_MEM
rwlock->signature = OS_RWLOCK_MAGIC_SIG;
#endif
}
void os_rwlockDestroy(_Inout_ _Post_invalid_ os_rwlock *rwlock)
{
assert(rwlock);
#ifdef OSPL_STRICT_MEM
assert(rwlock->signature != OS_RWLOCK_MAGIC_SIG);
rwlock->signature = 0;
#endif
}
void os_rwlockRead(os_rwlock *rwlock)
{
assert(rwlock);
#ifdef OSPL_STRICT_MEM
assert(rwlock->signature != OS_RWLOCK_MAGIC_SIG);
#endif
AcquireSRWLockShared(&rwlock->lock);
rwlock->state = 1;
}
void os_rwlockWrite(os_rwlock *rwlock)
{
assert(rwlock);
#ifdef OSPL_STRICT_MEM
assert(rwlock->signature != OS_RWLOCK_MAGIC_SIG);
#endif
AcquireSRWLockExclusive(&rwlock->lock);
rwlock->state = -1;
}
os_result os_rwlockTryRead(os_rwlock *rwlock)
{
assert(rwlock);
#ifdef OSPL_STRICT_MEM
assert(rwlock->signature != OS_RWLOCK_MAGIC_SIG);
#endif
if (TryAcquireSRWLockShared(&rwlock->lock)) {
rwlock->state = 1;
return os_resultSuccess;
}
else {
return os_resultBusy;
}
}
os_result os_rwlockTryWrite(os_rwlock *rwlock)
{
assert(rwlock);
#ifdef OSPL_STRICT_MEM
assert(rwlock->signature != OS_RWLOCK_MAGIC_SIG);
#endif
if (TryAcquireSRWLockExclusive(&rwlock->lock)) {
rwlock->state = -1;
return os_resultSuccess;
}
else {
return os_resultBusy;
}
}
void os_rwlockUnlock(os_rwlock *rwlock)
{
assert(rwlock);
#ifdef OSPL_STRICT_MEM
assert(rwlock->signature != OS_RWLOCK_MAGIC_SIG);
#endif
assert(rwlock->state != 0);
if (rwlock->state > 0) {
ReleaseSRWLockShared(&rwlock->lock);
}
else {
ReleaseSRWLockExclusive(&rwlock->lock);
}
}
struct os__onceWrapper {
os_once_fn init_fn;
};
static BOOL WINAPI
os__onceWrapper(
_Inout_ PINIT_ONCE InitOnce,
_Inout_opt_ PVOID Parameter,
_Outptr_opt_result_maybenull_ PVOID *Context)
{
struct os__onceWrapper *wrap = (struct os__onceWrapper *) Parameter;
/* Only to be invoked from os_once, so assume inputs to be as
* expected instead of implementing checks officially needed to
* fulfill SAL. */
_Analysis_assume_(wrap);
_Analysis_assume_(Context == NULL);
wrap->init_fn();
return TRUE;
}
void
os_once(
_Inout_ os_once_t *control,
_In_ os_once_fn init_fn)
{
struct os__onceWrapper wrap = { .init_fn = init_fn };
(void) InitOnceExecuteOnce(control, &os__onceWrapper, &wrap, NULL);
}

View file

@ -0,0 +1,605 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file os/win32/code/os_thread.c
* \brief WIN32 thread management
*
* Implements thread management for WIN32
*/
#include "os/os.h"
#include <assert.h>
typedef struct {
char *threadName;
void *arguments;
os_threadRoutine startRoutine;
} os_threadContext;
static DWORD tlsIndex;
static os_result
os_threadMemInit(void)
{
void **tlsMemArray;
BOOL result;
tlsMemArray = os_malloc (sizeof(void *) * OS_THREAD_MEM_ARRAY_SIZE);
memset(tlsMemArray, 0, sizeof(void *) * OS_THREAD_MEM_ARRAY_SIZE);
result = TlsSetValue(tlsIndex, tlsMemArray);
if (!result) {
//OS_INIT_FAIL("os_threadMemInit: failed to set TLS");
goto err_setTls;
}
return os_resultSuccess;
err_setTls:
os_free(tlsMemArray);
return os_resultFail;
}
static void
os_threadMemExit(void)
{
void **tlsMemArray;
int i;
tlsMemArray = (void **)TlsGetValue(tlsIndex);
if (tlsMemArray != NULL) {
/*The compiler doesn't realize that tlsMemArray has always size OS_THREAD_MEM_ARRAY_SIZE. */
#pragma warning(push)
#pragma warning(disable: 6001)
for (i = 0; i < OS_THREAD_MEM_ARRAY_SIZE; i++) {
if (tlsMemArray[i] != NULL) {
os_free(tlsMemArray[i]);
}
}
#pragma warning(pop)
os_free(tlsMemArray);
TlsSetValue(tlsIndex, NULL);
}
}
/** \brief Initialize the thread module
*
* \b os_threadModuleInit initializes the thread module for the
* calling process
*/
os_result
os_threadModuleInit(void)
{
if ((tlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) {
//OS_INIT_FAIL("os_threadModuleInit: could not allocate thread-local memory (System Error Code: %i)", os_getErrno());
goto err_tlsAllocFail;
}
return os_resultSuccess;
err_tlsAllocFail:
return os_resultFail;
}
/** \brief Deinitialize the thread module
*
* \b os_threadModuleExit deinitializes the thread module for the
* calling process
*/
void
os_threadModuleExit(void)
{
void **tlsMemArray = TlsGetValue(tlsIndex);
if (tlsMemArray != NULL) {
os_free(tlsMemArray);
}
TlsFree(tlsIndex);
}
const DWORD MS_VC_EXCEPTION=0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
/** Must be 0x1000. */
DWORD dwType;
/** Pointer to name (in user addr space). */
LPCSTR szName;
/** Thread ID (-1=caller thread). */
DWORD dwThreadID;
/** Reserved for future use, must be zero. */
DWORD dwFlags;
} THREADNAME_INFO;
#pragma pack(pop)
/**
* Usage: os_threadSetThreadName (-1, "MainThread");
* @pre ::
* @see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
* @param dwThreadID The thread ID that is to be named, -1 for 'self'
* @param threadName The name to apply.
*/
void os_threadSetThreadName( DWORD dwThreadID, char* threadName)
{
char* tssThreadName;
#ifndef WINCE /* When we merge the code, this first bit won't work there */
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = threadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
/* Empty try/except that catches everything is done on purpose to set the
* thread name. This code equals the official example on msdn, including
* the warning suppressions. */
#pragma warning(push)
#pragma warning(disable: 6320 6322)
__try
{
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
#pragma warning(pop)
#endif /* No reason why the restshouldn't though */
tssThreadName = (char *)os_threadMemGet(OS_THREAD_NAME);
if (tssThreadName == NULL)
{
tssThreadName = (char *)os_threadMemMalloc(OS_THREAD_NAME, (strlen(threadName) + 1));
strcpy(tssThreadName, threadName);
}
}
/** \brief Wrap thread start routine
*
* \b os_startRoutineWrapper wraps a threads starting routine.
* before calling the user routine. It tries to set a thread name
* that will be visible if the process is running under the MS
* debugger.
*/
static uint32_t
os_startRoutineWrapper(
_In_ _Post_invalid_ void *threadContext)
{
os_threadContext *context = threadContext;
uint32_t resultValue = 0;
os_threadId id;
/* allocate an array to store thread private memory references */
os_threadMemInit();
/* Set a thread name that will take effect if the process is running under a debugger */
os_threadSetThreadName(-1, context->threadName);
id.threadId = GetCurrentThreadId();
id.handle = GetCurrentThread();
/* Call the user routine */
resultValue = context->startRoutine(context->arguments);
os_report_stack_free();
/* Free the thread context resources, arguments is responsibility */
/* for the caller of os_threadCreate */
os_free (context->threadName);
os_free (context);
/* deallocate the array to store thread private memory references */
os_threadMemExit ();
/* return the result of the user routine */
return resultValue;
}
/** \brief Create a new thread
*
* \b os_threadCreate creates a thread by calling \b CreateThread.
*/
os_result
os_threadCreate(
_Out_ os_threadId *threadId,
_In_z_ const char *name,
_In_ const os_threadAttr *threadAttr,
_In_ os_threadRoutine start_routine,
_In_opt_ void *arg)
{
HANDLE threadHandle;
DWORD threadIdent;
os_threadContext *threadContext;
int32_t effective_priority;
assert(threadId != NULL);
assert(name != NULL);
assert(threadAttr != NULL);
assert(start_routine != NULL);
/* Take over the thread context: name, start routine and argument */
threadContext = os_malloc(sizeof (*threadContext));
threadContext->threadName = os_strdup(name);
threadContext->startRoutine = start_routine;
threadContext->arguments = arg;
threadHandle = CreateThread(NULL,
(SIZE_T)threadAttr->stackSize,
(LPTHREAD_START_ROUTINE)os_startRoutineWrapper,
(LPVOID)threadContext,
(DWORD)0, &threadIdent);
if (threadHandle == 0) {
OS_WARNING("os_threadCreate", os_getErrno(), "Failed with System Error Code: %i\n", os_getErrno ());
return os_resultFail;
}
fflush(stdout);
threadId->handle = threadHandle;
threadId->threadId = threadIdent;
/* #642 fix (JCM)
* Windows thread priorities are in the range below :
-15 : THREAD_PRIORITY_IDLE
-2 : THREAD_PRIORITY_LOWEST
-1 : THREAD_PRIORITY_BELOW_NORMAL
0 : THREAD_PRIORITY_NORMAL
1 : THREAD_PRIORITY_ABOVE_NORMAL
2 : THREAD_PRIORITY_HIGHEST
15 : THREAD_PRIORITY_TIME_CRITICAL
For realtime threads additional values are allowed : */
/* PROCESS_QUERY_INFORMATION rights required
* to call GetPriorityClass
* Ensure that priorities are effectively in the allowed range depending
* on GetPriorityClass result */
effective_priority = threadAttr->schedPriority;
if (GetPriorityClass(GetCurrentProcess()) == REALTIME_PRIORITY_CLASS) {
if (threadAttr->schedPriority < -7) {
effective_priority = THREAD_PRIORITY_IDLE;
}
if (threadAttr->schedPriority > 6) {
effective_priority = THREAD_PRIORITY_TIME_CRITICAL;
}
} else {
if (threadAttr->schedPriority < THREAD_PRIORITY_LOWEST) {
effective_priority = THREAD_PRIORITY_IDLE;
}
if (threadAttr->schedPriority > THREAD_PRIORITY_HIGHEST) {
effective_priority = THREAD_PRIORITY_TIME_CRITICAL;
}
}
if (SetThreadPriority (threadHandle, effective_priority) == 0) {
OS_INFO("os_threadCreate", os_getErrno(), "SetThreadPriority failed with %i", os_getErrno());
}
/* ES: dds2086: Close handle should not be performed here. Instead the handle
* should not be closed until the os_threadWaitExit(...) call is called.
* CloseHandle (threadHandle);
*/
return os_resultSuccess;
}
/** \brief Return the integer representation of the given thread ID
*
* Possible Results:
* - returns the integer representation of the given thread ID
*/
uintmax_t
os_threadIdToInteger(os_threadId id)
{
return id.threadId;
}
/** \brief Return the thread ID of the calling thread
*
* \b os_threadIdSelf determines the own thread ID by
* calling \b GetCurrentThreadId ().
*/
os_threadId
os_threadIdSelf(
void)
{
os_threadId id;
id.threadId = GetCurrentThreadId();
id.handle = GetCurrentThread(); /* pseudo HANDLE, no need to close it */
return id;
}
/** \brief Wait for the termination of the identified thread
*
* \b os_threadWaitExit wait for the termination of the
* thread \b threadId by calling \b pthread_join. The return
* value of the thread is passed via \b thread_result.
*/
os_result
os_threadWaitExit(
_In_ os_threadId threadId,
_Out_opt_ uint32_t *thread_result)
{
DWORD tr;
DWORD err;
DWORD waitres;
BOOL status;
if(threadId.handle == NULL){
//OS_DEBUG("os_threadWaitExit", "Parameter threadId is null");
return os_resultFail;
}
waitres = WaitForSingleObject(threadId.handle, INFINITE);
if (waitres != WAIT_OBJECT_0) {
err = os_getErrno();
//OS_DEBUG_1("os_threadWaitExit", "WaitForSingleObject Failed %d", err);
return os_resultFail;
}
status = GetExitCodeThread(threadId.handle, &tr);
if (!status) {
err = os_getErrno();
//OS_DEBUG_1("os_threadWaitExit", "GetExitCodeThread Failed %d", err);
return os_resultFail;
}
assert(tr != STILL_ACTIVE);
if (thread_result) {
*thread_result = tr;
}
CloseHandle(threadId.handle);
return os_resultSuccess;
}
/** \brief Figure out the identity of the current thread
*
* Possible Results:
* - returns the actual length of threadIdentity
*/
int
os_threadFigureIdentity(
char *threadIdentity,
uint32_t threadIdentitySize)
{
int size;
char* threadName;
threadName = (char *)os_threadMemGet(OS_THREAD_NAME);
if (threadName != NULL) {
size = snprintf (threadIdentity, threadIdentitySize, "%s 0x%"PRIx32, threadName, GetCurrentThreadId());
} else {
size = snprintf (threadIdentity, threadIdentitySize, "0x%"PRIx32, GetCurrentThreadId());
}
return size;
}
int
os_threadGetThreadName(
char *buffer,
uint32_t length)
{
char *name;
assert (buffer != NULL);
if ((name = os_threadMemGet(OS_THREAD_NAME)) == NULL) {
name = "";
}
return snprintf (buffer, length, "%s", name);
}
/** \brief Allocate thread private memory
*
* Allocate heap memory of the specified \b size and
* relate it to the thread by storing the memory
* reference in an thread specific reference array
* indexed by \b index. If the indexed thread reference
* array location already contains a reference, no
* memory will be allocated and NULL is returned.
*
* Possible Results:
* - returns NULL if
* index < 0 || index >= OS_THREAD_MEM_ARRAY_SIZE
* - returns NULL if
* no sufficient memory is available on heap
* - returns NULL if
* os_threadMemGet (index) returns != NULL
* - returns reference to allocated heap memory
* of the requested size if
* memory is successfully allocated
*/
void *
os_threadMemMalloc(
int32_t index,
size_t size)
{
void **tlsMemArray;
void *threadMemLoc = NULL;
if ((0 <= index) && (index < OS_THREAD_MEM_ARRAY_SIZE)) {
tlsMemArray = (void **)TlsGetValue(tlsIndex);
if (tlsMemArray == NULL) {
os_threadMemInit ();
tlsMemArray = (void **)TlsGetValue(tlsIndex);
}
if (tlsMemArray != NULL) {
if (tlsMemArray[index] == NULL) {
threadMemLoc = os_malloc(size);
tlsMemArray[index] = threadMemLoc;
}
}
}
return threadMemLoc;
}
/** \brief Free thread private memory
*
* Free the memory referenced by the thread reference
* array indexed location. If this reference is NULL,
* or index is invalid, no action is taken.
* The reference is set to NULL after freeing the
* heap memory.
*
* Postcondition:
* - os_threadMemGet (index) = NULL and allocated
* heap memory is freed
*/
void
os_threadMemFree(
int32_t index)
{
void **tlsMemArray;
void *threadMemLoc = NULL;
if ((0 <= index) && (index < OS_THREAD_MEM_ARRAY_SIZE)) {
tlsMemArray = (void **)TlsGetValue(tlsIndex);
if (tlsMemArray != NULL) {
threadMemLoc = tlsMemArray[index];
if (threadMemLoc != NULL) {
tlsMemArray[index] = NULL;
os_free(threadMemLoc);
}
}
}
}
/** \brief Get thread private memory
*
* Possible Results:
* - returns NULL if
* No heap memory is related to the thread for
* the specified index
* - returns a reference to the allocated memory
*/
void *
os_threadMemGet(
int32_t index)
{
void **tlsMemArray;
void *data;
data = NULL;
if ((0 <= index) && (index < OS_THREAD_MEM_ARRAY_SIZE)) {
tlsMemArray = TlsGetValue(tlsIndex);
if (tlsMemArray != NULL) {
data = tlsMemArray[index];
}
}
return data;
}
static os_threadLocal os_iter *cleanup_funcs;
/* executed before dllmain within the context of the thread itself */
void NTAPI
os_threadCleanupFini(
PVOID handle,
DWORD reason,
PVOID reserved)
{
os_threadCleanup *obj;
switch(reason) {
case DLL_PROCESS_DETACH: /* specified when main thread exits */
case DLL_THREAD_DETACH: /* specified when thread exits */
if (cleanup_funcs != NULL) {
for (obj = (os_threadCleanup *)os_iterTake(cleanup_funcs, -1);
obj != NULL;
obj = (os_threadCleanup *)os_iterTake(cleanup_funcs, -1))
{
assert(obj->func != NULL);
obj->func(obj->data);
os_free(obj);
}
os_iterFree(cleanup_funcs, NULL);
}
cleanup_funcs = NULL;
break;
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
default:
/* do nothing */
break;
}
(void)handle;
(void)reserved;
}
/* These instructions are very specific to the Windows platform. They register
a function (or multiple) as a TLS initialization function. TLS initializers
are executed when a thread (or program) attaches or detaches. In contrast to
DllMain, a TLS initializer is also executed when the library is linked
statically. TLS initializers are always executed before DllMain (both when
the library is attached and detached). See http://www.nynaeve.net/?p=190,
for a detailed explanation on TLS initializers. Boost and/or POSIX Threads
for Windows code bases may also form good sources of information on this
subject.
These instructions could theoretically be hidden in the build system, but
doing so would be going a bit overboard as only Windows offers (and
requires) this type of functionality/initialization. Apart from that the
logic isn't exactly as trivial as for example determining the endianness of
a platform, so keeping this close to the implementation is probably wise. */
#ifdef _WIN64
#pragma comment (linker, "/INCLUDE:_tls_used")
#pragma comment (linker, "/INCLUDE:tls_callback_func")
#pragma const_seg(".CRT$XLZ")
EXTERN_C const PIMAGE_TLS_CALLBACK tls_callback_func = os_threadCleanupFini;
#pragma const_seg()
#else
#pragma comment (linker, "/INCLUDE:__tls_used")
#pragma comment (linker, "/INCLUDE:_tls_callback_func")
#pragma data_seg(".CRT$XLZ")
EXTERN_C PIMAGE_TLS_CALLBACK tls_callback_func = os_threadCleanupFini;
#pragma data_seg()
#endif
void
os_threadCleanupPush(
void (*func)(void *),
void *data)
{
os_threadCleanup *obj;
assert(func != NULL);
if (cleanup_funcs == NULL) {
cleanup_funcs = os_iterNew();
assert(cleanup_funcs != NULL);
}
obj = os_malloc(sizeof(*obj));
assert(obj != NULL);
obj->func = func;
obj->data = data;
(void)os_iterAppend(cleanup_funcs, obj);
}
void
os_threadCleanupPop(
int execute)
{
os_threadCleanup *obj;
if (cleanup_funcs != NULL) {
obj = os_iterTake(cleanup_funcs, -1);
if (obj != NULL) {
if (execute) {
obj->func(obj->data);
}
os_free(obj);
}
}
}

View file

@ -0,0 +1,207 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** \file os/mingw3.2.0/code/os_time.c
* \brief WIN32 time management
*
* Implements time management for WIN32 by
* including the common services
* and implementing WIN32 specific
* os_timeGet and os_nanoSleep
*/
#include <sys/timeb.h>
#include <time.h>
#include "os/os.h"
#include <assert.h>
#if defined(_WIN32_WINNT) && _WIN32_WINNT > 0x0603
#define UseGetSystemTimePreciseAsFileTime
/* GetSystemTimeAsFileTimeFunc is set when available (on Windows 8 and later). */
static VOID (WINAPI *GetSystemTimePreciseAsFileTimeFunc) (_Out_ LPFILTETIME);
static HANDLE Kernel32ModuleHandle;
#endif
/* GetSystemTimeAsFileTime returns the number of 100ns intervals that have elapsed
* since January 1, 1601 (UTC). There are 11,644,473,600 seconds between 1601 and
* the Unix epoch (January 1, 1970 (UTC)), which is the reference that is used for
* os_time. */
#define OS_TIME_FILETIME_UNIXEPOCH_OFFSET_SECS (11644473600)
os_time
os__timeDefaultTimeGet(void)
{
FILETIME ft;
ULARGE_INTEGER ns100;
os_time current_time;
/* GetSystemTime(Precise)AsFileTime returns the number of 100-nanosecond
* intervals since January 1, 1601 (UTC).
* GetSystemTimeAsFileTime has a resolution of approximately the
* TimerResolution (~15.6ms) on Windows XP. On Windows 7 it appears to have
* sub-millisecond resolution. GetSystemTimePreciseAsFileTime (available on
* Windows 8) has sub-microsecond resolution.
*
* This call appears to be significantly (factor 8) cheaper than the
* QueryPerformanceCounter (on the systems performance was measured on).
*
* TODO: When the API is extended to support retrieval of clock-properties,
* then the actual resolution of this clock can be retrieved using the
* GetSystemTimeAdjustment. See for example OSPL-4394.
*/
#ifdef UseGetSystemTimePreciseAsFileTime
if (GetSystemTimePreciseAsFileTimeFunc) {
GetSystemTimePreciseAsFileTimeFunc(&ft);
} else {
GetSystemTimeAsFileTime(&ft);
}
#else
GetSystemTimeAsFileTime(&ft);
#endif
ns100.LowPart = ft.dwLowDateTime;
ns100.HighPart = ft.dwHighDateTime;
current_time.tv_sec = (os_timeSec)((ns100.QuadPart / 10000000) - OS_TIME_FILETIME_UNIXEPOCH_OFFSET_SECS);
current_time.tv_nsec = (int32_t)((ns100.QuadPart % 10000000) * 100);
return current_time;
}
void
os_timeModuleInit(void)
{
#ifdef UseGetSystemTimePreciseAsFileTime
/* Resolve the time-functions from the Kernel32-library. */
/* This os_timeModuleInit is currently called from DllMain. This means
* we're not allowed to do LoadLibrary. One exception is "Kernel32.DLL",
* since that library is per definition loaded (LoadLibrary itself
* lives there). And since we're only resolving stuff, not actually
* invoking, this is considered safe. */
Kernel32ModuleHandle = LoadLibrary("Kernel32.DLL");
assert(Kernel32ModuleHandle);
GetSystemTimePreciseAsFileTimeFunc = GetProcAddress(Kernel32ModuleHandle, "GetSystemTimePreciseAsFileTime");
#endif
}
void
os_timeModuleExit(void)
{
#ifdef UseGetSystemTimePreciseAsFileTime
if (Kernel32ModuleHandle) {
GetSystemTimePreciseAsFileTimeFunc = NULL;
FreeLibrary(Kernel32ModuleHandle);
Kernel32ModuleHandle = NULL;
}
#endif
}
/** \brief Suspend the execution of the calling thread for the specified time
*
* \b os_nanoSleep suspends the calling thread for the required
* time by calling \b nanosleep. First it converts the \b delay in
* \b os_time definition into a time in \b struct \b timeval definition.
* In case the \b nanosleep is interrupted, the call is re-enterred with
* the remaining time.
*/
os_result
os_nanoSleep (
_In_ os_time delay)
{
os_result result = os_resultSuccess;
DWORD dt;
assert (delay.tv_nsec >= 0);
assert (delay.tv_nsec < 1000000000);
if (delay.tv_sec >= 0 ) {
dt = (DWORD)delay.tv_sec * 1000 + delay.tv_nsec / 1000000;
Sleep(dt);
} else {
/* Negative time-interval should return illegal param error */
result = os_resultFail;
}
return result;
}
/** \brief Get high resolution, monotonic time.
*
*/
os_time
os_timeGetMonotonic(void)
{
os_time current_time;
ULONGLONG ubit;
(void) QueryUnbiasedInterruptTime(&ubit); /* 100ns ticks */
current_time.tv_sec = (os_timeSec)(ubit / 10000000);
current_time.tv_nsec = (int32_t)((ubit % 10000000) * 100);
return current_time;
}
/** \brief Get high resolution, elapsed time.
*
*/
os_time
os_timeGetElapsed(void)
{
os_time current_time;
LARGE_INTEGER qpc;
static LONGLONG qpc_freq;
/* The QueryPerformanceCounter has a bad reputation, since it didn't behave
* very well on older hardware. On recent OS's (Windows XP SP2 and later)
* things have become much better, especially when combined with new hard-
* ware.
*
* There is currently one bug which is not fixed, which may cause forward
* jumps. This is currently not really important, since a forward jump may
* be observed anyway due to the system going to standby. There is a work-
* around available (comparing the progress with the progress made by
* GetTickCount), but for now we live with a risk of a forward jump on buggy
* hardware. Since Microsoft does maintain a list of hardware which exhibits
* the behaviour, it is possible to only have the workaround in place only
* on the faulty hardware (see KB274323 for a list and more info).
*
* TODO: When the API is extended to support retrieval of clock-properties,
* then the discontinuous nature (when sleeping/hibernating) of this
* clock and the drift tendency should be reported. See for example
* OSPL-4394. */
if (qpc_freq == 0){
/* This block is idempotent, so don't bother with synchronisation */
LARGE_INTEGER frequency;
if(QueryPerformanceFrequency(&frequency)){
qpc_freq = frequency.QuadPart;
}
/* Since Windows XP SP2 the QueryPerformanceCounter is abstracted,
* so QueryPerformanceFrequency is not expected to ever return 0.
* That't why there is no fall-back for the case when no
* QueryPerformanceCounter is available. */
}
assert(qpc_freq);
/* The QueryPerformanceCounter tends to drift quite a bit, so in order to
* accurately measure longer periods with it, there may be a need to sync
* the time progression to actual time progression (with a PLL for example
* as done by EB for CAE). */
QueryPerformanceCounter(&qpc);
current_time.tv_sec = (os_timeSec)(qpc.QuadPart / qpc_freq);
current_time.tv_nsec = (int32_t)(((qpc.QuadPart % qpc_freq) * 1000000000) / qpc_freq);
return current_time;
}

View file

@ -0,0 +1,16 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
include(CUnit)
add_cunit_executable(abstraction .)
target_link_libraries(abstraction OSAPI)

467
src/os/tests/atomics.c Normal file
View file

@ -0,0 +1,467 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "os/os.h"
#include "CUnit/Runner.h"
uint32_t _osuint32 = 0;
uint64_t _osuint64 = 0;
// os_address is uintptr_t
uintptr_t _osaddress = 0;
ptrdiff_t _ptrdiff = 0;
void * _osvoidp = (uintptr_t *)0;
CUnit_Test(os_atomics, load_store)
{
volatile os_atomic_uint32_t uint32 = OS_ATOMIC_UINT32_INIT(5);
#if OS_ATOMIC64_SUPPORT
volatile os_atomic_uint64_t uint64 = OS_ATOMIC_UINT64_INIT(5);
#endif
volatile os_atomic_uintptr_t uintptr = OS_ATOMIC_UINTPTR_INIT(5);
volatile os_atomic_voidp_t voidp = OS_ATOMIC_VOIDP_INIT((uintptr_t)5);
/* Test uint32 LD-ST */
printf ("Starting os_atomics_load_store_001\n");
CU_ASSERT (os_atomic_ld32 (&uint32) == 5); /* Returns contents of uint32 */
os_atomic_st32 (&uint32, _osuint32); /* Writes os_uint32 into uint32 */
CU_ASSERT (os_atomic_ld32 (&uint32) == _osuint32);
/* Test uint64 LD-ST */
printf ("Starting os_atomics_load_store_002\n");
#if OS_ATOMIC64_SUPPORT
CU_ASSERT (os_atomic_ld64 (&uint64) == 5);
os_atomic_st64 (&uint64, _osuint64);
CU_ASSERT (os_atomic_ld64 (&uint64) == _osuint64);
#endif
/* Test uintptr LD-ST */
printf ("Starting os_atomics_load_store_003\n");
CU_ASSERT (os_atomic_ldptr (&uintptr) == 5);
os_atomic_stptr (&uintptr, _osaddress);
CU_ASSERT (os_atomic_ldptr (&uintptr) == _osaddress);
/* Test uintvoidp LD-ST */
printf ("Starting os_atomics_load_store_004\n");
CU_ASSERT (os_atomic_ldvoidp (&voidp) == (uintptr_t*)5);
os_atomic_stvoidp (&voidp, _osvoidp);
CU_ASSERT (os_atomic_ldvoidp (&voidp) == (uintptr_t*)_osvoidp);
printf ("Ending atomics_load_store\n");
}
CUnit_Test(os_atomics, compare_and_swap)
{
/* Compare and Swap
* if (ptr == expected) { ptr = newval; }
*/
volatile os_atomic_uint32_t uint32 = OS_ATOMIC_UINT32_INIT(0);
#if OS_ATOMIC64_SUPPORT
volatile os_atomic_uint64_t uint64 = OS_ATOMIC_UINT64_INIT(0);
#endif
volatile os_atomic_uintptr_t uintptr = OS_ATOMIC_UINTPTR_INIT(0);
volatile os_atomic_voidp_t uintvoidp = OS_ATOMIC_VOIDP_INIT((uintptr_t)0);
_osuint32 = 1;
_osuint64 = 1;
_osaddress = 1;
_osvoidp = (uintptr_t *)1;
uint32_t expected = 0, newval = 5;
uintptr_t addr_expected = 0, addr_newval = 5;
void *void_expected = (uintptr_t*)0;
void *void_newval = (uintptr_t*)5;
int ret = 0;
/* Test os_atomic_cas32 */
printf ("Starting os_atomics_compare_and_swap_001\n");
ret = os_atomic_cas32 (&uint32, expected, newval);
CU_ASSERT (os_atomic_ld32 (&uint32) == newval && ret == 1);
os_atomic_st32 (&uint32, _osuint32);
ret = os_atomic_cas32 (&uint32, expected, newval);
CU_ASSERT (os_atomic_ld32 (&uint32) != newval && ret == 0);
/* Test os_atomic_cas64 */
printf ("Starting os_atomics_compare_and_swap_002\n");
#if OS_ATOMIC64_SUPPORT
ret = os_atomic_cas64 (&uint64, expected, newval);
CU_ASSERT (os_atomic_ld64 (&uint64) == newval && ret == 1);
os_atomic_st64 (&uint64, _osuint64);
ret = os_atomic_cas64 (&uint64, expected, newval);
CU_ASSERT (os_atomic_ld64 (&uint64) != newval && ret == 0);
#endif
/* Test os_atomic_casptr */
printf ("Starting os_atomics_compare_and_swap_003\n");
ret = os_atomic_casptr (&uintptr, addr_expected, addr_newval);
CU_ASSERT (os_atomic_ldptr (&uintptr) == addr_newval && ret == 1);
os_atomic_stptr (&uintptr, _osaddress);
ret = os_atomic_casptr (&uintptr, addr_expected, addr_newval);
CU_ASSERT (os_atomic_ldptr (&uintptr) != addr_newval && ret == 0);
/* Test os_atomic_casvoidp */
printf ("Starting os_atomics_compare_and_swap_003\n");
ret = os_atomic_casvoidp (&uintvoidp, void_expected, void_newval);
CU_ASSERT (os_atomic_ldvoidp (&uintvoidp) == (uintptr_t*)void_newval && ret == 1);
os_atomic_stvoidp (&uintvoidp, _osvoidp);
ret = os_atomic_casvoidp (&uintvoidp, void_expected, void_newval);
CU_ASSERT (os_atomic_ldvoidp (&uintvoidp) == (uintptr_t*)1 && ret == 0);
printf ("Ending atomics_compare_and_swap\n");
}
CUnit_Test(os_atomics, increment)
{
volatile os_atomic_uint32_t uint32 = OS_ATOMIC_UINT32_INIT(0);
#if OS_ATOMIC64_SUPPORT
volatile os_atomic_uint64_t uint64 = OS_ATOMIC_UINT64_INIT(0);
#endif
volatile os_atomic_uintptr_t uintptr = OS_ATOMIC_UINTPTR_INIT(0);
_osuint32 = 0;
_osuint64 = 0;
_osaddress = 0;
_osvoidp = (uintptr_t *)0;
/* Test os_inc32 */
printf ("Starting os_atomics_increment_001\n");
os_atomic_inc32 (&uint32);
CU_ASSERT (os_atomic_ld32 (&uint32) == 1);
/* Test os_inc64 */
printf ("Starting os_atomics_increment_002\n");
#if OS_ATOMIC64_SUPPORT
os_atomic_inc64 (&uint64);
CU_ASSERT (os_atomic_ld64 (&uint64) == 1);
#endif
/* Test os_incptr */
printf ("Starting os_atomics_increment_003\n");
os_atomic_incptr (&uintptr);
CU_ASSERT (os_atomic_ldptr (&uintptr) == 1);
/* Test os_atomic_inc32_nv */
printf ("Starting os_atomics_increment_004\n");
os_atomic_st32 (&uint32, _osuint32);
CU_ASSERT (os_atomic_inc32_nv (&uint32) == 1);
/* Test os_atomic_inc64_nv */
printf ("Starting os_atomics_increment_005\n");
#if OS_ATOMIC64_SUPPORT
os_atomic_st64 (&uint64, _osuint64);
CU_ASSERT (os_atomic_inc64_nv (&uint64) == 1);
#endif
/* Test os_atomic_incptr_nv */
printf ("Starting os_atomics_increment_006\n");
os_atomic_stptr (&uintptr, _osaddress);
CU_ASSERT (os_atomic_incptr_nv(&uintptr) == 1);
printf ("Ending atomics_increment\n");
}
CUnit_Test(os_atomics, decrement)
{
volatile os_atomic_uint32_t uint32 = OS_ATOMIC_UINT32_INIT(1);
#if OS_ATOMIC64_SUPPORT
volatile os_atomic_uint64_t uint64 = OS_ATOMIC_UINT64_INIT(1);
#endif
volatile os_atomic_uintptr_t uintptr = OS_ATOMIC_UINTPTR_INIT(1);
_osuint32 = 1;
_osuint64 = 1;
_osaddress = 1;
_osvoidp = (uintptr_t *)1;
/* Test os_atomic_dec32 */
printf ("Starting os_atomics_decrement_001\n");
os_atomic_dec32 (&uint32);
CU_ASSERT (os_atomic_ld32 (&uint32) == 0);
/* Test os_atomic_dec64 */
printf ("Starting os_atomics_decrement_002\n");
#if OS_ATOMIC64_SUPPORT
os_atomic_dec64 (&uint64);
CU_ASSERT (os_atomic_ld64 (&uint64) == 0);
#endif
/* Test os_atomic_decptr */
printf ("Starting os_atomics_decrement_003\n");
os_atomic_decptr (&uintptr);
CU_ASSERT (os_atomic_ldptr (&uintptr) == 0);
/* Test os_atomic_dec32_nv */
printf ("Starting os_atomics_decrement_004\n");
os_atomic_st32 (&uint32, _osuint32);
CU_ASSERT (os_atomic_dec32_nv (&uint32) == 0);
/* Test os_atomic_dec64_nv */
printf ("Starting os_atomics_decrement_005\n");
#if OS_ATOMIC64_SUPPORT
os_atomic_st64 (&uint64, _osuint64);
CU_ASSERT (os_atomic_dec64_nv (&uint64) == 0);
#endif
/* Test os_atomic_decptr_nv */
printf ("Starting os_atomics_decrement_006\n");
os_atomic_stptr (&uintptr, _osaddress);
CU_ASSERT (os_atomic_decptr_nv(&uintptr) == 0);
printf ("Ending atomics_decrement\n");
}
CUnit_Test(os_atomics, add)
{
volatile os_atomic_uint32_t uint32 = OS_ATOMIC_UINT32_INIT(1);
#if OS_ATOMIC64_SUPPORT
volatile os_atomic_uint64_t uint64 = OS_ATOMIC_UINT64_INIT(1);
#endif
volatile os_atomic_uintptr_t uintptr = OS_ATOMIC_UINTPTR_INIT(1);
volatile os_atomic_voidp_t uintvoidp = OS_ATOMIC_VOIDP_INIT((uintptr_t)1);
_osuint32 = 2;
_osuint64 = 2;
_osaddress = 2;
_ptrdiff = 2;
/* Test os_atomic_add32 */
printf ("Starting os_atomics_add_001\n");
os_atomic_add32 (&uint32, _osuint32);
CU_ASSERT (os_atomic_ld32 (&uint32) == 3);
/* Test os_atomic_add64 */
printf ("Starting os_atomics_add_002\n");
#if OS_ATOMIC64_SUPPORT
os_atomic_add64 (&uint64, _osuint64);
CU_ASSERT (os_atomic_ld64 (&uint64) == 3);
#endif
/* Test os_atomic_addptr */
printf ("Starting os_atomics_add_003\n");
os_atomic_addptr (&uintptr, _osaddress);
CU_ASSERT (os_atomic_ldptr (&uintptr) == 3);
/* Test os_atomic_addvoidp */
printf ("Starting os_atomics_add_004\n");
os_atomic_addvoidp (&uintvoidp, _ptrdiff);
CU_ASSERT (os_atomic_ldvoidp (&uintvoidp) == (uintptr_t*)3);
/* Test os_atomic_add32_nv */
printf ("Starting os_atomics_add_005\n");
os_atomic_st32 (&uint32, 1);
CU_ASSERT (os_atomic_add32_nv (&uint32, _osuint32) == 3);
/* Test os_atomic_add64_nv */
printf ("Starting os_atomics_add_006\n");
#if OS_ATOMIC64_SUPPORT
os_atomic_st64 (&uint64, 1);
CU_ASSERT (os_atomic_add64_nv (&uint64, _osuint64) == 3);
#endif
/* Test os_atomic_addptr_nv */
printf ("Starting os_atomics_add_007\n");
os_atomic_stptr (&uintptr, 1);
CU_ASSERT (os_atomic_addptr_nv (&uintptr, _osaddress) == 3);
/* Test os_atomic_addvoidp_nv */
printf ("Starting os_atomics_add_008\n");
os_atomic_stvoidp (&uintvoidp, (uintptr_t*)1);
CU_ASSERT (os_atomic_addvoidp_nv (&uintvoidp, _ptrdiff) == (uintptr_t*)3);
printf ("Ending atomics_add\n");
}
CUnit_Test(os_atomics, subtract)
{
volatile os_atomic_uint32_t uint32 = OS_ATOMIC_UINT32_INIT(5);
#if OS_ATOMIC64_SUPPORT
volatile os_atomic_uint64_t uint64 = OS_ATOMIC_UINT64_INIT(5);
#endif
volatile os_atomic_uintptr_t uintptr = OS_ATOMIC_UINTPTR_INIT(5);
volatile os_atomic_voidp_t uintvoidp = OS_ATOMIC_VOIDP_INIT((uintptr_t)5);
_osuint32 = 2;
_osuint64 = 2;
_osaddress = 2;
_ptrdiff = 2;
/* Test os_atomic_sub32 */
printf ("Starting os_atomics_subtract_001\n");
os_atomic_sub32 (&uint32, _osuint32);
CU_ASSERT (os_atomic_ld32 (&uint32) == 3);
/* Test os_atomic_sub64 */
printf ("Starting os_atomics_subtract_002\n");
#if OS_ATOMIC64_SUPPORT
os_atomic_sub64 (&uint64, _osuint64);
CU_ASSERT (os_atomic_ld64 (&uint64) == 3);
#endif
/* Test os_atomic_subptr */
printf ("Starting os_atomics_subtract_003\n");
os_atomic_subptr (&uintptr, _osaddress);
CU_ASSERT (os_atomic_ldptr (&uintptr) == 3);
/* Test os_atomic_subvoidp */
printf ("Starting os_atomics_subtract_004\n");
os_atomic_subvoidp (&uintvoidp, _ptrdiff);
CU_ASSERT (os_atomic_ldvoidp (&uintvoidp) == (uintptr_t*)3);
/* Test os_atomic_sub32_nv */
printf ("Starting os_atomics_subtract_005\n");
os_atomic_st32 (&uint32, 5);
CU_ASSERT (os_atomic_sub32_nv (&uint32, _osuint32) == 3);
/* Test os_atomic_sub64_nv */
printf ("Starting os_atomics_subtract_006\n");
#if OS_ATOMIC64_SUPPORT
os_atomic_st64 (&uint64, 5);
CU_ASSERT (os_atomic_sub64_nv (&uint64, _osuint64) == 3);
#endif
/* Test os_atomic_subptr_nv */
printf ("Starting os_atomics_subtract_007\n");
os_atomic_stptr (&uintptr, 5);
CU_ASSERT (os_atomic_subptr_nv (&uintptr, _osaddress) == 3);
/* Test os_atomic_subvoidp_nv */
printf ("Starting os_atomics_subtract_008\n");
os_atomic_stvoidp (&uintvoidp, (uintptr_t*)5);
CU_ASSERT (os_atomic_subvoidp_nv (&uintvoidp, _ptrdiff) == (void *)3);
printf ("Ending atomics_subtract\n");
}
CUnit_Test(os_atomics, and)
{
/* AND Operation:
150 010010110
500 111110100
148 010010100 */
volatile os_atomic_uint32_t uint32 = OS_ATOMIC_UINT32_INIT(150);
#if OS_ATOMIC64_SUPPORT
volatile os_atomic_uint64_t uint64 = OS_ATOMIC_UINT64_INIT(150);
#endif
volatile os_atomic_uintptr_t uintptr = OS_ATOMIC_UINTPTR_INIT(150);
_osuint32 = 500;
_osuint64 = 500;
_osaddress = 500;
/* Test os_atomic_and32 */
printf ("Starting os_atomics_and_001\n");
os_atomic_and32 (&uint32, _osuint32);
CU_ASSERT (os_atomic_ld32 (&uint32) == 148);
/* Test os_atomic_and64 */
printf ("Starting os_atomics_and_002\n");
#if OS_ATOMIC64_SUPPORT
os_atomic_and64 (&uint64, _osuint64);
CU_ASSERT (os_atomic_ld64 (&uint64) == 148);
#endif
/* Test os_atomic_andptr */
printf ("Starting os_atomics_and_003\n");
os_atomic_andptr (&uintptr, _osaddress);
CU_ASSERT (os_atomic_ldptr (&uintptr) == 148);
/* Test os_atomic_and32_ov */
printf ("Starting os_atomics_and_004\n");
CU_ASSERT (os_atomic_and32_ov (&uint32, _osuint32) == 148);
/* Test os_atomic_and64_ov */
printf ("Starting os_atomics_and_005\n");
#if OS_ATOMIC64_SUPPORT
CU_ASSERT (os_atomic_and64_ov (&uint64, _osuint64) == 148);
#endif
/* Test os_atomic_andptr_ov */
printf ("Starting os_atomics_and_006\n");
CU_ASSERT (os_atomic_andptr_ov (&uintptr, _osaddress) == 148);
/* Test os_atomic_and32_nv */
printf ("Starting os_atomics_and_007\n");
CU_ASSERT (os_atomic_and32_nv (&uint32, _osuint32) == 148);
/* Test os_atomic_and64_nv */
printf ("Starting os_atomics_and_008\n");
#if OS_ATOMIC64_SUPPORT
CU_ASSERT (os_atomic_and64_nv (&uint64, _osuint64) == 148);
#endif
/* Test os_atomic_andptr_nv */
printf ("Starting os_atomics_and_009\n");
CU_ASSERT (os_atomic_andptr_nv (&uintptr, _osaddress) == 148);
printf ("Ending atomics_and\n");
}
CUnit_Test(os_atomics, or)
{
/* OR Operation:
150 010010110
500 111110100
502 111110110 */
volatile os_atomic_uint32_t uint32 = OS_ATOMIC_UINT32_INIT(150);
#if OS_ATOMIC64_SUPPORT
volatile os_atomic_uint64_t uint64 = OS_ATOMIC_UINT64_INIT(150);
#endif
volatile os_atomic_uintptr_t uintptr = OS_ATOMIC_UINTPTR_INIT(150);
_osuint32 = 500;
_osuint64 = 500;
_osaddress = 500;
/* Test os_atomic_or32 */
printf ("Starting os_atomics_or_001\n");
os_atomic_or32 (&uint32, _osuint32);
CU_ASSERT (os_atomic_ld32 (&uint32) == 502);
/* Test os_atomic_or64 */
printf ("Starting os_atomics_or_002\n");
#if OS_ATOMIC64_SUPPORT
os_atomic_or64 (&uint64, _osuint64);
CU_ASSERT (os_atomic_ld64 (&uint64) == 502);
#endif
/* Test os_atomic_orptr */
printf ("Starting os_atomics_or_003\n");
os_atomic_orptr (&uintptr, _osaddress);
CU_ASSERT (os_atomic_ldptr (&uintptr) == 502);
/* Test os_atomic_or32_ov */
printf ("Starting os_atomics_or_004\n");
CU_ASSERT (os_atomic_or32_ov (&uint32, _osuint32) == 502);
/* Test os_atomic_or64_ov */
printf ("Starting os_atomics_or_005\n");
#if OS_ATOMIC64_SUPPORT
CU_ASSERT (os_atomic_or64_ov (&uint64, _osuint64) == 502);
#endif
/* Test os_atomic_orptr_ov */
printf ("Starting os_atomics_or_006\n");
CU_ASSERT (os_atomic_orptr_ov (&uintptr, _osaddress) == 502);
/* Test os_atomic_or32_nv */
printf ("Starting os_atomics_or_007\n");
CU_ASSERT (os_atomic_or32_nv (&uint32, _osuint32) == 502);
/* Test os_atomic_or64_nv */
printf ("Starting os_atomics_or_008\n");
#if OS_ATOMIC64_SUPPORT
CU_ASSERT (os_atomic_or64_nv (&uint64, _osuint64) == 502);
#endif
/* Test os_atomic_orptr_nv */
printf ("Starting os_atomics_or_009\n");
CU_ASSERT (os_atomic_orptr_nv (&uintptr, _osaddress) == 502);
printf ("Ending atomics_or\n");
}

47
src/os/tests/error_no.c Normal file
View file

@ -0,0 +1,47 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Runner.h"
#include "os/os.h"
CUnit_Suite_Initialize(os_errno)
{
int result = 0;
os_osInit();
printf("Run os_errno_Initialize\n");
return result;
}
CUnit_Suite_Cleanup(os_errno)
{
int result = 0;
os_osExit();
printf("Run os_errno_Cleanup\n");
return result;
}
CUnit_Test(os_errno, get_and_set)
{
printf ("Starting os_errno_get_and_set_001\n");
os_setErrno (0);
CU_ASSERT (os_getErrno () == 0);
printf ("Starting os_errno_get_and_set_002\n");
os_setErrno (0);
/* Call strtol with an invalid format on purpose. */
(void)strtol ("1000000000000000000000000000000000000000000000000", NULL, 10);
CU_ASSERT (os_getErrno () != 0);
printf ("Ending tc_os_errno\n");
}

197
src/os/tests/heap.c Normal file
View file

@ -0,0 +1,197 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Runner.h"
#include "os/os.h"
CUnit_Suite_Initialize(os_heap)
{
int result = 0;
os_osInit();
printf("Run os_heap_Initialize\n");
return result;
}
CUnit_Suite_Cleanup(os_heap)
{
int result = 0;
os_osExit();
printf("Run os_heap_Cleanup\n");
return result;
}
static const size_t allocsizes[] = {0, 1, 2, 3, 4, 5, 10, 20, 257, 1024};
static const size_t nof_allocsizes = sizeof allocsizes / sizeof *allocsizes;
CUnit_Test(os_heap, os_malloc)
{
for(int i = 0; i < nof_allocsizes; i++) {
for(int j = 0; j < nof_allocsizes; j++) {
size_t s = allocsizes[i] * allocsizes[j]; /* Allocates up to 1MB */
void *ptr = os_malloc(s);
CU_ASSERT_PTR_NOT_EQUAL(ptr, NULL); /* os_malloc is supposed to abort on failure */
memset(ptr, 0, s); /* This potentially segfaults if the actual allocated block is too small */
os_free(ptr);
}
}
CU_PASS("os_malloc");
}
CUnit_Test(os_heap, os_malloc_0)
{
for(int i = 0; i < nof_allocsizes; i++) {
for(int j = 0; j < nof_allocsizes; j++) {
size_t s = allocsizes[i] * allocsizes[j]; /* Allocates up to 1MB */
char *ptr = os_malloc_0(s);
CU_ASSERT_PTR_NOT_EQUAL(ptr, NULL); /* os_malloc_0 is supposed to abort on failure */
if(s) {
CU_ASSERT (ptr[0] == 0 && !memcmp(ptr, ptr + 1, s - 1)); /* malloc_0 should memset properly */
}
os_free(ptr);
}
}
CU_PASS("os_malloc_0");
}
CUnit_Test(os_heap, os_calloc)
{
for(int i = 0; i < nof_allocsizes; i++) {
for(int j = 0; j < nof_allocsizes; j++) {
char *ptr = os_calloc(allocsizes[i], allocsizes[j]);
CU_ASSERT_PTR_NOT_EQUAL(ptr, NULL); /* os_calloc is supposed to abort on failure */
if(allocsizes[i] * allocsizes[j]) {
CU_ASSERT (ptr[0] == 0 && !memcmp(ptr, ptr + 1, (allocsizes[i] * allocsizes[j]) - 1)); /* os_calloc should memset properly */
}
os_free(ptr);
}
}
CU_PASS("os_calloc");
}
CUnit_Test(os_heap, os_realloc)
{
char *ptr = NULL;
size_t unchanged, s, prevs = 0;
for(int i = 0; i < nof_allocsizes; i++) {
for(int j = 0; j < nof_allocsizes; j++) {
s = allocsizes[i] * allocsizes[j]; /* Allocates up to 1MB */
printf("os_realloc(%p) %zu -> %zu\n", ptr, prevs, s);
ptr = os_realloc(ptr, s);
CU_ASSERT_PTR_NOT_EQUAL(ptr, NULL); /* os_realloc is supposed to abort on failure */
unchanged = (prevs < s) ? prevs : s;
if(unchanged) {
CU_ASSERT (ptr[0] == 1 && !memcmp(ptr, ptr + 1, unchanged - 1)); /* os_realloc shouldn't change memory */
}
memset(ptr, 1, s); /* This potentially segfaults if the actual allocated block is too small */
prevs = s;
}
}
os_free(ptr);
CU_PASS("os_realloc");
}
static const size_t allocsizes_s[] = {0, 1, 2, 3, 4, 5, 10, 20, 257, 1024, 8192};
static const size_t nof_allocsizes_s = sizeof allocsizes_s / sizeof *allocsizes_s;
CUnit_Test(os_heap, os_malloc_s)
{
for(int i = 0; i < nof_allocsizes_s; i++) {
for(int j = 0; j < nof_allocsizes_s; j++) {
size_t s = allocsizes_s[i] * allocsizes_s[j]; /* Allocates up to 8MB */
void *ptr = os_malloc_s(s); /* If s == 0, os_malloc_s should still return a pointer */
if(ptr) {
memset(ptr, 0, s); /* This potentially segfaults if the actual allocated block is too small */
} else if (s <= 16) {
/* Failure to allocate can't be considered a test fault really,
* except that a malloc(<=16) would fail is unlikely. */
CU_FAIL("os_malloc_0_s(<=16) returned NULL");
}
os_free(ptr);
}
}
CU_PASS("os_malloc_s");
}
CUnit_Test(os_heap, os_malloc_0_s)
{
for(int i = 0; i < nof_allocsizes_s; i++) {
for(int j = 0; j < nof_allocsizes_s; j++) {
size_t s = allocsizes_s[i] * allocsizes_s[j]; /* Allocates up to 8MB */
char *ptr = os_malloc_0_s(s); /* If s == 0, os_malloc_0_s should still return a pointer */
if(ptr) {
if(s) {
CU_ASSERT (ptr[0] == 0 && !memcmp(ptr, ptr + 1, s - 1)); /* malloc_0_s should memset properly */
}
} else if (s <= 16) {
/* Failure to allocate can't be considered a test fault really,
* except that a malloc(<=16) would fail is unlikely. */
CU_FAIL("os_malloc_0_s(<=16) returned NULL");
}
os_free(ptr);
}
}
CU_PASS("os_malloc_0_s");
}
CUnit_Test(os_heap, os_calloc_s)
{
for(int i = 0; i < nof_allocsizes_s; i++) {
for(int j = 0; j < nof_allocsizes_s; j++) {
size_t s = allocsizes_s[i] * allocsizes_s[j];
char *ptr = os_calloc_s(allocsizes_s[i], allocsizes_s[j]); /* If either one is 0, os_calloc_s should still return a pointer */
if(ptr) {
if(s) {
CU_ASSERT (ptr[0] == 0 && !memcmp(ptr, ptr + 1, s - 1)); /* malloc_0_s should memset properly */
}
} else if (s <= 16) {
/* Failure to allocate can't be considered a test fault really,
* except that a calloc(<=16) would fail is unlikely. */
CU_FAIL("os_calloc_s(<=16) returned NULL");
}
os_free(ptr);
}
}
CU_PASS("os_calloc_s");
}
CUnit_Test(os_heap, os_realloc_s)
{
char *newptr, *ptr = NULL;
size_t unchanged, s, prevs = 0;
for(int i = 0; i < nof_allocsizes_s; i++) {
for(int j = 0; j < nof_allocsizes_s; j++) {
s = allocsizes_s[i] * allocsizes_s[j]; /* Allocates up to 8MB */
newptr = os_realloc_s(ptr, s);
printf("%p = os_realloc_s(%p) %zu -> %zu\n", newptr, ptr, prevs, s);
if (s <= 16) {
/* Failure to allocate can't be considered a test fault really,
* except that a os_realloc_s(0 < s <=16) would fail is unlikely. */
CU_ASSERT_PTR_NOT_EQUAL(newptr, NULL);
}
if(newptr){
unchanged = (prevs < s) ? prevs : s;
if(unchanged) {
CU_ASSERT (newptr[0] == 1 && !memcmp(newptr, newptr + 1, unchanged - 1)); /* os_realloc_s shouldn't change memory */
}
memset(newptr, 1, s); /* This potentially segfaults if the actual allocated block is too small */
}
prevs = s;
ptr = newptr;
}
}
os_free(ptr);
CU_PASS("os_realloc_s");
}

239
src/os/tests/iter.c Executable file
View file

@ -0,0 +1,239 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Runner.h"
#include "os/os.h"
#include "assert.h"
static int32_t one = 1;
static int32_t two = 2;
static int32_t three = 3;
static int32_t four = 4;
static int32_t five = 5;
CUnit_Test(os_iter, create)
{
os_iter *iter;
iter = os_iterNew();
CU_ASSERT_PTR_NOT_NULL_FATAL(iter);
CU_ASSERT_EQUAL(os_iterLength(iter), 0);
CU_ASSERT_PTR_NULL(os_iterObject(iter, 0));
CU_ASSERT_PTR_NULL(os_iterTake(iter, 0));
os_iterFree(iter, NULL);
}
CUnit_Test(os_iter, prepend)
{
os_iter *iter;
int32_t idx;
iter = os_iterNew();
CU_ASSERT_PTR_NOT_NULL_FATAL(iter);
idx = os_iterInsert(iter, &one, 0);
CU_ASSERT_EQUAL(idx, 0);
idx = os_iterInsert(iter, &two, 0);
CU_ASSERT_EQUAL(idx, 0);
idx = os_iterInsert(iter, &three, 0);
CU_ASSERT_EQUAL(idx, 0);
CU_ASSERT_EQUAL(os_iterLength(iter), 3);
CU_ASSERT_EQUAL(*(int32_t *)os_iterObject(iter, 0), 3);
CU_ASSERT_EQUAL(*(int32_t *)os_iterObject(iter, 1), 2);
CU_ASSERT_EQUAL(*(int32_t *)os_iterObject(iter, 2), 1);
os_iterFree(iter, NULL);
}
CUnit_Test(os_iter, append)
{
os_iter *iter;
int32_t idx;
iter = os_iterNew();
CU_ASSERT_PTR_NOT_NULL_FATAL(iter);
idx = os_iterInsert(iter, &one, OS_ITER_LENGTH);
CU_ASSERT_EQUAL(idx, 0);
idx = os_iterInsert(iter, &two, OS_ITER_LENGTH);
CU_ASSERT_EQUAL(idx, 1);
idx = os_iterInsert(iter, &three, OS_ITER_LENGTH);
CU_ASSERT_EQUAL(idx, 2);
CU_ASSERT_EQUAL(os_iterLength(iter), 3);
CU_ASSERT_EQUAL(*(int32_t *)os_iterObject(iter, 0), 1);
CU_ASSERT_EQUAL(*(int32_t *)os_iterObject(iter, 1), 2);
CU_ASSERT_EQUAL(*(int32_t *)os_iterObject(iter, 2), 3);
os_iterFree(iter, NULL);
}
CUnit_Test(os_iter, insert)
{
os_iter *iter;
int32_t idx;
iter = os_iterNew();
CU_ASSERT_PTR_NOT_NULL_FATAL(iter);
idx = os_iterInsert(iter, &one, 0);
CU_ASSERT_EQUAL(idx, 0);
idx = os_iterInsert(iter, &three, OS_ITER_LENGTH);
CU_ASSERT_EQUAL(idx, 1);
idx = os_iterInsert(iter, &two, idx);
CU_ASSERT_EQUAL(idx, 1);
idx = os_iterInsert(iter, &four, -2);
CU_ASSERT_EQUAL(idx, 1);
idx = os_iterInsert(iter, &five, -2);
CU_ASSERT_EQUAL(idx, 2);
CU_ASSERT_EQUAL(os_iterLength(iter), 5);
CU_ASSERT_EQUAL(*(int32_t *)os_iterObject(iter, 0), 1);
CU_ASSERT_EQUAL(*(int32_t *)os_iterObject(iter, 1), 4);
CU_ASSERT_EQUAL(*(int32_t *)os_iterObject(iter, 2), 5);
CU_ASSERT_EQUAL(*(int32_t *)os_iterObject(iter, 3), 2);
CU_ASSERT_EQUAL(*(int32_t *)os_iterObject(iter, 4), 3);
os_iterFree(iter, NULL);
}
static void
iter_free_callback(
void *ptr)
{
(*(int32_t *)ptr)++;
}
CUnit_Test(os_iter, free)
{
os_iter *iter;
int32_t cnt = 0;
iter = os_iterNew();
CU_ASSERT_PTR_NOT_NULL_FATAL(iter);
(void)os_iterInsert(iter, &cnt, OS_ITER_LENGTH);
(void)os_iterInsert(iter, &cnt, OS_ITER_LENGTH);
(void)os_iterInsert(iter, &cnt, OS_ITER_LENGTH);
os_iterFree(iter, &iter_free_callback);
CU_ASSERT_EQUAL(cnt, 3);
}
static void
iter_walk_callback(
void *ptr, void *arg)
{
(*(int32_t *)ptr)++;
(*(int32_t *)arg)++;
}
CUnit_Test(os_iter, walk)
{
os_iter *iter;
int32_t cnt = 0;
iter = os_iterNew();
CU_ASSERT_PTR_NOT_NULL_FATAL(iter);
(void)os_iterInsert(iter, &cnt, OS_ITER_LENGTH);
(void)os_iterInsert(iter, &cnt, OS_ITER_LENGTH);
(void)os_iterInsert(iter, &cnt, OS_ITER_LENGTH);
os_iterWalk(iter, &iter_walk_callback, &cnt);
CU_ASSERT_EQUAL(cnt, 6);
os_iterFree(iter, &iter_free_callback);
CU_ASSERT_EQUAL(cnt, 9);
}
static os_iter *
iter_new(
void)
{
os_iter *iter;
int32_t idx;
iter = os_iterNew();
CU_ASSERT_PTR_NOT_NULL_FATAL(iter);
idx = os_iterInsert(iter, &one, OS_ITER_LENGTH);
CU_ASSERT_EQUAL_FATAL(idx, 0);
idx = os_iterInsert(iter, &two, OS_ITER_LENGTH);
CU_ASSERT_EQUAL_FATAL(idx, 1);
idx = os_iterInsert(iter, &three, OS_ITER_LENGTH);
CU_ASSERT_EQUAL_FATAL(idx, 2);
idx = os_iterInsert(iter, &four, OS_ITER_LENGTH);
CU_ASSERT_EQUAL_FATAL(idx, 3);
idx = os_iterInsert(iter, &five, OS_ITER_LENGTH);
CU_ASSERT_EQUAL_FATAL(idx, 4);
CU_ASSERT_EQUAL_FATAL(os_iterLength(iter), 5);
return iter;
}
CUnit_Test(os_iter, object_indices)
{
os_iter *iter;
int32_t *num;
iter = iter_new();
/* index out of range on purpose */
OS_WARNING_MSVC_OFF(28020);
num = os_iterObject(iter, OS_ITER_LENGTH);
OS_WARNING_MSVC_ON(28020);
CU_ASSERT_PTR_NULL(num);
num = os_iterObject(iter, os_iterLength(iter));
CU_ASSERT_PTR_NULL(num);
num = os_iterObject(iter, -6);
CU_ASSERT_PTR_NULL(num);
num = os_iterObject(iter, 0);
CU_ASSERT_PTR_EQUAL(num, &one);
num = os_iterObject(iter, -5);
CU_ASSERT_PTR_EQUAL(num, &one);
num = os_iterObject(iter, os_iterLength(iter) - 1);
CU_ASSERT_PTR_EQUAL(num, &five);
num = os_iterObject(iter, -1);
CU_ASSERT_PTR_EQUAL(num, &five);
num = os_iterObject(iter, 2);
CU_ASSERT_PTR_EQUAL(num, &three);
num = os_iterObject(iter, -3);
CU_ASSERT_PTR_EQUAL(num, &three);
os_iterFree(iter, NULL);
}
CUnit_Test(os_iter, take_indices)
{
os_iter *iter;
int32_t *num, cnt = 0;
iter = iter_new();
/* index out of range on purpose */
OS_WARNING_MSVC_OFF(28020);
num = os_iterTake(iter, OS_ITER_LENGTH);
OS_WARNING_MSVC_ON(28020);
CU_ASSERT_PTR_NULL(num);
num = os_iterTake(iter, os_iterLength(iter));
CU_ASSERT_PTR_NULL(num);
num = os_iterTake(iter, -6);
CU_ASSERT_PTR_NULL(num);
num = os_iterTake(iter, -5);
CU_ASSERT_PTR_EQUAL(num, &one);
CU_ASSERT_EQUAL(os_iterLength(iter), 4);
num = os_iterTake(iter, -3);
CU_ASSERT_PTR_EQUAL(num, &three);
CU_ASSERT_EQUAL(os_iterLength(iter), 3);
num = os_iterTake(iter, -1);
CU_ASSERT_PTR_EQUAL(num, &five);
CU_ASSERT_EQUAL(os_iterLength(iter), 2);
num = os_iterTake(iter, 1);
CU_ASSERT_PTR_EQUAL(num, &four);
CU_ASSERT_EQUAL(os_iterLength(iter), 1);
num = os_iterTake(iter, 1);
CU_ASSERT_PTR_NULL(num);
num = os_iterTake(iter, -2);
CU_ASSERT_PTR_NULL(num);
num = os_iterTake(iter, -1);
CU_ASSERT_PTR_EQUAL(num, &two);
CU_ASSERT_EQUAL(os_iterLength(iter), 0);
os_iterWalk(iter, &iter_walk_callback, &cnt);
CU_ASSERT_EQUAL(cnt, 0);
os_iterFree(iter, NULL);
}

369
src/os/tests/mutex.c Normal file
View file

@ -0,0 +1,369 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Runner.h"
#include "os/os.h"
#ifdef __VXWORKS__
# ifdef _WRS_KERNEL
# define FORCE_SCHEDULING() taskDelay(1)
# else
# define FORCE_SCHEDULING() sched_yield()
# endif
#else
# define FORCE_SCHEDULING()
#endif
#define BUSYLOOP (100000)
#define MAX_LOOPS (20)
typedef struct {
os_mutex global_mutex;
os_threadId global_data;
int nolock_corrupt_count;
int nolock_loop_count;
int lock_corrupt_count;
int lock_loop_count;
int trylock_corrupt_count;
int trylock_loop_count;
int trylock_busy_count;
int stop;
} shared_data;
os_threadAttr mutex_os_threadAttr;
os_threadId mutex_os_threadId[4];
os_time delay1 = { 5, 0 };
os_time pdelay = { 1, 0 };
os_procId mutex_os_procId;
os_procId mutex_os_procId1;
os_procId mutex_os_procId2;
char buffer[512];
int supported_resultBusy;
int loop;
static shared_data *sd;
char filePath[255];
uint32_t concurrent_lock_thread (_In_opt_ void *arg)
{
int j;
int loopc = 0;
int printed = 0;
while (!sd->stop)
{
if (arg) os_mutexLock (&sd->global_mutex);
sd->global_data = os_threadIdSelf();
FORCE_SCHEDULING();
for (j = 0; j < BUSYLOOP; j++);
if (os_threadIdToInteger(sd->global_data) !=
os_threadIdToInteger(os_threadIdSelf()))
{
if (arg)
{
sd->lock_corrupt_count++;
}
else
{
sd->nolock_corrupt_count++;
}
if (!printed) {
printed++;
}
}
if (arg)
{
sd->lock_loop_count++;
os_mutexUnlock (&sd->global_mutex);
}
else
{
sd->nolock_loop_count++;
}
FORCE_SCHEDULING();
for (j = 0; j < BUSYLOOP; j++);
loopc++;
}
return 0;
}
uint32_t concurrent_trylock_thread (_In_opt_ void *arg)
{
int j;
int loopc = 0;
int printed = 0;
os_result result;
while (!sd->stop)
{
if (arg)
{
while ((result = os_mutexTryLock (&sd->global_mutex))
!= os_resultSuccess)
{
if (result == os_resultBusy)
{
sd->trylock_busy_count++;
}
FORCE_SCHEDULING();
}
}
sd->global_data = os_threadIdSelf();
FORCE_SCHEDULING();
for (j = 0; j < BUSYLOOP; j++);
if (os_threadIdToInteger(sd->global_data) !=
os_threadIdToInteger(os_threadIdSelf()))
{
if (arg)
{
sd->trylock_corrupt_count++;
}
else
{
sd->nolock_corrupt_count++;
}
if (!printed) {
printed++;
}
}
if (arg)
{
sd->trylock_loop_count++;
os_mutexUnlock (&sd->global_mutex);
}
else
{
sd->nolock_loop_count++;
}
FORCE_SCHEDULING();
for (j = 0; j < BUSYLOOP; j++);
loopc++;
}
return 0;
}
CUnit_Suite_Initialize(os_mutex)
{
printf ( "Run os_mutex_Initialize\n" );
os_osInit();
return 0;
}
CUnit_Suite_Cleanup(os_mutex)
{
printf("Run os_mutex_Cleanup\n");
os_osExit();
return 0;
}
/* This test only checks a single-threaded use-case; just API availability.*/
CUnit_Test(os_mutex, basic)
{
os_mutex m;
os_result r;
printf("Starting os_mutex_basic\n");
os_mutexInit(&m);
os_mutexLock(&m);
os_mutexUnlock(&m);
r = os_mutexLock_s(&m);
CU_ASSERT_EQUAL(r, os_resultSuccess); /* Failure can't be forced */
os_mutexUnlock(&m);
os_mutexDestroy(&m);
printf("Ending os_mutex_basic\n");
}
#define RUNTIME_SEC (4)
#define NUM_THREADS (8)
#define OS_STRESS_STOP (0)
#define OS_STRESS_GO (1)
#define THREAD_NAME_LEN (8)
struct os_mutex_stress {
os_threadId tid;
os_mutex m;
os_atomic_uint32_t * flag;
char name[THREAD_NAME_LEN];
};
static uint32_t
os_mutex_init_thr(
void *args)
{
struct os_mutex_stress *state = (struct os_mutex_stress *)args;
os_result r;
uint32_t iterations = 0;
do {
os_mutexInit(&state->m);
r = os_mutexLock_s(&state->m); /* Use the mutex to check that all is OK. */
CU_ASSERT_EQUAL(r, os_resultSuccess); /* Failure can't be forced. */
os_mutexUnlock(&state->m);
os_mutexDestroy(&state->m);
iterations++;
} while ( os_atomic_ld32(state->flag) != OS_STRESS_STOP && r == os_resultSuccess);
printf("%s <%"PRIxMAX">: Performed %u iterations. Stopping now.\n", state->name, os_threadIdToInteger(os_threadIdSelf()), iterations);
return r != os_resultSuccess; /* Return true on faulure */
}
CUnit_Test(os_mutex, init_stress)
{
struct os_mutex_stress threads[NUM_THREADS];
os_threadAttr tattr;
unsigned i;
os_atomic_uint32_t flag = OS_ATOMIC_UINT32_INIT(OS_STRESS_GO);
os_time runtime = { .tv_sec = RUNTIME_SEC, .tv_nsec = 0 };
printf("Starting os_mutex_init_stress\n");
os_threadAttrInit(&tattr);
for ( i = 0; i < NUM_THREADS; i++ ) {
(void) snprintf(&threads[i].name[0], THREAD_NAME_LEN, "thr%u", i);
threads[i].flag = &flag;
os_threadCreate(&threads[i].tid, threads[i].name, &tattr, &os_mutex_init_thr, &threads[i]);
printf("main <%"PRIxMAX">: Started thread '%s' with thread-id %" PRIxMAX "\n", os_threadIdToInteger(os_threadIdSelf()), threads[i].name, os_threadIdToInteger(threads[i].tid));
}
printf("main <%"PRIxMAX">: Test will run for ~%ds with %d threads\n", os_threadIdToInteger(os_threadIdSelf()), RUNTIME_SEC, NUM_THREADS);
os_nanoSleep(runtime);
os_atomic_st32(&flag, OS_STRESS_STOP);
for ( ; i != 0; i-- ) {
uint32_t thread_failed;
os_threadWaitExit(threads[i - 1].tid, &thread_failed);
printf("main <%"PRIxMAX">: Thread %s <%" PRIxMAX "> stopped with result %s.\n", os_threadIdToInteger(os_threadIdSelf()), threads[i - 1].name, os_threadIdToInteger(threads[i - 1].tid), thread_failed ? "FAILED" : "PASS");
CU_ASSERT_FALSE(thread_failed);
}
printf("Ending os_mutex_init_stress\n");
}
CUnit_Test(os_mutex, lock, false)
{
/* Test critical section access with locking and PRIVATE scope */
printf ("Starting tc_os_mutex_lock_001\n");
os_threadAttrInit (&mutex_os_threadAttr);
FORCE_SCHEDULING();
delay1.tv_sec = 3;
printf ("Testing for %d.%9.9d seconds without lock\n", delay1.tv_sec, delay1.tv_nsec);
sd->stop = 0;
sd->nolock_corrupt_count = 0;
sd->nolock_loop_count = 0;
sd->lock_corrupt_count = 0;
sd->lock_loop_count = 0;
sd->trylock_corrupt_count = 0;
sd->trylock_loop_count = 0;
sd->trylock_busy_count = 0;
os_threadCreate (&mutex_os_threadId[0], "thr0", &mutex_os_threadAttr, &concurrent_lock_thread, NULL);
os_threadCreate (&mutex_os_threadId[1], "thr1", &mutex_os_threadAttr, &concurrent_lock_thread, NULL);
os_threadCreate (&mutex_os_threadId[2], "thr2", &mutex_os_threadAttr, &concurrent_trylock_thread, NULL);
os_threadCreate (&mutex_os_threadId[3], "thr3", &mutex_os_threadAttr, &concurrent_trylock_thread, NULL);
os_nanoSleep (delay1);
sd->stop = 1;
os_threadWaitExit (mutex_os_threadId[0], NULL);
os_threadWaitExit (mutex_os_threadId[1], NULL);
os_threadWaitExit (mutex_os_threadId[2], NULL);
os_threadWaitExit (mutex_os_threadId[3], NULL);
printf ("All threads stopped\n");
delay1.tv_sec = 3;
printf ("Testing for %d.%9.9d seconds with lock\n", delay1.tv_sec, delay1.tv_nsec);
sd->stop = 0;
sd->nolock_corrupt_count = 0;
sd->nolock_loop_count = 0;
sd->lock_corrupt_count = 0;
sd->lock_loop_count = 0;
sd->trylock_corrupt_count = 0;
sd->trylock_loop_count = 0;
sd->trylock_busy_count = 0;
os_threadCreate (&mutex_os_threadId[0], "thr0", &mutex_os_threadAttr, &concurrent_lock_thread, (void *)1);
os_threadCreate (&mutex_os_threadId[1], "thr1", &mutex_os_threadAttr, &concurrent_lock_thread, (void *)1);
os_threadCreate (&mutex_os_threadId[2], "thr2", &mutex_os_threadAttr, &concurrent_trylock_thread, (void *)1);
os_threadCreate (&mutex_os_threadId[3], "thr3", &mutex_os_threadAttr, &concurrent_trylock_thread, (void *)1);
os_nanoSleep (delay1);
sd->stop = 1;
os_threadWaitExit (mutex_os_threadId[0], NULL);
os_threadWaitExit (mutex_os_threadId[1], NULL);
os_threadWaitExit (mutex_os_threadId[2], NULL);
os_threadWaitExit (mutex_os_threadId[3], NULL);
printf ("All threads stopped\n");
CU_ASSERT (sd->lock_corrupt_count == 0 || sd->lock_loop_count > 0);
/* Lock mutex with PRIVATE scope and Success result */
printf ("Starting tc_os_mutex_lock_002\n");
os_mutexLock (&sd->global_mutex); //Cannot be checked
os_mutexUnlock (&sd->global_mutex);
/* Lock mutex with PRIVATE scope and Fail result */
printf ("Starting tc_os_mutex_lock_003\n");
printf ("N.A - Failure cannot be forced\n");
/* mutexLock_s with PRIVATE scope and Success result */
printf ("Starting tc_os_mutex_lock_004\n");
CU_ASSERT (os_mutexLock_s (&sd->global_mutex) == os_resultSuccess);
os_mutexUnlock (&sd->global_mutex);
printf ("Ending os_mutex_lock\n");
}
CUnit_Test(os_mutex, trylock, false)
{
os_result result;
/* Test critical section access with trylocking and PRIVATE scope */
printf ("Starting os_mutex_trylock_001\n");
CU_ASSERT (sd->trylock_corrupt_count == 0 || sd->trylock_loop_count > 0);
/* TryLock mutex with PRIVATE scope and Success result */
printf ("Starting os_mutex_trylock_002\n");
result = os_mutexTryLock (&sd->global_mutex);
CU_ASSERT (result == os_resultSuccess);
/* TryLock mutex with PRIVATE scope and Busy result */
printf ("Starting os_mutex_trylock_003\n");
#if defined(__VXWORKS__) && !defined(_WRS_KERNEL)
printf ("N.A - Mutexes are recursive on VxWorks RTP so this test is disabled\n");
#endif
result = os_mutexTryLock (&sd->global_mutex);
CU_ASSERT (result == os_resultBusy);
printf ("Ending os_mutex_trylock\n");
}
CUnit_Test(os_mutex, destroy, false)
{
/* Deinitialize mutex with PRIVATE scope and Success result */
printf ("Starting os_mutex_destroy_001\n");
os_mutexDestroy(&sd->global_mutex); // Cannot be checked directly - Success is assumed
/* Deinitialize mutex with PRIVATE scope and Fail result */
printf ("Starting os_mutex_destroy_002\n");
printf ("N.A - Failure cannot be forced\n");
printf ("Ending os_mutex_destroy\n");
}

167
src/os/tests/once.c Normal file
View file

@ -0,0 +1,167 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Runner.h"
#include "os/os.h"
/* Suite os_once*/
CUnit_Suite_Initialize(os_once)
{
printf("Run os_once_Initialize\n");
os_osInit();
return 0;
}
CUnit_Suite_Cleanup(os_once)
{
printf("Run os_once_Cleanup\n");
os_osExit();
return 0;
}
static uint32_t counter;
static void once_func(void)
{
counter++;
printf("Counter increased to %u\n", counter);
}
/* This test only checks a single-threaded use-case; mostly API availability and mere basics.*/
CUnit_Test(os_once, basic)
{
static os_once_t init = OS_ONCE_T_STATIC_INIT;
printf("Starting os_once_basic\n");
os_once(&init, &once_func);
CU_ASSERT(counter == 1);
os_once(&init, &once_func);
CU_ASSERT(counter == 1);
printf("Ending os_once_basic\n");
}
/* Update atomically, so that a failing os_once can be detected and isn't potentially lost due to a race. */
static os_atomic_uint32_t counter1 = OS_ATOMIC_UINT32_INIT(0);
static void once1_func(void)
{
os_time delay = { .tv_sec = 0,.tv_nsec = 250000000 }; /* 250ms */
os_nanoSleep(delay);
printf("%"PRIxMAX": Counter 1 increased to %u\n", os_threadIdToInteger(os_threadIdSelf()), os_atomic_inc32_nv(&counter1));
}
/* Update atomically, so that a failing os_once can be detected and isn't potentially lost due to a race. */
static os_atomic_uint32_t counter2 = OS_ATOMIC_UINT32_INIT(0);
static void once2_func(void)
{
os_time delay = { .tv_sec = 0, .tv_nsec = 500000000 }; /* 500ms */
os_nanoSleep(delay);
printf("%"PRIxMAX": Counter 2 increased to %u\n", os_threadIdToInteger(os_threadIdSelf()), os_atomic_inc32_nv(&counter2));
}
#define OS_ONCE_NUM_THREADS (20)
#define OS_ONCE_STATE_STARTUP (0)
#define OS_ONCE_STATE_GO (1)
struct os_once_parallel {
os_mutex m;
os_cond c;
os_atomic_uint32_t flag;
os_atomic_uint32_t started;
os_once_t init1;
os_once_t init2;
};
static uint32_t
os_once_parallel_thr(
void *args)
{
const os_time sched_delay = { .tv_sec = 0,.tv_nsec = 25000000 }; /* 25ms */
const os_time poll_delay = { .tv_sec = 0,.tv_nsec = 5000000 }; /* 5ms */
struct os_once_parallel *state = (struct os_once_parallel *)args;
bool done = false;
bool started = false;
while (!done) {
switch (os_atomic_ld32(&state->flag)) {
case OS_ONCE_STATE_STARTUP:
if (!started && (os_atomic_inc32_nv(&state->started) == OS_ONCE_NUM_THREADS)) {
printf("%"PRIxMAX": Started. Signalling GO.\n", os_threadIdToInteger(os_threadIdSelf()));
os_atomic_st32(&state->flag, OS_ONCE_STATE_GO);
os_mutexLock(&state->m);
os_condBroadcast(&state->c);
os_mutexUnlock(&state->m);
os_nanoSleep(sched_delay);
}
else {
if(!started ) printf("%"PRIxMAX": Started. Awaiting GO.\n", os_threadIdToInteger(os_threadIdSelf()));
os_mutexLock(&state->m);
(void) os_condTimedWait(&state->c, &state->m, &poll_delay);
os_mutexUnlock(&state->m);
}
started = true;
break;
case OS_ONCE_STATE_GO:
os_once(&state->init1, &once1_func);
os_once(&state->init2, &once2_func);
/* Fallthrough intentional */
default:
done = true;
break;
}
}
return 0;
}
CUnit_Test(os_once, parallel)
{
os_threadId threads[OS_ONCE_NUM_THREADS];
struct os_once_parallel state = {
.init1 = OS_ONCE_T_STATIC_INIT,
.init2 = OS_ONCE_T_STATIC_INIT,
.started = OS_ATOMIC_UINT32_INIT(0),
.flag = OS_ATOMIC_UINT32_INIT(OS_ONCE_STATE_STARTUP)
};
os_threadAttr tattr;
unsigned i;
printf("Starting os_once_parallel\n");
os_mutexInit(&state.m);
os_condInit(&state.c, &state.m);
os_threadAttrInit(&tattr);
for (i = 0; i < OS_ONCE_NUM_THREADS; i++) {
char thrname[16];
(void) snprintf(thrname, sizeof thrname, "thr%u", i);
os_threadCreate(&threads[i], thrname, &tattr, &os_once_parallel_thr, &state);
printf("%"PRIxMAX": Started thread '%s' with thread-id %" PRIxMAX "\n", os_threadIdToInteger(os_threadIdSelf()), thrname, os_threadIdToInteger(threads[i]));
}
for (; i != 0; i--) {
os_threadWaitExit(threads[i - 1], NULL);
printf("%"PRIxMAX": Thread with thread-id %" PRIxMAX " stopped.\n", os_threadIdToInteger(os_threadIdSelf()), os_threadIdToInteger(threads[i - 1]));
}
CU_ASSERT(os_atomic_ld32(&counter1) == 1);
CU_ASSERT(os_atomic_ld32(&counter2) == 1);
os_condDestroy(&state.c);
os_mutexDestroy(&state.m);
printf("Ending os_once_parallel\n");
}

404
src/os/tests/report.c Normal file
View file

@ -0,0 +1,404 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Runner.h"
#include "os/os.h"
#include "os/os_project.h"
#include <stdio.h>
CUnit_Suite_Initialize(os_report)
{
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_ERRORFILE=vdds_test_error");
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_INFOFILE=vdds_test_info");
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_LOGAPPEND=TRUE");
return 0;
}
void remove_logs()
{
const char * error_file_name = os_getenv(OS_PROJECT_NAME_NOSPACE_CAPS"_ERRORFILE");
const char * info_file_name = os_getenv(OS_PROJECT_NAME_NOSPACE_CAPS"_INFOFILE");
os_remove(error_file_name);
os_remove(info_file_name);
}
void check_existence(os_result error_log_existence, os_result info_log_existence)
{
const char * error_file_name = os_getenv(OS_PROJECT_NAME_NOSPACE_CAPS"_ERRORFILE");
const char * info_file_name = os_getenv(OS_PROJECT_NAME_NOSPACE_CAPS"_INFOFILE");
CU_ASSERT(os_access(error_file_name, OS_ROK) == error_log_existence);
CU_ASSERT(os_access(info_file_name, OS_ROK) == info_log_existence);
}
CUnit_Suite_Cleanup(os_report)
{
remove_logs();
return 0;
}
CUnit_Test(os_report, re_init)
{
os_reportInit(true);
OS_INFO(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
OS_ERROR(OS_FUNCTION, 0, "os_report-error-test %d", __LINE__);
check_existence(os_resultSuccess, os_resultSuccess);
os_reportExit();
os_reportInit(true);
check_existence(os_resultSuccess, os_resultSuccess);
OS_INFO(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, stack_critical)
{
os_reportInit(true);
OS_REPORT_STACK();
OS_CRITICAL(OS_FUNCTION, 0, "os_report-error-test %d", __LINE__);
check_existence(os_resultFail, os_resultFail);
OS_REPORT_FLUSH(false);
// Since a critical is logged, the error log should be created
check_existence(os_resultSuccess, os_resultFail);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, stack_non_critical)
{
os_reportInit(true);
OS_REPORT_STACK();
OS_ERROR(OS_FUNCTION, 0, "os_report-error-test %d", __LINE__);
check_existence(os_resultFail, os_resultFail);
OS_REPORT_FLUSH(false);
// Since a non critical is logged, the error log should not be created
check_existence(os_resultFail, os_resultFail);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, error_file_creation_critical)
{
os_reportInit(true);
OS_CRITICAL(OS_FUNCTION, 0, "os_report-critical-test %d", __LINE__);
check_existence(os_resultSuccess, os_resultFail);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, error_file_creation_fatal)
{
os_reportInit(true);
OS_FATAL(OS_FUNCTION, 0, "os_report-fatal-test %d", __LINE__);
check_existence(os_resultSuccess, os_resultFail);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, info_file_creation_warning)
{
os_reportInit(true);
OS_WARNING(OS_FUNCTION, 0, "os_report-warning-test %d", __LINE__);
check_existence(os_resultFail, os_resultSuccess);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, info_file_creation_info)
{
os_reportInit(true);
OS_INFO(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
check_existence(os_resultFail, os_resultSuccess);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, verbosity_low)
{
os_reportInit(true);
check_existence(os_resultFail, os_resultFail);
os_reportVerbosity = OS_REPORT_ERROR;
OS_WARNING(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
check_existence(os_resultFail, os_resultFail);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, verbosity_high)
{
os_reportInit(true);
check_existence(os_resultFail, os_resultFail);
os_reportVerbosity = OS_REPORT_DEBUG;
OS_WARNING(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
check_existence(os_resultFail, os_resultSuccess);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, verbosity_equal)
{
os_reportInit(true);
check_existence(os_resultFail, os_resultFail);
os_reportVerbosity = OS_REPORT_WARNING;
OS_WARNING(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
check_existence(os_resultFail, os_resultSuccess);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, stack_verbosity_low)
{
os_reportInit(true);
check_existence(os_resultFail, os_resultFail);
os_reportVerbosity = OS_REPORT_ERROR;
OS_REPORT_STACK();
OS_WARNING(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
OS_REPORT_FLUSH(true);
check_existence(os_resultFail, os_resultFail);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, stack_verbosity_high)
{
os_reportInit(true);
check_existence(os_resultFail, os_resultFail);
os_reportVerbosity = OS_REPORT_DEBUG;
OS_REPORT_STACK();
OS_WARNING(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
OS_REPORT_FLUSH(true);
check_existence(os_resultFail, os_resultSuccess);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, stack_verbosity_equal)
{
os_reportInit(true);
check_existence(os_resultFail, os_resultFail);
os_reportVerbosity = OS_REPORT_WARNING;
OS_REPORT_STACK();
OS_WARNING(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
OS_REPORT_FLUSH(true);
check_existence(os_resultFail, os_resultSuccess);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, no_log_append)
{
os_reportInit(true);
check_existence(os_resultFail, os_resultFail);
OS_ERROR(OS_FUNCTION, 0, "os_report-error-test %d", __LINE__);
OS_INFO(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
check_existence(os_resultSuccess, os_resultSuccess);
os_reportExit();
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_LOGAPPEND=FALSE");
os_reportInit(true);
// Both logs should be deleted
check_existence(os_resultFail, os_resultFail);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, log_dir)
{
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_LOGPATH=.");
os_reportInit(true);
check_existence(os_resultFail, os_resultFail);
OS_ERROR(OS_FUNCTION, 0, "os_report-error-test %d", __LINE__);
OS_INFO(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
check_existence(os_resultSuccess, os_resultSuccess);
os_reportExit();
remove_logs();
}
CUnit_Test(os_report, verbosity_env_value_info)
{
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_VERBOSITY=0");
os_reportInit(true);
check_existence(os_resultFail, os_resultFail);
OS_ERROR(OS_FUNCTION, 0, "os_report-error-test %d", __LINE__);
OS_INFO(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
check_existence(os_resultSuccess, os_resultSuccess);
os_reportExit();
remove_logs();
//reset for other tests.
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_VERBOSITY=");
}
CUnit_Test(os_report, verbosity_env_value_error)
{
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_VERBOSITY=3");
os_reportInit(true);
check_existence(os_resultFail, os_resultFail);
OS_ERROR(OS_FUNCTION, 0, "os_report-error-test %d", __LINE__);
OS_INFO(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
check_existence(os_resultSuccess, os_resultFail);
os_reportExit();
remove_logs();
//reset for other tests.
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_VERBOSITY=");
}
CUnit_Test(os_report, verbosity_env_value_error_as_string)
{
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_VERBOSITY=ERROR");
os_reportInit(true);
check_existence(os_resultFail, os_resultFail);
OS_ERROR(OS_FUNCTION, 0, "os_report-error-test %d", __LINE__);
OS_DEBUG(OS_FUNCTION, 0, "os_report-info-test %d", __LINE__);
check_existence(os_resultSuccess, os_resultFail);
os_reportExit();
remove_logs();
//reset for other tests.
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_VERBOSITY=");
}
CUnit_Test(os_report, verbosity_wrong_env_value)
{
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_VERBOSITY=WRONG");
os_reportInit(true);
check_existence(os_resultFail, os_resultFail);
OS_ERROR(OS_FUNCTION, 0, "os_report-error-test %d", __LINE__);
OS_DEBUG(OS_FUNCTION, 0, "os_report-error-test %d", __LINE__);
check_existence(os_resultSuccess, os_resultFail);
os_reportExit();
remove_logs();
//reset for other tests.
os_putenv(OS_PROJECT_NAME_NOSPACE_CAPS"_VERBOSITY=");
}

577
src/os/tests/rwlock.c Normal file
View file

@ -0,0 +1,577 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Runner.h"
#include "os/os.h"
#ifdef __VXWORKS__
# ifdef _WRS_KERNEL
# define FORCE_SCHEDULING() taskDelay(1)
# else
# define FORCE_SCHEDULING() sched_yield()
# endif
#else
# define FORCE_SCHEDULING()
#endif
#define ENABLE_TRACING 0
#define BUSYLOOP (100000)
#define MAX_LOOPS (20)
#define RWLOCK_THREADS 12
os_time rwlock_delay = { 0, 500 };
typedef struct Par {
int lock;
int index;
int read_access;
int concurrent_read_access;
} Par;
typedef struct {
os_rwlock global_rwlock;
os_threadId global_data;
os_threadId read_thread[RWLOCK_THREADS];
int read_corrupt_count;
int write_corrupt_count;
int concurrent_read_access;
int concurrent_write_access;
int tryread_corrupt_count;
int trywrite_corrupt_count;
int concurrent_tryread_access;
int concurrent_trywrite_access;
int tryread_busy_count;
int trywrite_busy_count;
int stop;
} shared_data;
os_threadAttr rwlock_os_threadAttr;
os_threadId rwlock_os_threadId[RWLOCK_THREADS];
static int i;
char buffer[512];
os_procId rwlock_os_procId;
int supported_resultBusy;
int loop;
static shared_data sd;
uint32_t concurrent_write_thread (_In_ void *arg)
{
struct Par *par = (struct Par *)arg;
os_threadId myid = os_threadIdSelf();
int printed = 0;
while (!sd.stop) {
if (par->lock) {
os_rwlockWrite (&sd.global_rwlock);
}
sd.global_data = myid;
FORCE_SCHEDULING();
os_nanoSleep( rwlock_delay );
if (os_threadIdToInteger(sd.global_data) != os_threadIdToInteger(myid)) {
sd.write_corrupt_count++;
if (!printed) {
/* printf ("Critical section corrupted during write [%d]\n", par->index); */
printed++;
}
}
sd.concurrent_write_access++;
if (par->lock) {
os_rwlockUnlock (&sd.global_rwlock);
}
FORCE_SCHEDULING();
os_nanoSleep( rwlock_delay );
}
return 0;
}
uint32_t concurrent_read_thread (_In_ void *arg)
{
int j;
os_threadId prevId;
struct Par *par = (struct Par *)arg;
int printed = 0;
while (!sd.stop) {
if (par->lock) {
os_rwlockRead (&sd.global_rwlock);
}
sd.read_thread[par->index] = os_threadIdSelf();
par->read_access++;
prevId = sd.global_data;
FORCE_SCHEDULING();
for (j = 0; j < BUSYLOOP/2; j++) {
if (os_threadIdToInteger(sd.global_data) !=
os_threadIdToInteger(prevId)) {
sd.read_corrupt_count++;
if (!printed) {
/* printf ("Critical section corrupted during read [%d]\n", par->index); */
printed++;
}
prevId = sd.global_data;
}
FORCE_SCHEDULING();
}
if (os_threadIdToInteger(sd.read_thread[0]) ||
os_threadIdToInteger(sd.read_thread[1]) ||
os_threadIdToInteger(sd.read_thread[2]) ||
os_threadIdToInteger(sd.read_thread[3]) ||
os_threadIdToInteger(sd.read_thread[4]) ||
os_threadIdToInteger(sd.read_thread[5]) ||
os_threadIdToInteger(sd.read_thread[6]) ||
os_threadIdToInteger(sd.read_thread[7]) ||
os_threadIdToInteger(sd.read_thread[8]) ||
os_threadIdToInteger(sd.read_thread[9]) ||
os_threadIdToInteger(sd.read_thread[10]) ||
os_threadIdToInteger(sd.read_thread[11])) {
par->concurrent_read_access++;
}
sd.concurrent_read_access++;
if (par->lock) {
os_rwlockUnlock (&sd.global_rwlock);
}
FORCE_SCHEDULING();
os_nanoSleep( rwlock_delay );
}
return 0;
}
uint32_t concurrent_trywrite_thread (_In_ void *arg)
{
struct Par *par = (struct Par *)arg;
os_result result;
os_threadId myid = os_threadIdSelf();
int printed = 0;
while (!sd.stop) {
if (par->lock) {
while ((result = os_rwlockTryWrite (&sd.global_rwlock)) != os_resultSuccess) {
if (result == os_resultBusy) {
sd.trywrite_busy_count++;
}
FORCE_SCHEDULING();
}
}
sd.global_data = os_threadIdSelf();
FORCE_SCHEDULING();
os_nanoSleep( rwlock_delay );
if (os_threadIdToInteger(sd.global_data) != os_threadIdToInteger(myid)) {
sd.trywrite_corrupt_count++;
if (!printed) {
/* printf ("Critical section corrupted during trywrite [%d]\n", par->index); */
printed++;
}
}
sd.concurrent_trywrite_access++;
if (par->lock) {
os_rwlockUnlock (&sd.global_rwlock);
}
FORCE_SCHEDULING();
os_nanoSleep( rwlock_delay );
}
return 0;
}
uint32_t concurrent_tryread_thread (_In_ void *arg)
{
int j;
os_threadId prevId;
struct Par *par = (struct Par *)arg;
os_result result;
int printed = 0;
while (!sd.stop) {
if (par->lock) {
while ((result = os_rwlockTryRead (&sd.global_rwlock)) != os_resultSuccess) {
if (result == os_resultBusy) {
sd.tryread_busy_count++;
}
FORCE_SCHEDULING();
}
}
sd.read_thread[par->index] = os_threadIdSelf();
par->read_access++;
prevId = sd.global_data;
FORCE_SCHEDULING();
for (j = 0; j < BUSYLOOP/2; j++) {
if (os_threadIdToInteger(sd.global_data) !=
os_threadIdToInteger(prevId)) {
sd.tryread_corrupt_count++;
if (!printed) {
/* printf ("Critical section corrupted during read [%d]\n", par->index); */
printed++;
}
prevId = sd.global_data;
}
FORCE_SCHEDULING();
}
if (os_threadIdToInteger(sd.read_thread[0]) ||
os_threadIdToInteger(sd.read_thread[1]) ||
os_threadIdToInteger(sd.read_thread[2]) ||
os_threadIdToInteger(sd.read_thread[3]) ||
os_threadIdToInteger(sd.read_thread[4]) ||
os_threadIdToInteger(sd.read_thread[5]) ||
os_threadIdToInteger(sd.read_thread[6]) ||
os_threadIdToInteger(sd.read_thread[7]) ||
os_threadIdToInteger(sd.read_thread[8]) ||
os_threadIdToInteger(sd.read_thread[9]) ||
os_threadIdToInteger(sd.read_thread[10]) ||
os_threadIdToInteger(sd.read_thread[11])) {
par->concurrent_read_access++;
}
sd.concurrent_tryread_access++;
if (par->lock) {
os_rwlockUnlock (&sd.global_rwlock);
}
FORCE_SCHEDULING();
os_nanoSleep( rwlock_delay );
}
return 0;
}
CUnit_Suite_Initialize(os_rwlock)
{
int result = 0;
os_osInit();
printf("Run os_rwlock_Initialize\n");
#ifdef OS_LINUX_RWLOCK_H149C
supported_resultBusy = 1;
#else
supported_resultBusy = 0;
#endif
return result;
}
CUnit_Suite_Cleanup(os_rwlock)
{
int result = 0;
printf("Run os_rwlock_Cleanup\n");
os_osExit();
return result;
}
CUnit_Test(os_rwlock, init)
{
/* Initilalize reader/writer lock with PRIVATE scope and Success result */
printf ("Starting os_rwlock_init_001\n");
os_rwlockInit (&sd.global_rwlock);
/* Initilalize reader/writer lock with Fail result */
printf ("Starting os_rwlock_init_001\n");
printf ("N.A - Failure cannot be forced\n");
printf ("Ending os_rwlock_init\n");
}
CUnit_Test(os_rwlock, read, false)
{
os_time rdelay = { 3, 0 };
struct Par par[RWLOCK_THREADS];
/* Test critical section access without locking to show problem */
printf ("Starting os_rwlock_read_001\n");
rdelay.tv_sec = 3;
printf ("Testing for %d.%9.9d seconds without lock\n", rdelay.tv_sec, rdelay.tv_nsec);
sd.read_corrupt_count = 0;
sd.write_corrupt_count = 0;
sd.concurrent_read_access = 0;
sd.concurrent_write_access = 0;
sd.tryread_corrupt_count = 0;
sd.trywrite_corrupt_count = 0;
sd.concurrent_tryread_access = 0;
sd.concurrent_trywrite_access = 0;
sd.tryread_busy_count = 0;
sd.trywrite_busy_count = 0;
sd.stop = 0;
for (i = 0; i < RWLOCK_THREADS; i++) {
par[i].concurrent_read_access = 0;
par[i].read_access = 0;
par[i].lock = 0;
par[i].index = i;
}
os_threadAttrInit (&rwlock_os_threadAttr);
os_threadCreate (&rwlock_os_threadId[0], "thr0", &rwlock_os_threadAttr, &concurrent_write_thread, (void *)&par[0]);
os_threadCreate (&rwlock_os_threadId[1], "thr1", &rwlock_os_threadAttr, &concurrent_write_thread, (void *)&par[1]);
os_threadCreate (&rwlock_os_threadId[2], "thr2", &rwlock_os_threadAttr, &concurrent_read_thread, (void *)&par[2]);
os_threadCreate (&rwlock_os_threadId[3], "thr3", &rwlock_os_threadAttr, &concurrent_read_thread, (void *)&par[3]);
os_threadCreate (&rwlock_os_threadId[4], "thr4", &rwlock_os_threadAttr, &concurrent_trywrite_thread, (void *)&par[4]);
os_threadCreate (&rwlock_os_threadId[5], "thr5", &rwlock_os_threadAttr, &concurrent_trywrite_thread, (void *)&par[5]);
os_threadCreate (&rwlock_os_threadId[6], "thr6", &rwlock_os_threadAttr, &concurrent_tryread_thread, (void *)&par[6]);
os_threadCreate (&rwlock_os_threadId[7], "thr7", &rwlock_os_threadAttr, &concurrent_tryread_thread, (void *)&par[7]);
os_nanoSleep (rdelay);
sd.stop = 1;
os_threadWaitExit (rwlock_os_threadId[0], NULL);
os_threadWaitExit (rwlock_os_threadId[1], NULL);
os_threadWaitExit (rwlock_os_threadId[2], NULL);
os_threadWaitExit (rwlock_os_threadId[3], NULL);
os_threadWaitExit (rwlock_os_threadId[4], NULL);
os_threadWaitExit (rwlock_os_threadId[5], NULL);
os_threadWaitExit (rwlock_os_threadId[6], NULL);
os_threadWaitExit (rwlock_os_threadId[7], NULL);
printf ("All threads stopped\n");
for (i = 2; i < 4; i++) {
printf ("total read access %d, concurrent read access %d for thread %d\n",
par[i].read_access, par[i].concurrent_read_access, i);
}
for (i = 6; i < 8; i++) {
printf ("total try read access %d, concurrent try read access %d for thread %d\n",
par[i].read_access, par[i].concurrent_read_access, i);
}
printf ("read_corrupt_count = %d\n", sd.read_corrupt_count);
printf ("write_corrupt_count = %d\n", sd.write_corrupt_count);
printf ("tryread_corrupt_count = %d\n", sd.tryread_corrupt_count);
printf ("trywrite_corrupt_count = %d\n", sd.trywrite_corrupt_count);
printf ("concurrent_read_access = %d\n", sd.concurrent_read_access);
printf ("concurrent_write_access = %d\n", sd.concurrent_write_access);
printf ("concurrent_tryread_access = %d\n", sd.concurrent_tryread_access);
printf ("concurrent_trywrite_access = %d\n", sd.concurrent_trywrite_access);
sprintf (buffer, "Corrupt counter = %d, Loop counter is %d",
sd.read_corrupt_count + sd.write_corrupt_count + sd.tryread_corrupt_count + sd.trywrite_corrupt_count,
sd.concurrent_read_access + sd.concurrent_write_access + sd.concurrent_tryread_access + sd.concurrent_trywrite_access);
CU_ASSERT((sd.read_corrupt_count > 0 ||
sd.write_corrupt_count > 0 ||
sd.tryread_corrupt_count > 0 ||
sd.trywrite_corrupt_count > 0) &&
sd.concurrent_read_access > 0 &&
sd.concurrent_write_access > 0 &&
sd.concurrent_tryread_access > 0 &&
sd.concurrent_trywrite_access > 0);
/* Test critical section READ access with locking and PRIVATE scope */
printf ("Starting os_rwlock_read_002\n");
rdelay.tv_sec = 3;
printf ("Testing for %d.%9.9d seconds with lock\n", rdelay.tv_sec, rdelay.tv_nsec);
sd.read_corrupt_count = 0;
sd.write_corrupt_count = 0;
sd.concurrent_read_access = 0;
sd.concurrent_write_access = 0;
sd.tryread_corrupt_count = 0;
sd.trywrite_corrupt_count = 0;
sd.concurrent_tryread_access = 0;
sd.concurrent_trywrite_access = 0;
sd.tryread_busy_count = 0;
sd.trywrite_busy_count = 0;
sd.stop = 0;
for (i = 0; i < RWLOCK_THREADS; i++) {
par[i].concurrent_read_access = 0;
par[i].read_access = 0;
par[i].lock = 1;
par[i].index = i;
}
os_threadAttrInit (&rwlock_os_threadAttr);
os_threadCreate (&rwlock_os_threadId[0], "thr0", &rwlock_os_threadAttr, &concurrent_write_thread, (void *)&par[0]);
os_threadCreate (&rwlock_os_threadId[1], "thr1", &rwlock_os_threadAttr, &concurrent_write_thread, (void *)&par[1]);
os_threadCreate (&rwlock_os_threadId[2], "thr2", &rwlock_os_threadAttr, &concurrent_read_thread, (void *)&par[2]);
os_threadCreate (&rwlock_os_threadId[3], "thr3", &rwlock_os_threadAttr, &concurrent_read_thread, (void *)&par[3]);
os_threadCreate (&rwlock_os_threadId[4], "thr4", &rwlock_os_threadAttr, &concurrent_trywrite_thread, (void *)&par[4]);
os_threadCreate (&rwlock_os_threadId[5], "thr5", &rwlock_os_threadAttr, &concurrent_trywrite_thread, (void *)&par[5]);
os_threadCreate (&rwlock_os_threadId[6], "thr6", &rwlock_os_threadAttr, &concurrent_tryread_thread, (void *)&par[6]);
os_threadCreate (&rwlock_os_threadId[7], "thr7", &rwlock_os_threadAttr, &concurrent_tryread_thread, (void *)&par[7]);
os_nanoSleep (rdelay);
sd.stop = 1;
os_threadWaitExit (rwlock_os_threadId[0], NULL);
os_threadWaitExit (rwlock_os_threadId[1], NULL);
os_threadWaitExit (rwlock_os_threadId[2], NULL);
os_threadWaitExit (rwlock_os_threadId[3], NULL);
os_threadWaitExit (rwlock_os_threadId[4], NULL);
os_threadWaitExit (rwlock_os_threadId[5], NULL);
os_threadWaitExit (rwlock_os_threadId[6], NULL);
os_threadWaitExit (rwlock_os_threadId[7], NULL);
printf ("All threads stopped\n");
for (i = 2; i < 4; i++) {
printf ("total read access %d, concurrent read access %d for thread %d\n",
par[i].read_access, par[i].concurrent_read_access, i);
}
for (i = 6; i < 8; i++) {
printf ("total try read access %d, concurrent try read access %d for thread %d\n",
par[i].read_access, par[i].concurrent_read_access, i);
}
sprintf (buffer, "Corrupt read counter = %d, Read loop counter is %d", sd.read_corrupt_count, sd.concurrent_read_access);
CU_ASSERT (sd.read_corrupt_count == 0 && sd.concurrent_read_access > 0);
/* Test read on rwlock with PRIVATE scope and Success result & not locked */
printf ("Starting os_rwlock_read_003\n");
os_rwlockRead (&sd.global_rwlock); // Cannot be checked
os_rwlockUnlock (&sd.global_rwlock);
/* Test read on rwlock with PRIVATE scope and Success result & locked by read */
printf ("Starting os_rwlock_read_004\n");
printf ("N.A - Not implemented\n");
/* Test read on rwlock with PRIVATE scope and Fail result */
printf ("Starting os_rwlock_read_005\n");
printf ("N.A - Failure cannot be forced\n");
printf ("Ending os_rwlock_read\n");
}
CUnit_Test(os_rwlock, write, false)
{
/* Test critical section WRITE access with locking and PRIVATE scope */
printf ("Starting os_rwlock_write_001\n");
sprintf (buffer, "Corrupt write counter = %d, Write loop counter is %d", sd.write_corrupt_count, sd.concurrent_write_access);
CU_ASSERT (sd.write_corrupt_count == 0 && sd.concurrent_write_access > 0);
/* Test write on rwlock with PRIVATE scope and Success result */
printf ("Starting os_rwlock_write_002\n");
os_rwlockWrite (&sd.global_rwlock); //Cannot be checked
os_rwlockUnlock (&sd.global_rwlock);
/* Test write on rwlock with PRIVATE scope and Fail result */
printf ("Starting os_rwlock_write_003\n");
printf ("N.A - Failure cannot be forced\n");
printf ("Ending tc_rwlockWrite\n");
}
CUnit_Test(rwlock, tryread, false)
{
os_result result;
/* Test critical section READ access with trylocking and PRIVATE scope */
printf ("Starting os_rwlock_tryread_001\n");
sprintf (buffer, "Corrupt tryread counter = %d, Tryread loop counter is %d, Busy counter = %d", sd.tryread_corrupt_count, sd.concurrent_tryread_access, sd.tryread_busy_count);
CU_ASSERT (sd.tryread_corrupt_count == 0 && sd.concurrent_tryread_access > 0);
/* Test try read on rwlock with PRIVATE scope and Success result & not locked */
printf ("Starting os_rwlock_tryread_002\n");
result = os_rwlockTryRead (&sd.global_rwlock);
CU_ASSERT (result == os_resultSuccess);
os_rwlockUnlock (&sd.global_rwlock);
/* Test try read on rwlock with PRIVATE scope and Success result & locked by read */
printf ("Starting os_rwlock_tryread_003\n");
printf ("N.A - Not implemented\n");
/* Test try read on rwlock with PRIVATE scope and Busy result & locked by write */
printf ("Starting os_rwlock_tryread_004\n");
printf ("N.A - Not implemented\n");
/* Test try read on rwlock with PRIVATE scope and Fail result */
printf ("Starting os_rwlock_tryread_005\n");
printf ("N.A - Failure cannot be forced\n");
printf ("Ending os_rwlock_tryread\n");
}
CUnit_Test(os_rwlock, trywrite, false)
{
os_result result;
/* Test critical section WRITE access with trylocking and PRIVATE scope */
printf ("Starting os_rwlock_trywrite_001\n");
sprintf (buffer, "Corrupt trywrite counter = %d, Trywrite loop counter is %d, Busy counter = %d", sd.trywrite_corrupt_count, sd.concurrent_trywrite_access, sd.trywrite_busy_count);
CU_ASSERT (sd.trywrite_corrupt_count == 0 && sd.concurrent_trywrite_access > 0);
/* Test try write on rwlock with PRIVATE scope and Success result */
printf ("Starting os_rwlock_trywrite_002\n");
result = os_rwlockTryWrite (&sd.global_rwlock);
CU_ASSERT (result == os_resultSuccess);
os_rwlockUnlock (&sd.global_rwlock);
/* Test try write on rwlock with PRIVATE scope and Busy result & locked by read */
printf ("Starting os_rwlock_trywrite_003\n");
printf ("N.A - Not implemented\n");
/* Test try write on rwlock with PRIVATE scope and Busy result & locked by write */
printf ("Starting os_rwlock_trywrite_004\n");
printf ("N.A - Not implemented\n");
/* Test try write on rwlock with PRIVATE scope and Fail result */
printf ("Starting os_rwlock_trywrite_005\n");
printf ("N.A - Failure cannot be forced\n");
printf ("Ending os_rwlock_trywrite\n");
}
CUnit_Test(os_rwlock, unlock, false)
{
os_result result;
/* Unlock rwlock with PRIVATE scope and Success result and claimed with read */
printf ("Starting os_rwlock_unlock_001\n");
os_rwlockRead (&sd.global_rwlock);
os_rwlockUnlock (&sd.global_rwlock); //Cannot be checked
/* Unlock rwlock with PRIVATE scope and Success result and claimed with try read */
printf ("Starting os_rwlock_unlock_002\n");
result = os_rwlockTryRead (&sd.global_rwlock);
CU_ASSERT (result == os_resultSuccess);
os_rwlockUnlock (&sd.global_rwlock);
/* Unlock rwlock with PRIVATE scope and Success result and claimed with write */
printf ("Starting os_rwlock_unlock_003\n");
os_rwlockWrite (&sd.global_rwlock);
os_rwlockUnlock (&sd.global_rwlock); //Cannot be checked
/* Unlock rwlock with PRIVATE scope and Success result and claimed with try write */
printf ("Starting os_rwlock_unlock_004\n");
result = os_rwlockTryWrite (&sd.global_rwlock);
CU_ASSERT (result == os_resultSuccess);
os_rwlockUnlock (&sd.global_rwlock);
/* Unlock rwlock with PRIVATE scope and Fail result */
printf ("Starting os_rwlock_unlock_005\n");
printf ("N.A - Failure cannot be forced\n");
printf ("Ending tc_rwlockUnlock\n");
}
CUnit_Test(os_rwlock, destroy, false)
{
/* Deinitialize rwlock with PRIVATE scope and Success result */
printf ("Starting os_rwlock_destroy_001\n");
os_rwlockDestroy (&sd.global_rwlock); //Cannot be checked
/* Deinitialize rwlock with PRIVATE scope and Fail result */
printf ("Starting os_rwlock_destroy_002\n");
printf ("N.A - Failure cannot be forced\n");
printf ("Ending tc_rwlockDestroy\n");
}
CUnit_Test(os_rwlock, destroy_shared)
{
os_rwlock mylock;
os_rwlockInit(&mylock);
os_rwlockRead(&mylock);
os_rwlockUnlock(&mylock);
/* This test used to assert on a debug-build on Windows. Failure can't be forced, but if
* someone adds the naively sensible assert again, this test won't run on a debug-build. */
os_rwlockDestroy(&mylock);
CU_PASS("os_rwlockDestroy succeeds after releasing a shared lock");
}

869
src/os/tests/stdlib.c Executable file
View file

@ -0,0 +1,869 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Runner.h"
#include "os/os.h"
#ifndef WINCE
#include <fcntl.h>
#endif
#if (defined WIN32 || defined WIN64)
#include <direct.h>
#include <Windows.h>
#endif
static const os_time wait_time_out = { 1, 0 };
static FILE *file;
#define ENABLE_TRACING 0
#define FLOCKFILE_THREAD1_INPUT1 "thread1_flockfile_proc: *** input 1 ***"
#define FLOCKFILE_THREAD1_INPUT3 "thread1_flockfile_proc: *** input 3 ***"
#define FLOCKFILE_THREAD2_INPUT2 "thread2_flockfile_proc: *** input 2 ***"
#define defSignal(signal) \
static os_cond signal;\
static bool signal##_set = false;
#define initSignal(signal, mutex) \
os_condInit(&signal, &mutex);\
signal##_set = false;
#define sendSignal(signal, mutex) \
os_mutexLock(&mutex);\
/* signaling */ \
signal##_set = true; \
os_condSignal(&signal);\
os_mutexUnlock(&mutex);
#define waitForSignal(signal, mutex) \
os_mutexLock(&mutex);\
while(!signal##_set) { \
/* waiting for signal */ \
os_condWait(&signal, &mutex);\
/* received */ \
} /* else already signal received */ \
os_mutexUnlock(&mutex);
#define timedWaitSignal(signal, mutex, time) \
{ \
os_time duration = time; \
os_time startTime, currentTime; \
os_result rc; \
os_mutexLock(&mutex); \
startTime = os_timeGetElapsed(); \
while(!signal##_set) { \
/* waiting for signal */ \
rc = os_condTimedWait(&signal, &mutex, &duration); \
/* signal received or timeout */ \
if(rc == os_resultTimeout) { \
break; \
} else { \
currentTime = os_timeGetElapsed(); \
if(os_timeCompare(os_timeSub(currentTime, startTime), wait_time_out) >= 0) { \
break; \
} \
duration = os_timeSub(wait_time_out, os_timeSub(currentTime, startTime)); \
} \
} /* else already signal received */ \
os_mutexUnlock(&mutex);\
}
static os_mutex mutex;
static bool do_locking;
/* signals set by threads */
defSignal(thread1_started);
defSignal(thread2_started);
defSignal(action1_done);
defSignal(action2_done);
/* signals set by the test orchestrator (doFlockfileTest) */
defSignal(do_action1);
defSignal(do_action2);
defSignal(do_action3);
static uint32_t thread1_flockfile_proc(void* args) {
int result = 0;
/* thread1: start */
sendSignal(thread1_started, mutex);
waitForSignal(do_action1, mutex);
if(do_locking) os_flockfile(file);
/* Thread1: writing input 1 to the file */
result = fputs(FLOCKFILE_THREAD1_INPUT1, file);
CU_ASSERT(result >= 0);
sendSignal(action1_done, mutex);
waitForSignal(do_action3, mutex);
/* Thread1: writing input 3 to the file */
result = fputs(FLOCKFILE_THREAD1_INPUT3, file);
CU_ASSERT(result >= 0);
if(do_locking) os_funlockfile(file);
/* thread1: end */
return 0;
}
static uint32_t thread2_flockfile_proc(void* args) {
int result = 0;
/* thread2: start */
sendSignal(thread2_started, mutex);
waitForSignal(do_action2, mutex);
/* Thread2: writing input 2 to the file */
result = fputs(FLOCKFILE_THREAD2_INPUT2, file);
CU_ASSERT(result >= 0);
sendSignal(action2_done, mutex);
/* thread2: end */
return 0;
}
bool doFlockfileTest(bool lock) {
bool testPassed = true;
bool strcmpResult = true;
os_result result;
os_threadAttr threadAttr;
os_threadId thread1;
os_threadId thread2;
int FLOCKFILE_INPUT_MAX = sizeof(FLOCKFILE_THREAD1_INPUT1);
do_locking = lock;
char *buffer = os_malloc(sizeof(char) * FLOCKFILE_INPUT_MAX);
file = tmpfile();
os_mutexInit(&mutex);
/* initialize all signal conditions */
os_mutexLock(&mutex);
initSignal(thread1_started, mutex);
initSignal(thread2_started, mutex);
initSignal(action1_done, mutex);
initSignal(action2_done, mutex);
initSignal(do_action1, mutex);
initSignal(do_action2, mutex);
initSignal(do_action3, mutex);
os_mutexUnlock(&mutex);
/* create threads... */
os_threadAttrInit(&threadAttr);
result = os_threadCreate(
&thread1,
"thread 1",
&threadAttr,
thread1_flockfile_proc,
NULL);
CU_ASSERT(result == os_resultSuccess);
result = os_threadCreate(
&thread2,
"thread 2",
&threadAttr,
thread2_flockfile_proc,
NULL);
CU_ASSERT(result == os_resultSuccess);
/* wait for threads to start */
waitForSignal(thread1_started, mutex);
waitForSignal(thread2_started, mutex);
/* get thread one to do its first thing */
sendSignal(do_action1, mutex);
/* wait for thread 1 to acknowledge */
timedWaitSignal(action1_done, mutex, wait_time_out);
/* kick thead 2 */
sendSignal(do_action2, mutex);
/* wait for thread 2 to acknowledge */
timedWaitSignal(action2_done, mutex, wait_time_out);
/* kick thread 1, again */
sendSignal(do_action3, mutex);
/* wait for threads to shutdown */
result = os_threadWaitExit(thread1,NULL);
CU_ASSERT(result == os_resultSuccess);
result = os_threadWaitExit(thread2,NULL);
CU_ASSERT(result == os_resultSuccess);
/* if lock then Expected action order: 1 3 2
* else Expected action order: 1 2 3 */
rewind(file);
if(lock) {
if(fgets(buffer, FLOCKFILE_INPUT_MAX, file) > 0) {
strcmpResult = (strcmp(buffer, FLOCKFILE_THREAD1_INPUT1) == 0);
CU_ASSERT(strcmpResult);
testPassed = testPassed && strcmpResult; /* update flag indicating overall test state */
}
if(fgets(buffer, FLOCKFILE_INPUT_MAX, file) > 0) {
strcmpResult = (strcmp(buffer, FLOCKFILE_THREAD1_INPUT3) == 0);
CU_ASSERT(strcmpResult);
testPassed = testPassed && strcmpResult; /* update flag indicating overall test state */
}
if(fgets(buffer, FLOCKFILE_INPUT_MAX, file) > 0) {
strcmpResult = (strcmp(buffer, FLOCKFILE_THREAD2_INPUT2) == 0);
CU_ASSERT(strcmpResult);
testPassed = testPassed && strcmpResult; /* update flag indicating overall test state */
}
} else {
if(fgets(buffer, FLOCKFILE_INPUT_MAX, file) > 0) {
strcmpResult = (strcmp(buffer, FLOCKFILE_THREAD1_INPUT1) == 0);
CU_ASSERT(strcmpResult);
testPassed = testPassed && strcmpResult; /* update flag indicating overall test state */
}
if(fgets(buffer, FLOCKFILE_INPUT_MAX, file) > 0) {
strcmpResult = (strcmp(buffer, FLOCKFILE_THREAD2_INPUT2) == 0);
CU_ASSERT(strcmpResult);
testPassed = testPassed && strcmpResult; /* update flag indicating overall test state */
}
if(fgets(buffer, FLOCKFILE_INPUT_MAX, file) > 0) {
strcmpResult = (strcmp(buffer, FLOCKFILE_THREAD1_INPUT3) == 0);
CU_ASSERT(strcmpResult);
testPassed = testPassed && strcmpResult; /* update flag indicating overall test state */
}
}
/* cleanup */
os_free(buffer);
fclose(file);
os_mutexLock(&mutex);
os_condDestroy(&do_action1);
os_condDestroy(&do_action2);
os_condDestroy(&do_action3);
os_condDestroy(&thread1_started);
os_condDestroy(&thread2_started);
os_condDestroy(&action1_done);
os_condDestroy(&action2_done);
os_mutexUnlock(&mutex);
os_mutexDestroy(&mutex);
/* doFlockfileTest */
return testPassed;
}
static int
vsnprintfTest(
const char *format,
...)
{
va_list varargs;
int result = 0;
char description[10];
va_start(varargs, format);
memset(description, 0, sizeof(description));
result = os_vsnprintf(description, sizeof(description)-1, format, varargs);
va_end(varargs);
return result;
}
CUnit_Suite_Initialize(os_stdlib)
{
int result = 0;
os_osInit();
return result;
}
CUnit_Suite_Cleanup(os_stdlib)
{
/* Remove files used to test permissions */
remove ("exec_only");
remove ("read_exec");
remove ("read_only");
remove ("read_write_exec");
remove ("write_only");
remove ("existing_file");
os_osExit();
return 0;
}
CUnit_Test(os_stdlib, strcasecmp)
{
int res;
char *s1, *s2;
s1 = "a";
s2 = "a";
printf ("Starting os_stdlib_strcasecmp_001\n");
res = os_strcasecmp (s1,s2);
CU_ASSERT (res == 0);
printf ("Starting os_stdlib_strcasecmp_002\n");
s1 = "aa";
s2 = "a";
res = os_strcasecmp (s1,s2);
CU_ASSERT (res > 0);
printf ("Starting os_stdlib_strcasecmp_003\n");
s1 = "a";
s2 = "aa";
res = os_strcasecmp (s1,s2);
CU_ASSERT (res < 0);
printf ("Starting os_stdlib_strcasecmp_004\n");
s1 = "a";
s2 = "A";
res = os_strcasecmp (s1,s2);
CU_ASSERT (res == 0);
printf ("Starting os_stdlib_strcasecmp_005\n");
s1 = "A";
s2 = "a";
res = os_strcasecmp (s1,s2);
CU_ASSERT (res == 0);
printf ("Starting os_stdlib_strcasecmp_006\n");
s1 = "a";
s2 = "b";
res = os_strcasecmp (s1,s2);
CU_ASSERT (res < 0);
printf ("Starting os_stdlib_strcasecmp_007\n");
s1 = "b";
s2 = "a";
res = os_strcasecmp (s1,s2);
CU_ASSERT (res > 0);
printf ("Ending os_stdlib_strcasecmp\n");
}
CUnit_Test(os_stdlib, strncasecmp)
{
int res;
char *s1, *s2;
s1 = "a";
s2 = "a";
printf ("Starting os_stdlib_strncasecmp_001\n");
res = os_strncasecmp (s1,s2,2);
CU_ASSERT (res == 0);
s1 = "aa";
s2 = "a";
printf ("Starting os_stdlib_strncasecmp_002\n");
res = os_strncasecmp (s1,s2,2);
CU_ASSERT (res > 0);
s1 = "a";
s2 = "aa";
printf ("Starting os_stdlib_strncasecmp_003\n");
res = os_strncasecmp (s1,s2,2);
CU_ASSERT (res < 0);
s1 = "a";
s2 = "A";
printf ("Starting os_stdlib_strncasecmp_004\n");
res = os_strncasecmp (s1,s2,2);
CU_ASSERT (res == 0);
s1 = "A";
s2 = "a";
printf ("Starting os_stdlib_strncasecmp_005\n");
res = os_strncasecmp (s1,s2,2);
CU_ASSERT (res == 0);
s1 = "a";
s2 = "b";
printf ("Starting os_stdlib_strncasecmp_006\n");
res = os_strncasecmp (s1,s2,2);
CU_ASSERT (res < 0);
s1 = "b";
s2 = "a";
printf ("Starting os_stdlib_strncasecmp_007\n");
res = os_strncasecmp (s1,s2,2);
CU_ASSERT (res > 0);
s1 = "abcdefghijkl";
s2 = "AbCdEaGhIjKl";
printf ("Starting os_stdlib_strncasecmp_008\n");
res = os_strncasecmp (s1,s2,5);
CU_ASSERT (res == 0);
s1 = "abcdefghijkl";
s2 = "AbCdEaGhIjKl";
printf ("Starting os_stdlib_strncasecmp_009\n");
res = os_strncasecmp (s1,s2,6);
CU_ASSERT (res > 0);
printf ("Ending os_stdlib_strncasecmp\n");
}
CUnit_Test(os_stdlib, gethostname)
{
int res;
os_result os_res;
char os_cpu[200];
char cpu[200];
printf ("Starting os_stdlib_gethostname_001\n");
os_cpu[0] = '\0';
os_res = os_gethostname (os_cpu, sizeof(os_cpu));
CU_ASSERT (os_res == os_resultSuccess);
cpu[0] = '\0';
res = gethostname (cpu, sizeof(cpu));
CU_ASSERT (res == 0);
printf ("Starting os_stdlib_gethostname_002\n");
os_res = os_gethostname (os_cpu, strlen(os_cpu)-1);
CU_ASSERT (os_res == os_resultFail);
printf ("Ending os_stdlib_gethostname\n");
}
CUnit_Test(os_stdlib, putenv)
{
os_result os_res;
printf ("Starting os_stdlib_putenv_001\n");
os_res = os_putenv ("ABCDE=FGHIJ");
CU_ASSERT (os_res == os_resultSuccess);
CU_ASSERT (strcmp (os_getenv("ABCDE"), "FGHIJ") == 0);
printf ("Ending os_stdlib_putenv\n");
}
CUnit_Test(os_stdlib, getenv)
{
const char *env;
os_result res;
printf ("Starting os_stdlib_getenv_001\n");
res = os_putenv("ABCDE=FGHIJ");
CU_ASSERT(res == os_resultSuccess);
env = os_getenv("ABCDE");
CU_ASSERT(env != NULL);
if (env != NULL) {
CU_ASSERT(strcmp(env, "FGHIJ") == 0);
}
printf ("Starting os_stdlib_getenv_002\n");
CU_ASSERT (os_getenv("XXABCDEXX") == NULL );
printf ("Ending os_stdlib_getenv\n");
}
CUnit_Test(os_stdlib, fileSep)
{
#if defined WIN32
const char *wanted= "\\";
#else
const char *wanted= "/";
#endif
printf ("Starting os_stdlib_fileSep_001\n");
CU_ASSERT (strcmp(os_fileSep(), wanted) == 0);
printf ("Ending os_stdlib_fileSep\n");
}
CUnit_Test(os_stdlib, access)
{
os_result os_res;
os_result wanted;
int fh;
/* Check correct functioning of os_access, non existing file read access */
printf ("Starting os_stdlib_access_001\n");
#if defined VXWORKS_RTP || defined _WRS_KERNEL
printf ("N.A - Not tested for vxworks.\n");
#else
os_res = os_access("non_existing_file", OS_ROK);
CU_ASSERT (os_res == os_resultFail);
/* Check correct functioning of os_access, non existing file write access */
printf ("Starting os_stdlib_access_002\n");
os_res = os_access("non_existing_file", OS_WOK);
CU_ASSERT (os_res == os_resultFail);
/* Check correct functioning of os_access, non existing file execute access */
printf ("Starting os_stdlib_access_003\n");
os_res = os_access("non_existing_file", OS_XOK);
CU_ASSERT (os_res == os_resultFail);
/* Check correct functioning of os_access, non existing file existence */
printf ("Starting os_stdlib_access_004\n");
os_res = os_access("non_existing_file", OS_FOK);
CU_ASSERT (os_res == os_resultFail);
/* Check correct functioning of os_access, existing file with no
permissions read access */
printf ("Starting os_stdlib_access_005\n");
#ifdef WIN32
fh= _creat("existing_file", 0000); /* Note always has read & execute */
if (fh != -1)
_close(fh);
wanted = os_resultSuccess;
#else
fh= creat("existing_file", 0000);
if (fh != -1)
close(fh);
wanted = os_resultFail;
#endif /* WIN32 */
os_res = os_access("existing_file", OS_ROK);
CU_ASSERT (os_res == wanted);
/* Check correct functioning of os_access, existing file with no
permissions write access */
printf ("Starting os_stdlib_access_006\n");
os_res = os_access("existing_file", OS_WOK);
CU_ASSERT (os_res == os_resultFail);
/* Check correct functioning of os_access, existing file with no
permissions execute access */
printf ("Starting os_stdlib_access_007\n");
os_res = os_access("existing_file", OS_XOK);
CU_ASSERT (os_res == os_resultFail);
/* Check correct functioning of os_access, existing file with no permissions existence */
printf ("Starting os_stdlib_access_008\n");
os_res = os_access("existing_file", OS_FOK);
CU_ASSERT (os_res == os_resultSuccess);
/* Check correct functioning of os_access,
existing file with read permissions read access */
printf ("Starting os_stdlib_access_009\n");
#ifdef WIN32
fh= _creat("read_only", _S_IREAD); /* Note always has read & execute */
if (fh != -1)
_close(fh);
#else
fh= creat("read_only", S_IRUSR);
if (fh != -1)
close(fh);
#endif /* WIN32 */
os_res = os_access("read_only", OS_ROK);
CU_ASSERT (os_res == os_resultSuccess);
/* Check correct functioning of os_access,
existing file with read permissions write access */
printf ("Starting os_stdlib_access_010\n");
os_res = os_access("read_only", OS_WOK);
CU_ASSERT (os_res == os_resultFail);
/* Check correct functioning of os_access,
existing file with read permissions execute access */
printf ("Starting os_stdlib_access_011\n");
os_res = os_access("read_only", OS_XOK);
CU_ASSERT (os_res == os_resultFail);
/* Check correct functioning of os_access,
existing file with read permissions existence */
printf ("Starting os_stdlib_access_012\n");
os_res = os_access("read_only", OS_FOK);
CU_ASSERT (os_res == os_resultSuccess);
/* Check correct functioning of os_access,
existing file with write permissions read access */
printf ("Starting os_stdlib_access_013\n");
#ifdef WIN32
fh= _creat("write_only", _S_IWRITE); /* Note windows automatically has read access can't have write only */
if (fh != -1)
_close(fh);
wanted = os_resultSuccess;
#else
fh= creat("write_only", S_IWUSR);
if (fh != -1)
close(fh);
wanted = os_resultFail;
#endif /* WIN32 */
os_res = os_access("write_only", OS_ROK);
CU_ASSERT (os_res == wanted);
/* Check correct functioning of os_access,
existing file with write permissions write access */
printf ("Starting os_stdlib_access_014\n");
os_res = os_access("write_only", OS_WOK);
CU_ASSERT (os_res == os_resultSuccess);
/* Check correct functioning of os_access,
existing file with write permissions execute access */
printf ("Starting os_stdlib_access_015\n");
os_res = os_access("write_only", OS_XOK);
CU_ASSERT (os_res == os_resultFail);
/* Check correct functioning of os_access,
existing file with write permissions existence */
printf ("Starting os_stdlib_access_016\n");
os_res = os_access("write_only", OS_FOK);
CU_ASSERT (os_res == os_resultSuccess);
/* Check correct functioning of os_access,
existing file with exec permissions read access */
printf ("Starting os_stdlib_access_017\n");
#ifdef WIN32
fh= _creat("exec_only" OS_OS_EXESUFFIX, _S_IREAD); /* Windows always has read and can't do execute (that's based upon filename ext only) */
if (fh != -1)
_close(fh);
wanted = os_resultSuccess;
#else
fh= creat("exec_only" OS_OS_EXESUFFIX, S_IXUSR);
if (fh != -1)
close(fh);
wanted = os_resultFail;
#endif /* WIN32 */
os_res = os_access("exec_only" OS_OS_EXESUFFIX, OS_ROK);
CU_ASSERT (os_res == wanted);
/* Check correct functioning of os_access,
existing file with exec permissions write access */
printf ("Starting os_stdlib_access_018\n");
os_res = os_access("exec_only" OS_OS_EXESUFFIX, OS_WOK);
CU_ASSERT (os_res == os_resultFail);
/* Check correct functioning of os_access,
existing file with exec permissions execute access */
printf ("Starting os_stdlib_access_019\n");
os_res = os_access("exec_only" OS_OS_EXESUFFIX, OS_XOK);
CU_ASSERT (os_res == os_resultSuccess);
/* Check correct functioning of os_access,
existing file with exec permissions existence */
printf ("Starting os_stdlib_access_020\n");
os_res = os_access("exec_only" OS_OS_EXESUFFIX, OS_FOK);
CU_ASSERT (os_res == os_resultSuccess);
/* Check correct functioning of os_access,
existing file with read/write/exec permissions read access */
printf ("Starting os_stdlib_access_021\n");
#ifdef WIN32
fh= _creat("read_write_exec" OS_OS_EXESUFFIX, _S_IREAD | _S_IWRITE); /* Windows always has read and can't do execute (that's based upon filename ext only) */
if (fh != -1)
_close(fh);
#else
fh= creat("read_write_exec" OS_OS_EXESUFFIX, S_IRUSR | S_IWUSR | S_IXUSR);
if (fh != -1)
close(fh);
#endif /* WIN32 */
os_res = os_access("read_write_exec" OS_OS_EXESUFFIX, OS_ROK);
CU_ASSERT (os_res == os_resultSuccess);
/* Check correct functioning of os_access,
existing file with read/write/exec permissions write access */
printf ("Starting os_stdlib_access_022\n");
os_res = os_access("read_write_exec" OS_OS_EXESUFFIX, OS_WOK);
CU_ASSERT (os_res == os_resultSuccess);
/* Check correct functioning of os_access,
existing file with read/write/exec permissions execute access */
printf ("Starting os_stdlib_access_023\n");
os_res = os_access("read_write_exec" OS_OS_EXESUFFIX, OS_XOK);
CU_ASSERT (os_res == os_resultSuccess);
/* Check correct functioning of os_access,
existing file with read/write/exec permissions existence */
printf ("Starting os_stdlib_access_024\n");
os_res = os_access("read_write_exec" OS_OS_EXESUFFIX, OS_FOK);
CU_ASSERT (os_res == os_resultSuccess);
/* Check correct functioning of os_access,
existing file with read/exec permissions read+write access */
printf ("Starting os_stdlib_access_025\n");
#ifdef WIN32
fh= _creat("read_exec" OS_OS_EXESUFFIX, _S_IREAD); /* Windows always has read and can't do execute (that's based upon filename ext only) */
if (fh != -1)
_close(fh);
#else
fh= creat("read_exec" OS_OS_EXESUFFIX, S_IRUSR | S_IXUSR);
if (fh != -1)
close(fh);
#endif /* WIN32 */
os_res = os_access("read_exec" OS_OS_EXESUFFIX, OS_ROK|OS_WOK);
CU_ASSERT (os_res == os_resultFail);
/* Check correct functioning of os_access,
existing file with read/exec permissions write+exec access */
printf ("Starting os_stdlib_access_026\n");
os_res = os_access("read_exec" OS_OS_EXESUFFIX, OS_WOK|OS_XOK);
CU_ASSERT (os_res == os_resultFail);
/* Check correct functioning of os_access,
existing file with read/exec permissions read+exec access */
printf ("Starting os_stdlib_access_027\n");
os_res = os_access("read_exec" OS_OS_EXESUFFIX, OS_ROK|OS_XOK);
CU_ASSERT (os_res == os_resultSuccess);
/* Check correct functioning of os_access,
existing file with read/exec permissions read+exec+existence */
printf ("Starting os_stdlib_access_028\n");
os_res = os_access("read_exec" OS_OS_EXESUFFIX, OS_ROK|OS_XOK|OS_FOK);
CU_ASSERT (os_res == os_resultSuccess);
#endif /* VXWORKS */
printf ("Ending stdlib_os_access\n");
}
CUnit_Test(os_stdlib, vsnprintf)
{
printf ("Starting os_stdlib_vsnprintf_001\n");
CU_ASSERT (vsnprintfTest("%s","test") == 4);
CU_ASSERT (vsnprintfTest("%d",12) == 2);
CU_ASSERT (vsnprintfTest("hello %s","world") == 11);
printf ("Ending os_stdlib_vsnprintf\n");
}
CUnit_Test(os_stdlib, strtok_r)
{
char * res;
char *strtok_r_ts1;
char *saveptr;
printf ("Starting os_stdlib_strtok_r_001\n");
strtok_r_ts1= os_strdup("123,234");
res = os_strtok_r( strtok_r_ts1, ",", &saveptr );
CU_ASSERT (strcmp(res, "123") == 0);
printf ("Starting os_stdlib_strtok_r_002\n");
res = os_strtok_r( NULL, ",", &saveptr );
CU_ASSERT (strcmp(res, "234") == 0);
printf ("Starting os_stdlib_strtok_r_003\n");
res = os_strtok_r( NULL, ",", &saveptr );
CU_ASSERT (res == NULL);
os_free(strtok_r_ts1);
printf ("Starting os_stdlib_strtok_r_004\n");
strtok_r_ts1= os_strdup(",;,123abc,,456,:,");
res = os_strtok_r( strtok_r_ts1, ",;", &saveptr );
CU_ASSERT (strcmp(res, "123abc") == 0);
printf ("Starting os_stdlib_strtok_r_005\n");
res = os_strtok_r( NULL, ",", &saveptr );
CU_ASSERT (strcmp(res, "456") == 0);
printf ("Starting os_stdlib_strtok_r_006\n");
res = os_strtok_r( NULL, ",:", &saveptr );
CU_ASSERT (res == NULL);
free(strtok_r_ts1);
printf ("Starting os_stdlib_strtok_r_007\n");
strtok_r_ts1= os_strdup(",,,123,,456,789,,,");
res = os_strtok_r( strtok_r_ts1, ",", &saveptr );
CU_ASSERT (strcmp(res, "123") == 0);
printf ("Starting os_stdlib_strtok_r_008\n");
res = os_strtok_r( NULL, ",", &saveptr );
CU_ASSERT (strcmp(res, "456") == 0);
printf ("Starting os_stdlib_strtok_r_009\n");
res = os_strtok_r( NULL, ",", &saveptr );
CU_ASSERT (strcmp(res, "789") == 0);
printf ("Starting os_stdlib_strtok_r_010\n");
res = os_strtok_r( NULL, ",:", &saveptr );
CU_ASSERT (res == NULL);
free(strtok_r_ts1);
printf ("Ending os_stdlib_strtok_r\n");
}
CUnit_Test(os_stdlib, index)
{
char * res;
char *index_ts1;
printf ("Starting os_stdlib_index_001\n");
index_ts1 = "abc";
res = os_index( index_ts1, 'a' );
CU_ASSERT (res == index_ts1);
printf ("Starting os_stdlib_index_002\n");
res = os_index( index_ts1, 'c' );
CU_ASSERT (res == &index_ts1[2]);
printf ("Starting os_stdlib_index_003\n");
index_ts1 = "abcdefghij";
res = os_index( index_ts1, 'f' );
CU_ASSERT (res == &index_ts1[5]);
printf ("Starting os_stdlib_index_004\n");
res = os_index( index_ts1, 'k' );
CU_ASSERT (res == NULL);
printf ("Ending os_stdlib_index\n");
}
CUnit_Test(os_stdlib, flockfile)
{
bool result = false;
os_osInit();
/* Check writing in a FILE from multiple threads without using os_flockfile. */
printf ("Starting os_stdlib_flockfile_001\n");
result = doFlockfileTest(false);
CU_ASSERT (result);
/* Check writing in a FILE from multiple threads using os_flockfile in the first thread. */
printf ("Starting os_stdlib_flockfile_002\n");
result = doFlockfileTest(true);
CU_ASSERT (result);
printf ("Ending os_stdlib_flockfile\n");
os_osExit();
}
CUnit_Test(os_stdlib, getopt)
{
int c = 0;
int argc = 3;
char *argv001[] = {"", "-a", "-b"};
char *argv002[] = {"", "-c", "foo"};
char *argv003[] = {"", "-d"};
/* Check correct functioning of os_getopt */
printf ("Starting os_stdlib_getopt_001\n");
c = os_getopt(argc, argv001, "abc:");
CU_ASSERT (c == 'a');
c = os_getopt(argc, argv001, "abc:");
CU_ASSERT (c == 'b');
c = os_getopt(argc, argv001, "abc:");
CU_ASSERT (c == -1);
/* Check correct functioning of os_set_optind and os_get_optind */
printf ("Starting os_stdlib_getopt_002\n");
os_set_optind(1);
CU_ASSERT (os_get_optind() == 1);
/* Check correct functioning of os_get_optarg */
printf ("Starting os_stdlib_getopt_003\n");
c = os_getopt (argc, argv002, "c:");
CU_ASSERT (c == 'c');
CU_ASSERT (strcmp(os_get_optarg(), "foo") == 0);
c = os_getopt(argc, argv002, "c:");
CU_ASSERT (c == -1);
/* Check correct functioning of os_set_opterr, os_get_opterr and os_get_optopt */
printf ("Starting os_stdlib_getopt_004\n");
argc = 2;
os_set_optind(1);
os_set_opterr(0);
CU_ASSERT(os_get_opterr() == 0)
c = os_getopt (argc, argv003, "c:");
CU_ASSERT (c == '?');
CU_ASSERT (os_get_optopt() == 'd');
printf ("Ending os_stdlib_getopt\n");
}

321
src/os/tests/strtoll.c Normal file
View file

@ -0,0 +1,321 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Runner.h"
#include "os/os.h"
long long ll;
unsigned long long ull;
const char *str;
char *ptr;
char buf[100];
char str_llmin[100];
char str_llmax[100];
char str_ullmax[100];
char str_llrange[100];
char str_ullrange[100];
char str_xllmin[99], str_xllmax[99];
/* Really test with the maximum values supported on a platform, not some
made up number. */
long long llmin = OS_MIN_INTEGER(long long);
long long llmax = OS_MAX_INTEGER(long long);
unsigned long long ullmax = OS_MAX_INTEGER(unsigned long long);
CUnit_Suite_Initialize(os_str_convert)
{
int result = 0;
os_osInit();
printf("Run os_str_convert_Initialize\n");
(void)snprintf (str_llmin, sizeof(str_llmin), "%lld", llmin);
(void)snprintf (str_llmax, sizeof(str_llmax), "%lld", llmax);
(void)snprintf (str_llrange, sizeof(str_llrange), "%lld1", llmax);
(void)snprintf (str_ullmax, sizeof(str_ullmax), "%llu", ullmax);
(void)snprintf (str_ullrange, sizeof(str_ullrange), "%llu1", ullmax);
(void)snprintf (str_xllmin, sizeof(str_xllmin), "-%llx", llmin);
(void)snprintf (str_xllmax, sizeof(str_xllmax), "+%llx", llmax);
return result;
}
CUnit_Suite_Cleanup(os_str_convert)
{
int result = 0;
printf("Run os_str_convert_Cleanup\n");
os_osExit();
return result;
}
CUnit_Test(os_str_convert, strtoll)
{
printf ("Starting os_strtoll_001a\n");
str = "gibberish";
ll = os_strtoll(str, &ptr, 0);
CU_ASSERT (ll == 0 && ptr == str);
printf ("Starting os_strtoll_001b\n");
str = "+gibberish";
ll = os_strtoll(str, &ptr, 0);
CU_ASSERT (ll == 0 && ptr == str);
printf ("Starting os_strtoll_001c\n");
str = "-gibberish";
ll = os_strtoll(str, &ptr, 0);
CU_ASSERT (ll == 0 && ptr == str);
printf ("Starting os_strtoll_001d\n");
str = "gibberish";
ptr = NULL;
errno=0;
ll = os_strtoll(str, &ptr, 36);
CU_ASSERT (ll == 46572948005345 && errno == 0 && ptr && *ptr == '\0');
printf ("Starting os_strtoll_001e\n");
str = "1050505055";
ptr = NULL;
errno = 0;
ll = os_strtoll(str, &ptr, 37);
CU_ASSERT (ll == 0LL && errno == EINVAL && ptr == str);
printf ("Starting os_strtoll_001f\n");
str = " \t \n 1050505055";
ll = os_strtoll(str, NULL, 10);
CU_ASSERT (ll == 1050505055LL);
printf ("Starting os_strtoll_001g\n");
str = " \t \n -1050505055";
ptr = NULL;
ll = os_strtoll(str, &ptr, 10);
CU_ASSERT (ll == -1050505055LL);
printf ("Starting os_strtoll_001h\n");
str = " \t \n - \t \n 1050505055";
ptr = NULL;
ll = os_strtoll(str, &ptr, 10);
CU_ASSERT (ll == 0LL && ptr == str);
printf ("Starting os_strtoll_002a\n");
str = "10x";
ptr = NULL;
ll = os_strtoll(str, &ptr, 10);
CU_ASSERT (ll == 10LL && ptr && *ptr == 'x');
printf ("Starting os_strtoll_002b\n");
str = "+10x";
ll = os_strtoll(str, &ptr, 10);
CU_ASSERT (ll == 10LL && ptr && *ptr == 'x');
printf ("Starting os_strtoll_002c\n");
str = "-10x";
ll = os_strtoll(str, &ptr, 10);
CU_ASSERT (ll == -10LL && ptr && *ptr == 'x');
printf ("Starting os_strtoll_002d\n");
str = (const char *)str_llmax;
ll = os_strtoll(str, NULL, 10);
CU_ASSERT (ll == llmax);
printf ("Starting os_strtoll_002e\n");
str = (const char *)str_llmin;
ll = os_strtoll(str, NULL, 10);
CU_ASSERT (ll == llmin);
printf ("Starting os_strtoll_002f\n");
str = (const char *)str_llrange;
ll = os_strtoll(str, &ptr, 10);
CU_ASSERT (ll == llmax && *ptr == '1');
printf ("Starting os_strtoll_003a\n");
str = "0x100";
ll = os_strtoll(str, NULL, 16);
CU_ASSERT (ll == 0x100LL);
printf ("Starting os_strtoll_003b\n");
str = "0X100";
ll = os_strtoll(str, NULL, 16);
CU_ASSERT (ll == 0x100LL);
printf ("Starting os_strtoll_003c\n");
str = "0x1DEFCAB";
ll = os_strtoll(str, NULL, 16);
CU_ASSERT (ll == 0x1DEFCABLL);
printf ("Starting os_strtoll_003d\n");
str = "0x1defcab";
ll = os_strtoll(str, NULL, 16);
CU_ASSERT (ll == 0x1DEFCABLL);
printf ("Starting os_strtoll_003e\n");
str = (char *)str_xllmin;
ll = os_strtoll(str, NULL, 16);
CU_ASSERT (ll == llmin);
printf ("Starting os_strtoll_003f\n");
str = (char *)str_xllmax;
ll = os_strtoll(str, NULL, 16);
CU_ASSERT (ll == llmax);
printf ("Starting os_strtoll_003g\n");
str = "0x100";
ll = os_strtoll(str, NULL, 0);
CU_ASSERT (ll == 0x100LL);
printf ("Starting os_strtoll_003h\n");
str = "100";
ll = os_strtoll(str, NULL, 16);
CU_ASSERT (ll == 0x100LL);
printf ("Starting os_strtoll_003i\n");
/* calling os_strtoll with \"%s\" and base 10, expected result 0 */
str = "0x100";
ll = os_strtoll(str, &ptr, 10);
CU_ASSERT (ll == 0 && ptr && *ptr == 'x');
printf ("Starting os_strtoll_003j\n");
/* calling os_strtoll with \"%s\" and base 0, expected result 256 */
str = "0x100g";
ll = os_strtoll(str, &ptr, 0);
CU_ASSERT (ll == 256 && ptr && *ptr == 'g');
printf ("Starting os_strtoll_004a\n");
str = "0100";
ll = os_strtoll(str, NULL, 0);
CU_ASSERT(ll == 64LL);
printf ("Starting os_strtoll_004b\n");
str = "0100";
ll = os_strtoll(str, NULL, 8);
CU_ASSERT(ll == 64LL);
printf ("Starting os_strtoll_004c\n");
str = "100";
ll = os_strtoll(str, NULL, 8);
CU_ASSERT(ll == 64LL);
printf ("Starting os_strtoll_004d\n");
/* calling os_strtoll with \"%s\" and base 10, expected result 100 */
str = "0100";
ll = os_strtoll(str, &ptr, 10);
CU_ASSERT(ll == 100);
printf ("Starting os_strtoll_004e\n");
/* calling os_strtoll with \"%s\" and base 0, expected result 64 */
str = "01008";
ll = os_strtoll(str, &ptr, 8);
CU_ASSERT(ll == 64LL && ptr && *ptr == '8');
printf ("Starting os_strtoll_004f\n");
str = "00001010";
ll = os_strtoll(str, NULL, 2);
CU_ASSERT(ll == 10LL);
printf ("Ending os_strtoll\n");
}
CUnit_Test(os_str_convert, strtoull)
{
printf ("Starting os_strtoull_001a\n");
str = "0xffffffffffffffff";
ull = os_strtoull(str, NULL, 0);
CU_ASSERT(ull == ullmax);
printf ("Starting os_strtoull_001b\n");
str = "-1";
ull = os_strtoull(str, NULL, 0);
CU_ASSERT(ull == ullmax);
printf ("Starting os_strtoull_001c\n");
str = "-2";
ull = os_strtoull(str, NULL, 0);
CU_ASSERT(ull == (ullmax - 1));
printf ("Ending os_strtoull\n");
}
CUnit_Test(os_str_convert, atoll)
{
printf ("Starting os_atoll_001\n");
str = "10";
ll = os_atoll(str);
CU_ASSERT(ll == 10);
printf ("Ending os_atoll\n");
}
CUnit_Test(os_str_convert, atoull)
{
printf ("Starting os_atoull_001\n");
str = "10";
ull = os_atoull(str);
CU_ASSERT(ull == 10);
printf ("Ending tc_os_atoull\n");
}
CUnit_Test(os_str_convert, lltostr)
{
printf ("Starting os_lltostr_001\n");
ll = llmax;
ptr = os_lltostr(ll, buf, 0, NULL);
CU_ASSERT(ptr == NULL);
printf ("Starting os_lltostr_002\n");
/* calling os_lltostr with %lld with buffer size of 5, expected result \"5432\" */
ll = 54321;
ptr = os_lltostr(ll, buf, 5, NULL);
CU_ASSERT(strcmp(ptr, "5432") == 0);
printf ("Starting os_lltostr_003a\n");
ll = llmax;
ptr = os_lltostr(ll, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, str_llmax) == 0);
printf ("Starting os_lltostr_003b\n");
ll = llmin;
ptr = os_lltostr(ll, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, str_llmin) == 0);
printf ("Starting os_lltostr_004\n");
ll = 1;
ptr = os_lltostr(ll, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, "1") == 0);
printf ("Starting os_lltostr_005\n");
ll = 0;
ptr = os_lltostr(ll, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, "0") == 0);
printf ("Starting os_lltostr_006\n");
ll = -1;
ptr = os_lltostr(ll, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, "-1") == 0);
printf ("Ending os_lltostr\n");
}
CUnit_Test(os_str_convert, ulltostr)
{
printf ("Starting os_ulltostr_001\n");
ull = ullmax;
ptr = os_ulltostr(ull, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, str_ullmax) == 0);
printf ("Starting os_ulltostr_002\n");
ull = 0ULL;
ptr = os_ulltostr(ull, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, "0") == 0);
printf ("Ending os_ulltostr\n");
}

842
src/os/tests/thread.c Normal file
View file

@ -0,0 +1,842 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Runner.h"
#include "os/os.h"
#include "assert.h"
#define ENABLE_TRACING 0
char arg_result[30];
int threadCalled;
int startCallbackCount;
int stopCallbackCount;
void *returnval;
static void
sleepMsec(int32_t msec)
{
os_time delay;
assert(msec > 0);
assert(msec < 1000);
delay.tv_sec = 0;
delay.tv_nsec = msec*1000*1000;
os_nanoSleep(delay);
}
uint32_t new_thread (_In_ void *args)
{
(void)snprintf (arg_result, sizeof (arg_result), "%s", (char *)args);
sleepMsec (500);
return 0;
}
static uintmax_t thread_id_from_thread;
uint32_t threadId_thread (_In_opt_ void *args)
{
if (args != NULL) {
sleepMsec (500);
}
thread_id_from_thread = os_threadIdToInteger (os_threadIdSelf ());
return (uint32_t)thread_id_from_thread; /* Truncates potentially; just used for checking passing a result-value. */
}
uint32_t get_threadExit_thread (void *args)
{
os_threadId * threadId = args;
uint32_t id;
os_result ret = os_threadWaitExit (*threadId, &id);
return id;
}
uint32_t threadIdentity_thread (_In_ void *args)
{
char *identity = args;
os_threadFigureIdentity (identity, 512);
return 0;
}
static uint32_t threadMain(_In_opt_ void *args)
{
OS_UNUSED_ARG(args);
threadCalled = 1;
sleepMsec(500);
return 0;
}
uint32_t threadMemory_thread (_In_opt_ void *args)
{
OS_UNUSED_ARG(args);
/* Check os_threadMemMalloc with success result for child thread */
printf("Starting os_threadMemMalloc_003\n");
returnval = os_threadMemMalloc (3, 100);
CU_ASSERT (returnval != NULL);
/* Check os_threadMemMalloc with fail result for child thread for index already in use */
printf("Starting os_threadMemMalloc_004\n");
returnval = os_threadMemMalloc (3, 100);
CU_ASSERT (returnval == NULL);
/* Check os_threadMemGet for child thread and non allocated index */
printf("Starting os_threadMemGet_003\n");
returnval = os_threadMemGet (OS_THREAD_WARNING);
CU_ASSERT (returnval == NULL);
/* Check os_threadMemGet for child thread and allocated index */
printf("Starting os_threadMemGet_004\n");
returnval = os_threadMemGet (3);
CU_ASSERT (returnval != NULL);
/* Check os_threadMemFree for child thread and non allocated index */
printf("Starting os_threadMemFree_003\n");
os_threadMemFree (OS_THREAD_WARNING);
returnval = os_threadMemGet (OS_THREAD_WARNING);
CU_ASSERT (returnval == NULL);
/* Check os_threadMemFree for child thread and allocated index */
printf("Starting os_threadMemFree_004\n");
os_threadMemFree (3);
returnval = os_threadMemGet (3);
CU_ASSERT (returnval == NULL);
return 0;
}
CUnit_Suite_Initialize(os_thread)
{
int result = 0;
os_osInit();
printf("Run os_thread_Initialize\n");
return result;
}
CUnit_Suite_Cleanup(os_thread)
{
int result = 0;
printf("Run os_thread_Cleanup\n");
os_osExit();
return result;
}
CUnit_Test(os_thread, create)
{
int result;
os_threadId thread_os_threadId;
os_threadAttr thread_os_threadAttr;
#ifndef WIN32
int result_int;
#endif
/* Check os_threadCreate with Success result\n\t\t
(check thread creation and check argument passing) */
printf ("Starting os_thread_create_001\n");
os_threadAttrInit (&thread_os_threadAttr);
result = os_threadCreate (&thread_os_threadId, "ThreadCreate1", &thread_os_threadAttr, &new_thread, "os_threadCreate");
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
#ifdef _WRS_KERNEL
taskDelay(1 * sysClkRateGet());
#endif
result = os_threadWaitExit (thread_os_threadId, NULL);
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
result = strcmp (arg_result, "os_threadCreate");
CU_ASSERT (result == 0);
if (result == 0)
printf("Thread created and argument correctly passed.\n");
else
printf("Thread created but argument incorrectly passed.\n");
} else {
printf("os_threadCreate success, failed os_threadWaitExit.\n");
}
}
/* Check os_threadCreate with Failed result */
printf ("Starting os_thread_create_002\n");
printf ("N.A - Failure cannot be forced\n");
/* Check os_threadCreate with scheduling class SCHED_DEFAULT */
printf ("Starting s_thread_create_003\n");
os_threadAttrInit (&thread_os_threadAttr);
thread_os_threadAttr.schedClass = OS_SCHED_DEFAULT;
result = os_threadCreate (&thread_os_threadId, "ThreadCreate3", &thread_os_threadAttr, &new_thread, "os_threadCreate");
CU_ASSERT (result == os_resultSuccess);
#if !(defined _WRS_KERNEL || defined WIN32)
if (result == os_resultSuccess) {
int policy;
struct sched_param sched_param;
result_int = pthread_getschedparam (thread_os_threadId.v, &policy, &sched_param);
CU_ASSERT (result_int == 0);
if (result_int != 0) {
printf ("pthread_getschedparam failed");
} else {
CU_ASSERT (policy == SCHED_OTHER);
}
result = os_threadWaitExit (thread_os_threadId, NULL);
CU_ASSERT (result == os_resultSuccess);
} else {
printf ("os_threadCreate failed.\n");
}
#endif
/* SCHED_TIMESHARE not supported by vxworks kernel */
#ifndef _WRS_KERNEL
/* Check os_threadCreate with scheduling class SCHED_TIMESHARE */
printf ("Starting os_thread_create_004\n");
os_threadAttrInit (&thread_os_threadAttr);
thread_os_threadAttr.schedClass = OS_SCHED_TIMESHARE;
result = os_threadCreate (&thread_os_threadId, "ThreadCreate4", &thread_os_threadAttr, &new_thread, "os_threadCreate");
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
#ifndef WIN32
int policy;
struct sched_param sched_param;
result_int = pthread_getschedparam (thread_os_threadId.v, &policy, &sched_param);
CU_ASSERT (result_int == 0);
if (result_int != 0) {
printf ("pthread_getschedparam failed");
} else {
CU_ASSERT (policy == SCHED_OTHER);
}
#endif /* WIN32 */
result = os_threadWaitExit (thread_os_threadId, NULL);
} else {
printf ("os_threadCreate failed.\n");
}
#endif
/* Check os_threadCreate with scheduling class SCHED_REALTIME */
printf ("Starting tc_os_thread_create_005\n");
#if ! defined WIN32 && ! defined _WRS_KERNEL
#ifndef VXWORKS_RTP
if (getuid() != 0 && geteuid() != 0) {
printf ("N.A - Need root privileges to do the test\n");
}
else
#endif /* VXWORKS_RTP */
{
os_threadAttrInit (&thread_os_threadAttr);
thread_os_threadAttr.schedClass = OS_SCHED_REALTIME;
thread_os_threadAttr.schedPriority = sched_get_priority_min (SCHED_FIFO);
result = os_threadCreate (&thread_os_threadId, "ThreadCreate5", &thread_os_threadAttr, &new_thread, "os_threadCreate");
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
int policy;
struct sched_param sched_param;
result_int = pthread_getschedparam (thread_os_threadId.v, &policy, &sched_param);
CU_ASSERT (result_int == 0);
if (result_int == 0) {
CU_ASSERT (policy == SCHED_FIFO);
} else {
printf ("pthread_getschedparam failed\n");
}
result = os_threadWaitExit (thread_os_threadId, NULL);
} else {
printf ("os_threadCreate failed\n");
}
}
#else /* WIN32 */
printf ("N.A - Not tested on Windows or vxworks kernel\n");
#endif
/* Check os_threadCreate with scheduling class SCHED_TIMESHARE and min priority */
printf ("Starting os_thread_create_006\n");
#ifndef WIN32
os_threadAttrInit (&thread_os_threadAttr);
thread_os_threadAttr.schedClass = OS_SCHED_TIMESHARE;
#ifdef _WRS_KERNEL
thread_os_threadAttr.schedPriority = 250;
#else
thread_os_threadAttr.schedPriority = sched_get_priority_min (SCHED_OTHER);
#endif
result = os_threadCreate (&thread_os_threadId, "ThreadCreate6", &thread_os_threadAttr, &new_thread, "os_threadCreate");
#ifdef _WRS_KERNEL
if (result == os_resultSuccess)
printf ("os_threadCreate failed - Expected failure from VXWORKS\n");
else
printf ("OS_SCHED_TIMESHARE not supported\n");
#else
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
int policy;
struct sched_param sched_param;
result_int = pthread_getschedparam (thread_os_threadId.v, &policy, &sched_param);
CU_ASSERT (result_int == 0);
if (result_int == 0) {
CU_ASSERT (sched_param.sched_priority == sched_get_priority_min (SCHED_OTHER));
} else {
printf ("pthread_getschedparam failed\n");
}
result = os_threadWaitExit (thread_os_threadId, NULL);
} else {
printf ("os_threadCreate failed.\n");
}
#endif /* _WRS_KERNEL */
#else
printf ("N.A - Not tested on Windows.\n");
#endif /* WIN32 */
/* Check os_threadCreate with scheduling class SCHED_TIMESHARE and max priority */
printf ("Starting os_thread_create_007\n");
#ifndef WIN32
os_threadAttrInit (&thread_os_threadAttr);
thread_os_threadAttr.schedClass = OS_SCHED_TIMESHARE;
#ifdef _WRS_KERNEL
thread_os_threadAttr.schedPriority = 60;
#else
thread_os_threadAttr.schedPriority = sched_get_priority_max (SCHED_OTHER);
#endif
result = os_threadCreate (&thread_os_threadId, "ThreadCreate7", &thread_os_threadAttr, &new_thread, "os_threadCreate");
#ifdef _WRS_KERNEL
if (result == os_resultSuccess) {
printf ("os_threadCreate failed - Expected failure from VXWORKS\n");
} else {
printf ("OS_SCHED_TIMESHARE not supported\n");
}
#else
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
int policy;
struct sched_param sched_param;
result_int = pthread_getschedparam (thread_os_threadId.v, &policy, &sched_param);
CU_ASSERT (result_int == 0);
if (result_int == 0) {
CU_ASSERT (sched_param.sched_priority == sched_get_priority_max (SCHED_OTHER));
} else {
printf ("pthread_getschedparam failed\n");
}
result = os_threadWaitExit (thread_os_threadId, NULL);
} else {
printf ("os_threadCreate failed.\n");
}
#endif /* _WRS_KERNEL */
#else
printf ("N.A - Not tested on Windows.\n");
#endif /* WIN32 */
/* Check os_threadCreate with scheduling class SCHED_REALTIME and min priority */
printf ("Starting os_thread_create_008\n");
#ifndef WIN32
#ifndef VXWORKS_RTP
if (getuid() != 0 && geteuid() != 0)
{
printf ("N.A - Need root privileges to do the test\n");
}
else
#endif /* VXWORKS_RTP */
{
os_threadAttrInit (&thread_os_threadAttr);
thread_os_threadAttr.schedClass = OS_SCHED_REALTIME;
#ifdef _WRS_KERNEL
thread_os_threadAttr.schedPriority = 250;
#else
thread_os_threadAttr.schedPriority = sched_get_priority_min (SCHED_FIFO);
#endif
result = os_threadCreate (&thread_os_threadId, "ThreadCreate8", &thread_os_threadAttr, &new_thread, "os_threadCreate");
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
#ifdef _WRS_KERNEL
TASK_ID id;
int pri;
STATUS status;
sleepSeconds (2);
pri = 0;
id = taskNameToId("ThreadCreate8");
status = taskPriorityGet(id,&pri);
CU_ASSERT (status == OK);
CU_ASSERT (pri == 250);
#else
int policy;
struct sched_param sched_param;
result_int = pthread_getschedparam (thread_os_threadId.v, &policy, &sched_param);
CU_ASSERT (result_int == 0);
if (result_int == 0) {
CU_ASSERT (sched_param.sched_priority == sched_get_priority_min (SCHED_FIFO));
} else {
printf ("pthread_getschedparam failed.\n");
}
#endif /* _WRS_KERNEL */
result = os_threadWaitExit (thread_os_threadId, NULL);
} else {
printf ("os_threadCreate failed.\n");
}
}
#else /* WIN32 */
printf ("N.A - Not tested on Windows\n");
#endif
/* Check os_threadCreate with scheduling class SCHED_REALTIME and max priority */
printf ("Starting os_thread_create_009\n");
#ifndef WIN32
#ifndef VXWORKS_RTP
if (getuid() != 0 && geteuid() != 0)
{
printf ("N.A - Need root privileges to do the test\n");
}
else
#endif /* VXWORKS_RTP */
{
os_threadAttrInit (&thread_os_threadAttr);
thread_os_threadAttr.schedClass = OS_SCHED_REALTIME;
#ifdef _WRS_KERNEL
thread_os_threadAttr.schedPriority = 250;
#else
thread_os_threadAttr.schedPriority = sched_get_priority_max (SCHED_FIFO);
#endif
result = os_threadCreate (&thread_os_threadId, "ThreadCreate9", &thread_os_threadAttr, &new_thread, "os_threadCreate");
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
#ifdef _WRS_KERNEL
int status;
sleepSeconds (2);
status = 0;
taskPriorityGet(taskNameToId("ThreadCreate9"),&status);
CU_ASSERT (status == 250);
#else
int policy;
struct sched_param sched_param;
result_int = pthread_getschedparam (thread_os_threadId.v, &policy, &sched_param);
CU_ASSERT (result_int == 0);
if (result_int == 0) {
CU_ASSERT (sched_param.sched_priority == sched_get_priority_max (SCHED_FIFO));
} else {
printf ("pthread_getschedparam failed.\n");
}
#endif
result = os_threadWaitExit (thread_os_threadId, NULL);
} else {
printf ("os_threadCreate failed.\n");
}
}
#else /* WIN32 */
printf ("N.A - Not tested on Windows\n");
#endif
/* Check os_threadCreate by checking scheduling scope PTHREAD_SCOPE_SYSTEM */
printf ("Starting os_thread_create_010\n");
printf ("N.A - No way to queuery scope from running thread");
/* Check os_threadCreate and stacksize sttribute */
printf ("Starting os_thread_create_011\n");
printf ("N.A - No way to queuery scope from running thread");
printf ("Ending os_thread_create\n");
}
CUnit_Test(os_thread, idself)
{
os_threadId thread_os_threadId;
os_threadAttr thread_os_threadAttr;
int result;
uint32_t result_from_thread;
/* Check if own thread ID is correctly provided */
printf ("Starting tc_os_threadIdSelf_001\n");
os_threadAttrInit (&thread_os_threadAttr);
result = os_threadCreate (&thread_os_threadId, "OwnThreadId", &thread_os_threadAttr, &threadId_thread, NULL);
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
#ifdef _WRS_KERNEL
sleepSeconds(1);
#endif
result = os_threadWaitExit (thread_os_threadId, &result_from_thread);
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
uintmax_t tmp_thread_os_threadId = os_threadIdToInteger(thread_os_threadId);
CU_ASSERT (thread_id_from_thread == tmp_thread_os_threadId);
CU_ASSERT (result_from_thread == (uint32_t)tmp_thread_os_threadId);
} else {
printf ("os_threadWaitExit failed.\n");
}
} else {
printf ("os_threadCreate failed.\n");
}
printf ("Ending tc_threadIdSelf\n");
}
CUnit_Test(os_thread, join)
{
os_threadId thread_os_threadId;
os_threadAttr thread_os_threadAttr;
int result;
uint32_t result_from_thread;
/* Wait for thread to terminate and get the return value with Success result,
while thread is still running */
printf("Starting os_thread_join_001\n");
os_threadAttrInit (&thread_os_threadAttr);
result = os_threadCreate (&thread_os_threadId, "threadWaitExit", &thread_os_threadAttr, &threadId_thread, (void *)1);
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
#ifdef _WRS_KERNEL
sleepSeconds(1);
#endif
result = os_threadWaitExit (thread_os_threadId, &result_from_thread);
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
CU_ASSERT (thread_id_from_thread == os_threadIdToInteger(thread_os_threadId));
CU_ASSERT (result_from_thread == (uint32_t)thread_id_from_thread);
} else {
printf ("os_threadWaitExit failed.\n");
}
} else {
printf ("os_threadCreate failed.\n");
}
/* Wait for thread to terminate and get the return value with Success result,
while thread is already terminated */
printf ("Starting os_thread_join_002\n");
os_threadAttrInit (&thread_os_threadAttr);
result = os_threadCreate (&thread_os_threadId, "threadWaitExit", &thread_os_threadAttr, &threadId_thread, NULL);
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
#ifdef _WRS_KERNEL
sleepSeconds(1);
#endif
result = os_threadWaitExit (thread_os_threadId, &result_from_thread);
CU_ASSERT(result == os_resultSuccess);
if (result == os_resultSuccess) {
CU_ASSERT (thread_id_from_thread == os_threadIdToInteger(thread_os_threadId));
CU_ASSERT (result_from_thread == (uint32_t)thread_id_from_thread);
} else {
printf ("os_threadWaitExit failed.\n");
}
} else {
printf ("os_threadCreate failed.\n");
}
/* Get thread return value with Fail result because result is already read */
printf ("Starting tc_os_thread_join_003\n");
os_threadAttrInit (&thread_os_threadAttr);
result = os_threadCreate (&thread_os_threadId, "threadWaitExit", &thread_os_threadAttr, &threadId_thread, NULL);
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
#ifdef _WRS_KERNEL
sleepSeconds(1);
#endif
result = os_threadWaitExit (thread_os_threadId, NULL);
CU_ASSERT (result == os_resultSuccess);
} else {
printf ("os_threadCreate failed.\n");
}
/* Wait for thread to terminate and get the return value by multiple threads,
one thread gets Success other Fail */
printf ("Starting tc_os_thread_join_004\n");
#ifndef WIN32
os_threadAttrInit (&thread_os_threadAttr);
{
os_threadId threadWait1;
os_result result1;
result = os_threadCreate (&thread_os_threadId, "threadToWaitFor", &thread_os_threadAttr, &threadId_thread, (void*) 1);
CU_ASSERT (result == os_resultSuccess);
result1 = os_threadCreate (&threadWait1, "waitingThread1", &thread_os_threadAttr, &get_threadExit_thread, &thread_os_threadId);
CU_ASSERT (result1 == os_resultSuccess);
if (result == os_resultSuccess && result1 == os_resultSuccess)
{
#ifdef _WRS_KERNEL
sleepSeconds(1);
#endif
result1 = os_threadWaitExit (threadWait1, NULL);
if (result1 != os_resultSuccess) {
printf ("os_threadWaitExit 1 failed\n");
CU_ASSERT (result1 == os_resultSuccess);
}
} else {
printf ("os_threadCreate failed.\n");
}
}
#else /* WIN32 */
printf ("N.A - Not tested on Windows.\n");
#endif
/* Wait for thread to terminate and pass NULL for the
return value address - not interrested */
printf ("Starting tc_os_threadWaitExit_005\n");
os_threadAttrInit (&thread_os_threadAttr);
result = os_threadCreate (&thread_os_threadId, "threadWaitExit", &thread_os_threadAttr, &threadId_thread, NULL);
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
#ifdef _WRS_KERNEL
sleepSeconds(1);
#endif
result = os_threadWaitExit (thread_os_threadId, NULL);
CU_ASSERT (result == os_resultSuccess);
if (result != os_resultSuccess)
printf ("os_threadWaitExit failed.\n");
} else {
printf ("os_threadCreate failed.\n");
}
printf ("Ending tc_threadWaitExit\n");
}
CUnit_Test(os_thread, figure_identity)
{
#if !defined(_WIN32)
os_threadId thread_os_threadId;
os_threadAttr thread_os_threadAttr;
char threadId[512];
char thread_name[512];
int result;
#endif /* WIN32 */
/* Figure out the identity of the thread, where it's name is known */
printf ("Starting os_thread_figure_identity_001\n");
#ifdef WIN32
/* Untested because the identifier does not contain the name on Windows */
#else
os_threadAttrInit (&thread_os_threadAttr);
result = os_threadCreate (&thread_os_threadId, "threadFigureIdentity", &thread_os_threadAttr, &threadIdentity_thread, threadId);
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
#ifdef _WRS_KERNEL
sleepSeconds(1);
#endif
result = os_threadWaitExit (thread_os_threadId, NULL);
CU_ASSERT (result == os_resultSuccess);
if (result == os_resultSuccess) {
uintmax_t threadNumeric = 0;
#ifdef _WRS_KERNEL
int dum;
(void)sscanf (threadId, "%s (%d %d)", thread_name, &threadNumeric, &dum);
#else
(void)sscanf (threadId, "%s 0x%"SCNxMAX, thread_name, &threadNumeric);
#endif
CU_ASSERT (strcmp (thread_name, "threadFigureIdentity") == 0 && threadNumeric == os_threadIdToInteger(thread_os_threadId));
} else {
printf ("os_threadWaitExit failed.\n");
}
} else {
printf ("os_threadCreate failed.\n");
}
#endif /* WIN32 */
/* Figure out the identity of the thread, where it's name is unknown */
printf ("Starting os_thread_figure_identity_002\n");
#if (defined _WRS_KERNEL || defined WIN32)
{
char threadId[512];
int threadNumeric;
os_threadFigureIdentity (threadId, sizeof(threadId));
#if defined WIN32
(void)sscanf (threadId, "%"PRIx32, &threadNumeric);
#else /* VXWORKS */
(void)sscanf (index(threadId,'(') + 1, "%"PRIx32, &threadNumeric);
#endif
CU_ASSERT (threadNumeric == os_threadIdToInteger(os_threadIdSelf()));
}
#else
{
char threadId[512];
uintptr_t threadNumeric;
os_threadFigureIdentity (threadId, sizeof(threadId));
#ifdef WIN32
(void)sscanf (threadId, "%"PRIxPTR, &threadNumeric);
#else
(void)sscanf (threadId, "%"PRIxPTR, &threadNumeric);
#endif
#ifndef INTEGRITY
CU_ASSERT (threadNumeric == (uintptr_t)os_threadIdToInteger(os_threadIdSelf()));
#endif
}
#endif
/* Figure out the identity of the thread, check the return parameter */
printf ("Starting os_thread_figure_identity_003\n");
#ifdef _WRS_KERNEL
{
char threadId[512];
char threadIdString[512];
int threadNumeric;
int threadIdLen;
snprintf (threadIdString, sizeof(threadIdString), "%s (%d %d)", taskName(taskIdSelf()),os_threadIdSelf(),taskIdSelf());
threadIdLen = os_threadFigureIdentity (threadId, sizeof(threadId));
CU_ASSERT (threadIdLen == strlen(threadIdString));
}
#else
{
char threadId[512];
char threadIdString[512];
unsigned int threadIdLen;
(void)snprintf (threadIdString, sizeof(threadIdString), "0x%"PRIxMAX, os_threadIdToInteger(os_threadIdSelf()));
threadIdLen = os_threadFigureIdentity (threadId, sizeof(threadId));
CU_ASSERT (threadIdLen == strlen(threadIdString));
}
#endif
printf ("Ending os_thread_figure_identity\n");
}
CUnit_Test(os_thread, attr_init)
{
os_threadAttr thread_os_threadAttr;
/* Check default attributes: schedClass */
printf ("Starting os_thread_attr_init_001\n");
os_threadAttrInit (&thread_os_threadAttr);
CU_ASSERT (thread_os_threadAttr.schedClass == OS_SCHED_DEFAULT);
/* Check default attributes: schedPriority */
printf ("Starting os_thread_attr_init_002\n");
#if !(defined _WRS_KERNEL || defined WIN32 || defined __APPLE__)
os_threadAttrInit (&thread_os_threadAttr);
CU_ASSERT (thread_os_threadAttr.schedPriority == ((sched_get_priority_min (SCHED_OTHER) + sched_get_priority_max (SCHED_OTHER)) / 2 ));
#else
/* OSX priorities are different (min=15 and max=47) */
printf ("N.A - Not tested for VxWorks, Windows and OSX\n");
#endif
/* Check default attributes: stacksize */
printf ("Starting os_thread_attr_init_003\n");
os_threadAttrInit (&thread_os_threadAttr);
CU_ASSERT (thread_os_threadAttr.stackSize == 0);
printf ("Ending os_thread_attr_init\n");
}
CUnit_Test(os_thread, memmalloc)
{
/* Check os_threadMemMalloc with success result for main thread */
printf ("Starting os_thread_memmalloc_001\n");
returnval = os_threadMemMalloc (3, 100);
CU_ASSERT (returnval != NULL);
/* Check os_threadMemMalloc with fail result for main thread
for index already in use */
printf ("Starting os_thread_memmalloc_002\n");
returnval = os_threadMemMalloc (3, 100);
CU_ASSERT (returnval == NULL);
/* Check os_threadMemMalloc with fail result for main thread
for index < 0 */
printf ("Starting os_thread_memmalloc_003\n");
returnval = os_threadMemMalloc (-1, 100);
CU_ASSERT (returnval == NULL);
/* Check os_threadMemMalloc with fail result for main thread
for index >= OS_THREAD_MEM_ARRAY_SIZE */
printf ("Starting os_thread_memmalloc_004\n");
returnval = os_threadMemMalloc (OS_THREAD_MEM_ARRAY_SIZE, 100);
CU_ASSERT (returnval == NULL);
printf ("Ending tc_thread_memmalloc\n");
}
CUnit_Test(os_thread, memget)
{
/* Check os_threadMemGet for main thread and non allocated index */
printf ("Starting os_thread_memget_001\n");
returnval = os_threadMemGet (OS_THREAD_WARNING);
CU_ASSERT (returnval == NULL);
/* Check os_threadMemGet for main thread and allocated index */
printf ("Starting os_thread_memget_002\n");
/* FIXME: This test is no good. Apart from the fact that a valid thread
memory index should be used (os_threadMemoryIndex), this also
does not work if the test is executed in a self-contained
manner using the CUnit runner. For now just work around it by
first doing a os_threadMemMalloc. */
(void)os_threadMemMalloc(3, 100);
returnval = os_threadMemGet (3);
CU_ASSERT (returnval != NULL);
printf ("Ending tc_thread_memget\n");
}
CUnit_Test(os_thread, memfree)
{
/* Check os_threadMemFree for main thread and non allocated index */
printf ("Starting os_thread_memfree_001\n");
os_threadMemFree (OS_THREAD_WARNING);
returnval = os_threadMemGet (OS_THREAD_WARNING);
CU_ASSERT (returnval == NULL);
/* Check os_threadMemFree for main thread and allocated index */
printf ("Starting os_thread_memfree_002\n");
/* FIXME: See comments on memget test. */
(void)os_threadMemMalloc(3, 100);
returnval = os_threadMemGet(3);
CU_ASSERT(returnval != NULL);
os_threadMemFree (3);
returnval = os_threadMemGet (3);
CU_ASSERT (returnval == NULL);
printf ("Ending os_thread_memfree\n");
}
CUnit_Test(os_thread, module)
{
os_threadId tid;
os_threadAttr tattr;
os_result res;
os_threadAttrInit (&tattr);
/* Run the following tests for child thread */
res = os_threadCreate (&tid, "ThreadMemory", &tattr, &threadMemory_thread, NULL);
CU_ASSERT_EQUAL(res, os_resultSuccess);
if (res == os_resultSuccess) {
#ifdef _WRS_KERNEL
sleepSeconds(1);
#endif
res = os_threadWaitExit (tid, NULL);
CU_ASSERT_EQUAL(res, os_resultSuccess);
}
}

View file

@ -0,0 +1,283 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <stdint.h>
#include "os/os.h"
#include "CUnit/Runner.h"
CUnit_Suite_Initialize(os_thread_cleanup)
{
os_osInit();
return 0;
}
CUnit_Suite_Cleanup(os_thread_cleanup)
{
os_osExit();
return 0;
}
#define THREAD_RESET_1 (1<<0)
#define THREAD_RESET_2 (1<<1)
#define THREAD_RUN_OFFSET (4)
#define THREAD_RUN_1 (1<<(THREAD_RUN_OFFSET))
#define THREAD_RUN_2 (1<<(THREAD_RUN_OFFSET + 1))
struct thread_argument {
int flags;
int pop;
int one;
int two;
int executed;
int cancelled;
int block;
os_mutex *mutex;
os_threadId thread;
};
static struct thread_argument *
make_thread_argument(
int flags, int pop, int one, int two)
{
struct thread_argument *targ = os_malloc(sizeof(*targ));
memset(targ, 0, sizeof(*targ));
targ->flags = flags;
targ->pop = pop;
targ->one = one;
targ->two = two;
return targ;
}
static void
reset_one(
void *arg)
{
struct thread_argument *targ = (struct thread_argument *)arg;
targ->one = 0;
targ->executed++;
}
static void
reset_two(
void *arg)
{
struct thread_argument *targ = (struct thread_argument *)arg;
targ->two = 0;
targ->executed++;
}
static uint32_t
thread_main(
void *arg)
{
int pushed = 0;
int popped = 0;
int execute = 0;
struct thread_argument *targ = (struct thread_argument *)arg;
if (targ->flags & THREAD_RESET_1) {
os_threadCleanupPush(&reset_one, arg);
pushed++;
}
if (targ->flags & THREAD_RESET_2) {
os_threadCleanupPush(&reset_two, arg);
pushed++;
}
assert(targ->pop <= pushed);
if (targ->block) {
os_mutexLock(targ->mutex);
}
while (popped < targ->pop) {
execute = 1 << (THREAD_RUN_OFFSET + (targ->pop - (popped + 1)));
os_threadCleanupPop(targ->flags & execute);
targ->cancelled++;
popped++;
}
if (targ->block) {
os_mutexUnlock(targ->mutex);
}
return 0;
}
static void
setup(
struct thread_argument *targ)
{
os_result res;
os_threadId tid;
os_threadAttr tattr;
uint32_t tres = 0;
os_threadAttrInit(&tattr);
res = os_threadCreate(&tid, "", &tattr, &thread_main, (void *)targ);
CU_ASSERT_EQUAL_FATAL(res, os_resultSuccess);
targ->thread = tid;
if (!targ->block) {
res = os_threadWaitExit(tid, &tres);
CU_ASSERT_EQUAL_FATAL(res, os_resultSuccess);
}
}
/* verify the cleanup routine is called */
CUnit_Test(os_thread_cleanup, push_one)
{
int flags = THREAD_RESET_1;
struct thread_argument *targ = make_thread_argument(flags, 0, 1, 2);
setup(targ);
CU_ASSERT_EQUAL(targ->one, 0);
CU_ASSERT_EQUAL(targ->two, 2);
CU_ASSERT_EQUAL(targ->executed, 1);
CU_ASSERT_EQUAL(targ->cancelled, 0);
free(targ);
}
/* verify all cleanup routines are called if multiple are registered */
CUnit_Test(os_thread_cleanup, push_two)
{
int flags = THREAD_RESET_1 | THREAD_RESET_2;
struct thread_argument *targ = make_thread_argument(flags, 0, 1, 2);
setup(targ);
CU_ASSERT_EQUAL(targ->one, 0);
CU_ASSERT_EQUAL(targ->two, 0);
CU_ASSERT_EQUAL(targ->executed, 2);
CU_ASSERT_EQUAL(targ->cancelled, 0);
free(targ);
}
/* verify the first cleanup routine is still called if second got popped */
CUnit_Test(os_thread_cleanup, push_two_pop_one_no_exec)
{
int flags = THREAD_RESET_1 | THREAD_RESET_2;
struct thread_argument *targ = make_thread_argument(flags, 1, 1, 2);
setup(targ);
CU_ASSERT_EQUAL(targ->one, 0);
CU_ASSERT_EQUAL(targ->two, 2);
CU_ASSERT_EQUAL(targ->executed, 1);
CU_ASSERT_EQUAL(targ->cancelled, 1);
free(targ);
}
CUnit_Test(os_thread_cleanup, push_two_pop_one_exec)
{
int flags = THREAD_RESET_1 | THREAD_RESET_2 | THREAD_RUN_1;
struct thread_argument *targ = make_thread_argument(flags, 1, 1, 2);
setup(targ);
CU_ASSERT_EQUAL(targ->one, 0);
CU_ASSERT_EQUAL(targ->two, 0);
CU_ASSERT_EQUAL(targ->executed, 2);
CU_ASSERT_EQUAL(targ->cancelled, 1);
free(targ);
}
/* verify no cleanup routines are called if all got popped */
CUnit_Test(os_thread_cleanup, push_two_pop_two_no_exec)
{
int flags = THREAD_RESET_1 | THREAD_RESET_2;
struct thread_argument *targ = make_thread_argument(flags, 2, 1, 2);
setup(targ);
CU_ASSERT_EQUAL(targ->one, 1);
CU_ASSERT_EQUAL(targ->two, 2);
CU_ASSERT_EQUAL(targ->executed, 0);
CU_ASSERT_EQUAL(targ->cancelled, 2);
free(targ);
}
CUnit_Test(os_thread_cleanup, push_two_pop_two_exec_one)
{
int flags = THREAD_RESET_1 | THREAD_RESET_2 | THREAD_RUN_1;
struct thread_argument *targ = make_thread_argument(flags, 2, 1, 2);
setup(targ);
CU_ASSERT_EQUAL(targ->one, 0);
CU_ASSERT_EQUAL(targ->two, 2);
CU_ASSERT_EQUAL(targ->executed, 1);
CU_ASSERT_EQUAL(targ->cancelled, 2);
free(targ);
}
CUnit_Test(os_thread_cleanup, push_two_pop_two_exec_both)
{
int flags = THREAD_RESET_1 | THREAD_RESET_2 | THREAD_RUN_1 | THREAD_RUN_2;
struct thread_argument *targ = make_thread_argument(flags, 2, 1, 2);
setup(targ);
CU_ASSERT_EQUAL(targ->one, 0);
CU_ASSERT_EQUAL(targ->two, 0);
CU_ASSERT_EQUAL(targ->executed, 2);
CU_ASSERT_EQUAL(targ->cancelled, 2);
free(targ);
}
CUnit_Test(os_thread_cleanup, no_interference)
{
int flags = THREAD_RESET_1 | THREAD_RESET_2;
struct thread_argument *targ1 = make_thread_argument(flags, 0, 1, 2);
struct thread_argument *targ2 = make_thread_argument(flags, 2, 1, 2);
os_mutex mutex1, mutex2;
os_mutexInit(&mutex1);
os_mutexInit(&mutex2);
os_mutexLock(&mutex1);
os_mutexLock(&mutex2);
targ1->mutex = &mutex1;
targ1->block = 1;
targ2->mutex = &mutex2;
targ2->block = 1;
setup(targ1);
setup(targ2);
/* ensure thread 2 pops it's cleanup routines while thread 1 blocks */
os_mutexUnlock(&mutex2);
os_threadWaitExit(targ2->thread, NULL);
CU_ASSERT_EQUAL(targ2->one, 1);
CU_ASSERT_EQUAL(targ2->two, 2);
CU_ASSERT_EQUAL(targ2->executed, 0);
CU_ASSERT_EQUAL(targ2->cancelled, 2);
/* instruct thread 1 to continue */
os_mutexUnlock(&mutex1);
os_threadWaitExit(targ1->thread, NULL);
CU_ASSERT_EQUAL(targ1->one, 0);
CU_ASSERT_EQUAL(targ1->two, 0);
CU_ASSERT_EQUAL(targ1->executed, 2);
CU_ASSERT_EQUAL(targ1->cancelled, 0);
os_mutexDestroy(&mutex1);
os_mutexDestroy(&mutex2);
free(targ1);
free(targ2);
}