Rearrange and fixup abstraction layer

- Replace os_result by dds_retcode_t and move DDS return code defines down.
  Eliminates the need to convert between different return code types.

- Move dds_time_t down and remove os_time.
  Eliminates the need to convert between different time representations and
  reduces code duplication.

- Remove use of Microsoft source-code annotation language (SAL).
  SAL annotations are Microsoft specific and not very well documented. This
  makes it very difficult for contributers to write.

- Rearrange the abstraction layer to be feature-based. The previous layout
  falsely assumed that the operating system dictates which implementation is
  best suited. For general purpose operating systems this is mostly true, but
  embedded targets require a slightly different approach and may not even offer
  all features. The new layout makes it possible to mix-and-match feature
  implementations and allows for features to not be implemented at all.

- Replace the os prefix by ddsrt to avoid name collisions.

- Remove various portions of unused and unwanted code.

- Export thread names on all supported platforms.

- Return native thread identifier on POSIX compatible platforms.

- Add timed wait for condition variables that takes an absolute time.

- Remove system abstraction for errno. The os_getErrno and os_setErrno were
  incorrect. Functions that might fail now simply return a DDS return code
  instead.

- Remove thread-specific memory abstraction. os_threadMemGet and accompanying
  functions were a mess and their use has been eliminated by other changes in
  this commit.

- Replace attribute (re)defines by ddsrt_ prefixed equivalents to avoid name
  collisions and problems with faulty __nonnull__ attributes.

Signed-off-by: Jeroen Koekkoek <jeroen@koekkoek.nl>
This commit is contained in:
Jeroen Koekkoek 2019-01-18 14:10:19 +01:00
parent 318968f40f
commit cd6742ee12
439 changed files with 22117 additions and 28782 deletions

210
src/ddsrt/CMakeLists.txt Normal file
View file

@ -0,0 +1,210 @@
#
# 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(CheckCSourceCompiles)
include(CheckLibraryExists)
function(check_runtime_feature SOURCE_FILE)
set(expr "cmake_([_a-zA-Z0-9]+)=([_a-zA-Z0-9]+)")
try_compile(
foo "${CMAKE_BINARY_DIR}"
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE}"
OUTPUT_VARIABLE output)
string(REGEX MATCHALL "${expr}" matches "${output}")
foreach(match ${matches})
string(REGEX REPLACE "${expr}" "\\1" option "${match}")
string(REGEX REPLACE "${expr}" "\\2" value "${match}")
set(${option} ${value} PARENT_SCOPE)
endforeach()
endfunction()
if(APPLE)
set(system_name darwin)
else()
string(TOLOWER ${CMAKE_SYSTEM_NAME} system_name)
endif()
# A better choice is to use a so-called object library for ddsrt, but it was
# not possible to use target_link_libraries with object libraries until CMake
# 3.12. At the time of this writing most long-term stable distributions still
# ship an older version, so an interface library with public sources is used
# as a workaround for now.
add_library(ddsrt INTERFACE)
target_include_directories(
ddsrt INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>")
# Generate version header.
configure_file("include/dds/version.h.in" "include/dds/version.h")
target_sources(
ddsrt INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/include/dds/version.h")
if(WIN32)
configure_file("include/getopt.h.in" "include/getopt.h" COPYONLY)
list(APPEND headers "${CMAKE_CURRENT_BINARY_DIR}/include/getopt.h")
list(APPEND sources "${CMAKE_CURRENT_SOURCE_DIR}/src/getopt.c")
endif()
set(include_path "${CMAKE_CURRENT_SOURCE_DIR}/include")
set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/src")
list(APPEND headers
"${include_path}/dds/ddsrt/log.h"
"${include_path}/dds/ddsrt/retcode.h"
"${include_path}/dds/ddsrt/attributes.h"
"${include_path}/dds/ddsrt/endian.h"
"${include_path}/dds/ddsrt/arch.h"
"${include_path}/dds/ddsrt/misc.h"
"${include_path}/dds/ddsrt/io.h"
"${include_path}/dds/ddsrt/process.h"
"${include_path}/dds/ddsrt/strtod.h"
"${include_path}/dds/ddsrt/strtol.h"
"${include_path}/dds/ddsrt/types.h")
list(APPEND sources
"${source_path}/io.c"
"${source_path}/log.c"
"${source_path}/retcode.c"
"${source_path}/process.c"
"${source_path}/strtod.c"
"${source_path}/strtol.c")
# Not every target offers the same set of features. For embedded targets the
# set of features may even be different between builds. e.g. a FreeRTOS build
# could use the lightweight IP stack, but later change to FreeRTOS+TCP.
#
# Most features and target specific settings can be determined at compile time
# by a combination of pre-defined macros. However, some features require input
# from the build system. e.g. that the target operating system is FreeRTOS or
# that the network stack to be used is lwIP as opposed to the target native
# network stack. In order to mix-and-match various compilers, architectures,
# operating systems, etc input from the build system is required.
foreach(feature atomics cdtors environ heap ifaddrs random rusage
sockets string sync threads time)
if(EXISTS "${include_path}/dds/ddsrt/${feature}.h")
list(APPEND headers "${include_path}/dds/ddsrt/${feature}.h")
file(GLOB
files
CONFIGURE_DEPENDS
"${include_path}/dds/ddsrt/${feature}/**.h")
list(APPEND headers ${files})
# Do not add any sources if a feature is not offered by the target. The
# headers will define any macros needed by the source code by combining
# build system exports and pre-defined macros. To determine if a certain
# feature is offered by the target and whether or not to compile any
# source files, that information must be made available to CMake.
#
# Tests that export the required information can be written in
# cmake/${feature}.c. A test consists of a source file that includes the
# required header files and results in a specifically crafted compiler
# error that is picked up by CMake. By default, if a file named after the
# feature does not exist in cmake, the feature is expected to be
# implemented for all targets.
string(TOUPPER "${feature}" feature_uc)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${feature}.c")
check_runtime_feature(cmake/${feature}.c)
else()
set(HAVE_${feature_uc} TRUE)
endif()
if(HAVE_${feature_uc})
# Code that is more-or-less the same for all targets can placed in
# src/<feature>.c. An example would be ddsrt_freeifaddrs.
if(EXISTS "${source_path}/${feature}.c")
list(APPEND sources "${source_path}/${feature}.c")
endif()
set(system_exists FALSE)
foreach(system ${system_name} posix)
# Headers that must remain private but are required by other runtime
# source files must be located in src/<feature>/dds/ddsrt.
if(IS_DIRECTORY "${source_path}/${feature}/include")
file(GLOB
files
CONFIGURE_DEPENDS
"${source_path}/${feature}/include/**.h")
list(APPEND sources ${files})
target_include_directories(
ddsrt INTERFACE
"$<BUILD_INTERFACE:${source_path}/${feature}/include/>")
endif()
if(IS_DIRECTORY "${source_path}/${feature}/${system}")
file(GLOB
files
CONFIGURE_DEPENDS
"${source_path}/${feature}/${system}/**.c")
list(APPEND sources ${files})
set(system_exists TRUE)
endif()
# Break as soon a system-specific headers or sources are found.
if(system_exists)
break()
endif()
endforeach()
else()
message(STATUS "Feature ${feature} disabled")
endif()
else()
message(FATAL_ERROR "Feature ${feature} does not exist")
endif()
endforeach()
target_sources(ddsrt INTERFACE ${sources})
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
target_link_libraries(ddsrt INTERFACE Threads::Threads)
if(WIN32)
target_link_libraries(ddsrt INTERFACE wsock32 ws2_32 iphlpapi)
elseif(UNIX)
check_library_exists(c clock_gettime "" HAVE_CLOCK_GETTIME)
if(NOT HAVE_CLOCK_GETTIME)
# Before glibc 2.17, clock_gettime was in librt.
check_library_exists(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME_RT)
if(HAVE_CLOCK_GETTIME_RT)
set(HAVE_CLOCK_GETTIME TRUE)
target_link_libraries(ddsrt INTERFACE rt)
endif()
endif()
if(NOT HAVE_CLOCK_GETTIME)
message(FATAL_ERROR "clock_gettime is not available")
endif()
endif()
if(${CMAKE_C_COMPILER_ID} STREQUAL "SunPro")
target_link_libraries(ddsrt INTERFACE socket nsl)
endif()
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
install(
DIRECTORY "include/dds"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
COMPONENT dev
FILES_MATCHING PATTERN "*.h")
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/include/dds/version.h"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/dds"
COMPONENT dev)
if(WIN32)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/include/getopt.h"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
COMPONENT dev)
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
*/
#ifndef DDSRT_ARCH_H
#define DDSRT_ARCH_H
#if _WIN32
# if _WIN64
# define DDSRT_64BIT 1
# else
# define DDSRT_64BIT 0
# endif
#else
# if defined(_LP64)
# define DDSRT_64BIT 1
# else
# define DDSRT_64BIT 0
# endif
#endif
#endif /* DDSRT_ARCH_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 DDSRT_ATOMICS_H
#define DDSRT_ATOMICS_H
#include <stddef.h>
#include "dds/export.h"
#include "dds/ddsrt/arch.h"
#include "dds/ddsrt/endian.h"
#include "dds/ddsrt/types.h"
#if defined (__cplusplus)
extern "C" {
#endif
/**
* @brief Types on which atomic operations are defined.
*
* @note 64-bit types are defined even if atomic operations on them are not
* really supported. atomic
*/
typedef struct { uint32_t v; } ddsrt_atomic_uint32_t;
typedef struct { uint64_t v; } ddsrt_atomic_uint64_t;
typedef struct { uintptr_t v; } ddsrt_atomic_uintptr_t;
typedef ddsrt_atomic_uintptr_t ddsrt_atomic_voidp_t;
#if DDSRT_64BIT
# define DDSRT_HAVE_ATOMIC64 1
#endif
/**
* @brief Initializers for the types on which atomic operations are defined.
*/
#define DDSRT_ATOMIC_UINT32_INIT(v) { (v) }
#define DDSRT_ATOMIC_UINT64_INIT(v) { (v) }
#define DDSRT_ATOMIC_UINTPTR_INIT(v) { (v) }
#define DDSRT_ATOMIC_VOIDP_INIT(v) { (uintptr_t) (v) }
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40100
#include "dds/ddsrt/atomics/gcc.h"
#elif defined(_WIN32)
#include "dds/ddsrt/atomics/msvc.h"
#elif defined(__sun)
#include "dds/ddsrt/atomics/sun.h"
#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__)
#include "dds/ddsrt/atomics/arm.h"
#else
#error "Atomic operations are not supported"
#endif
#if defined(__cplusplus)
}
#endif
#endif /* DDSRT_ATOMICS_H */

View file

@ -0,0 +1,213 @@
/*
* 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 DDSRT_ATOMICS_ARM_H
#define DDSRT_ATOMICS_ARM_H
#if !defined(__arm__)
#define __arm__
#endif
/* IAR documentation states that __CPU_MODE__ is a predefined preprocessor
symbol reflecting the selected CPU mode and is defined to 1 for Thumb and
2 for ARM. */
#if !defined(__thumb__) && __CPU_MODE__ == 1
#define __thumb__
#endif
/* LD, ST */
inline uint32_t ddsrt_atomic_ld32 (const volatile ddsrt_atomic_uint32_t *x) { return x->v; }
inline uintptr_t ddsrt_atomic_ldptr (const volatile ddsrt_atomic_uintptr_t *x) { return x->v; }
inline void *ddsrt_atomic_ldvoidp (const volatile ddsrt_atomic_voidp_t *x) { return (void *) ddsrt_atomic_ldptr (x); }
inline void ddsrt_atomic_st32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { x->v = v; }
inline void ddsrt_atomic_stptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) { x->v = v; }
inline void ddsrt_atomic_stvoidp (volatile ddsrt_atomic_voidp_t *x, void *v) { ddsrt_atomic_stptr (x, (uintptr_t) v); }
/* CAS */
inline int ddsrt_atomic_cas32 (volatile ddsrt_atomic_uint32_t *x, uint32_t exp, uint32_t des) {
register int result;
asm volatile ("ldrex r0, [%1]\n\t" /*exclusive load of ptr */
"cmp r0, %2\n\t" /*compare the oldval == *ptr */
#if defined(__thumb__)
"ite eq\n\t"
#endif
"strexeq %0, %3, [%1]\n\t" /*store if eq, strex+eq*/
#if defined(__thumb__)
"clrexne"
#endif
: "=&r" (result)
: "r"(&x->v), "r"(exp),"r"(des)
: "r0");
return result == 0;
}
inline int ddsrt_atomic_casptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t exp, uintptr_t des) {
return ddsrt_atomic_cas32 ((volatile ddsrt_atomic_uint32_t *) x, exp, des);
}
inline int ddsrt_atomic_casvoidp (volatile ddsrt_atomic_voidp_t *x, void *exp, void *des) {
return ddsrt_atomic_casptr ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) exp, (uintptr_t) des);
}
/* ADD */
inline uint32_t ddsrt_atomic_add32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
register unsigned int result;
asm volatile ("1: ldrex %0, [%1]\n\t"
"add %0, %0, %2\n\t"
"strex r1, %0, [%1]\n\t"
"cmp r1, #0\n\t"
"bne 1b"
: "=&r" (result)
: "r"(&x->v), "r"(v)
: "r1");
return result;
}
inline uintptr_t ddsrt_atomic_addptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return ddsrt_atomic_add32_nv ((volatile ddsrt_atomic_uint32_t *) x, v);
}
inline void *ddsrt_atomic_addvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
return (void *) ddsrt_atomic_addptr_nv ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v);
}
inline void ddsrt_atomic_add32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
(void) ddsrt_atomic_add32_nv (x, v);
}
inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
(void) ddsrt_atomic_addptr_nv (x, v);
}
inline void ddsrt_atomic_addvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
(void) ddsrt_atomic_addvoidp_nv (x, v);
}
/* SUB */
inline uint32_t ddsrt_atomic_sub32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return ddsrt_atomic_add32_nv (x, -v);
}
inline uintptr_t ddsrt_atomic_subptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return ddsrt_atomic_addptr_nv (x, -v);
}
inline void *ddsrt_atomic_subvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
return ddsrt_atomic_addvoidp_nv (x, -v);
}
inline void ddsrt_atomic_sub32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
ddsrt_atomic_add32 (x, -v);
}
inline void ddsrt_atomic_subptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
ddsrt_atomic_subptr (x, -v);
}
inline void ddsrt_atomic_subvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
ddsrt_atomic_subvoidp (x, -v);
}
/* INC */
inline uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x) {
return ddsrt_atomic_add32_nv (x, 1);
}
inline uintptr_t ddsrt_atomic_incptr_nv (volatile ddsrt_atomic_uintptr_t *x) {
return ddsrt_atomic_addptr_nv (x, 1);
}
inline void ddsrt_atomic_inc32 (volatile ddsrt_atomic_uint32_t *x) {
(void) ddsrt_atomic_inc32_nv (x);
}
inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x) {
(void) ddsrt_atomic_incptr_nv (x);
}
/* DEC */
inline uint32_t ddsrt_atomic_dec32_nv (volatile ddsrt_atomic_uint32_t *x) {
return ddsrt_atomic_sub32_nv (x, 1);
}
inline uintptr_t ddsrt_atomic_decptr_nv (volatile ddsrt_atomic_uintptr_t *x) {
return ddsrt_atomic_subptr_nv (x, 1);
}
inline void ddsrt_atomic_dec32 (volatile ddsrt_atomic_uint32_t *x) {
(void) ddsrt_atomic_dec32_nv (x);
}
inline void ddsrt_atomic_decptr (volatile ddsrt_atomic_uintptr_t *x) {
(void) ddsrt_atomic_decptr_nv (x);
}
/* AND */
inline uint32_t ddsrt_atomic_and32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
uint32_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (!ddsrt_atomic_cas32 (x, oldval, newval));
return oldval;
}
inline uintptr_t ddsrt_atomic_andptr_ov (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
uintptr_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (!ddsrt_atomic_casptr (x, oldval, newval));
return oldval;
}
inline uint32_t ddsrt_atomic_and32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
uint32_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (!ddsrt_atomic_cas32 (x, oldval, newval));
return newval;
}
inline uintptr_t ddsrt_atomic_andptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
uintptr_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (!ddsrt_atomic_casptr (x, oldval, newval));
return newval;
}
inline void ddsrt_atomic_and32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
(void) ddsrt_atomic_and32_nv (x, v);
}
inline void ddsrt_atomic_andptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
(void) ddsrt_atomic_andptr_nv (x, v);
}
/* OR */
inline uint32_t ddsrt_atomic_or32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
uint32_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (!ddsrt_atomic_cas32 (x, oldval, newval));
return oldval;
}
inline uintptr_t ddsrt_atomic_orptr_ov (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
uintptr_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (!ddsrt_atomic_casptr (x, oldval, newval));
return oldval;
}
inline uint32_t ddsrt_atomic_or32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
uint32_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (!ddsrt_atomic_cas32 (x, oldval, newval));
return newval;
}
inline uintptr_t ddsrt_atomic_orptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
uintptr_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (!ddsrt_atomic_casptr (x, oldval, newval));
return newval;
}
inline void ddsrt_atomic_or32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
(void) ddsrt_atomic_or32_nv (x, v);
}
inline void ddsrt_atomic_orptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
(void) ddsrt_atomic_orptr_nv (x, v);
}
/* FENCES */
inline void ddsrt_atomic_fence (void) {
__asm volatile ("dmb" : : : "memory");
}
inline void ddsrt_atomic_fence_acq (void) {
ddsrt_atomic_fence ();
}
inline void ddsrt_atomic_fence_rel (void) {
ddsrt_atomic_fence ();
}
#endif /* DDSRT_ATOMICS_ARM_H */

View file

@ -0,0 +1,291 @@
/*
* 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 DDSRT_ATOMICS_GCC_H
#define DDSRT_ATOMICS_GCC_H
#include "dds/ddsrt/misc.h"
#if ( DDSRT_HAVE_ATOMIC64 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) || \
(!DDSRT_HAVE_ATOMIC64 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
# define DDSRT_HAVE_ATOMIC_LIFO 1
#endif
/* LD, ST */
inline uint32_t ddsrt_atomic_ld32(const volatile ddsrt_atomic_uint32_t *x) { return x->v; }
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_ld64(const volatile ddsrt_atomic_uint64_t *x) { return x->v; }
#endif
inline uintptr_t ddsrt_atomic_ldptr(const volatile ddsrt_atomic_uintptr_t *x) { return x->v; }
inline void *ddsrt_atomic_ldvoidp(const volatile ddsrt_atomic_voidp_t *x) { return (void *) ddsrt_atomic_ldptr(x); }
inline void ddsrt_atomic_st32(volatile ddsrt_atomic_uint32_t *x, uint32_t v) { x->v = v; }
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_st64(volatile ddsrt_atomic_uint64_t *x, uint64_t v) { x->v = v; }
#endif
inline void ddsrt_atomic_stptr(volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) { x->v = v; }
inline void ddsrt_atomic_stvoidp(volatile ddsrt_atomic_voidp_t *x, void *v) { ddsrt_atomic_stptr(x, (uintptr_t)v); }
/* INC */
inline void ddsrt_atomic_inc32(volatile ddsrt_atomic_uint32_t *x) {
__sync_fetch_and_add (&x->v, 1);
}
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x) {
__sync_fetch_and_add (&x->v, 1);
}
#endif
inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x) {
__sync_fetch_and_add (&x->v, 1);
}
inline uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x) {
return __sync_add_and_fetch (&x->v, 1);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_inc64_nv (volatile ddsrt_atomic_uint64_t *x) {
return __sync_add_and_fetch (&x->v, 1);
}
#endif
inline uintptr_t ddsrt_atomic_incptr_nv (volatile ddsrt_atomic_uintptr_t *x) {
return __sync_add_and_fetch (&x->v, 1);
}
/* DEC */
inline void ddsrt_atomic_dec32 (volatile ddsrt_atomic_uint32_t *x) {
__sync_fetch_and_sub (&x->v, 1);
}
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_dec64 (volatile ddsrt_atomic_uint64_t *x) {
__sync_fetch_and_sub (&x->v, 1);
}
#endif
inline void ddsrt_atomic_decptr (volatile ddsrt_atomic_uintptr_t *x) {
__sync_fetch_and_sub (&x->v, 1);
}
inline uint32_t ddsrt_atomic_dec32_nv (volatile ddsrt_atomic_uint32_t *x) {
return __sync_sub_and_fetch (&x->v, 1);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_dec64_nv (volatile ddsrt_atomic_uint64_t *x) {
return __sync_sub_and_fetch (&x->v, 1);
}
#endif
inline uintptr_t ddsrt_atomic_decptr_nv (volatile ddsrt_atomic_uintptr_t *x) {
return __sync_sub_and_fetch (&x->v, 1);
}
inline uint32_t ddsrt_atomic_dec32_ov (volatile ddsrt_atomic_uint32_t *x) {
return __sync_fetch_and_sub (&x->v, 1);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_dec64_ov (volatile ddsrt_atomic_uint64_t *x) {
return __sync_fetch_and_sub (&x->v, 1);
}
#endif
inline uintptr_t ddsrt_atomic_decptr_ov (volatile ddsrt_atomic_uintptr_t *x) {
return __sync_fetch_and_sub (&x->v, 1);
}
/* ADD */
inline void ddsrt_atomic_add32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
__sync_fetch_and_add (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_add64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
__sync_fetch_and_add (&x->v, v);
}
#endif
inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
__sync_fetch_and_add (&x->v, v);
}
inline void ddsrt_atomic_addvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
ddsrt_atomic_addptr ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v);
}
inline uint32_t ddsrt_atomic_add32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return __sync_add_and_fetch (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_add64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return __sync_add_and_fetch (&x->v, v);
}
#endif
inline uintptr_t ddsrt_atomic_addptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return __sync_add_and_fetch (&x->v, v);
}
inline void *ddsrt_atomic_addvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
return (void *) ddsrt_atomic_addptr_nv ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v);
}
/* SUB */
inline void ddsrt_atomic_sub32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
__sync_fetch_and_sub (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_sub64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
__sync_fetch_and_sub (&x->v, v);
}
#endif
inline void ddsrt_atomic_subptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
__sync_fetch_and_sub (&x->v, v);
}
inline void ddsrt_atomic_subvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
ddsrt_atomic_subptr ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v);
}
inline uint32_t ddsrt_atomic_sub32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return __sync_sub_and_fetch (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_sub64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return __sync_sub_and_fetch (&x->v, v);
}
#endif
inline uintptr_t ddsrt_atomic_subptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return __sync_sub_and_fetch (&x->v, v);
}
inline void *ddsrt_atomic_subvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
return (void *) ddsrt_atomic_subptr_nv ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v);
}
/* AND */
inline void ddsrt_atomic_and32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
__sync_fetch_and_and (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_and64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
__sync_fetch_and_and (&x->v, v);
}
#endif
inline void ddsrt_atomic_andptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
__sync_fetch_and_and (&x->v, v);
}
inline uint32_t ddsrt_atomic_and32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return __sync_fetch_and_and (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_and64_ov (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return __sync_fetch_and_and (&x->v, v);
}
#endif
inline uintptr_t ddsrt_atomic_andptr_ov (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return __sync_fetch_and_and (&x->v, v);
}
inline uint32_t ddsrt_atomic_and32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return __sync_and_and_fetch (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_and64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return __sync_and_and_fetch (&x->v, v);
}
#endif
inline uintptr_t ddsrt_atomic_andptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return __sync_and_and_fetch (&x->v, v);
}
/* OR */
inline void ddsrt_atomic_or32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
__sync_fetch_and_or (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_or64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
__sync_fetch_and_or (&x->v, v);
}
#endif
inline void ddsrt_atomic_orptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
__sync_fetch_and_or (&x->v, v);
}
inline uint32_t ddsrt_atomic_or32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return __sync_fetch_and_or (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_or64_ov (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return __sync_fetch_and_or (&x->v, v);
}
#endif
inline uintptr_t ddsrt_atomic_orptr_ov (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return __sync_fetch_and_or (&x->v, v);
}
inline uint32_t ddsrt_atomic_or32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return __sync_or_and_fetch (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_or64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return __sync_or_and_fetch (&x->v, v);
}
#endif
inline uintptr_t ddsrt_atomic_orptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return __sync_or_and_fetch (&x->v, v);
}
/* CAS */
inline int ddsrt_atomic_cas32 (volatile ddsrt_atomic_uint32_t *x, uint32_t exp, uint32_t des) {
return __sync_bool_compare_and_swap (&x->v, exp, des);
}
#if DDSRT_HAVE_ATOMIC64
inline int ddsrt_atomic_cas64 (volatile ddsrt_atomic_uint64_t *x, uint64_t exp, uint64_t des) {
return __sync_bool_compare_and_swap (&x->v, exp, des);
}
#endif
inline int ddsrt_atomic_casptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t exp, uintptr_t des) {
return __sync_bool_compare_and_swap (&x->v, exp, des);
}
inline int ddsrt_atomic_casvoidp (volatile ddsrt_atomic_voidp_t *x, void *exp, void *des) {
return ddsrt_atomic_casptr (x, (uintptr_t) exp, (uintptr_t) des);
}
#if DDSRT_HAVE_ATOMIC_LIFO
#if DDSRT_HAVE_ATOMIC64
typedef union { __int128_t x; struct { uintptr_t a, b; } s; } ddsrt_atomic_uintptr2_t;
#else
typedef union { uint64_t x; struct { uintptr_t a, b; } s; } ddsrt_atomic_uintptr2_t;
#endif
typedef struct {
ddsrt_atomic_uintptr2_t aba_head;
} ddsrt_atomic_lifo_t;
DDS_EXPORT void ddsrt_atomic_lifo_init(ddsrt_atomic_lifo_t *head);
DDS_EXPORT void ddsrt_atomic_lifo_push(ddsrt_atomic_lifo_t *head, void *elem, size_t linkoff);
DDS_EXPORT void *ddsrt_atomic_lifo_pop(ddsrt_atomic_lifo_t *head, size_t linkoff);
DDS_EXPORT void ddsrt_atomic_lifo_pushmany(ddsrt_atomic_lifo_t *head, void *first, void *last, size_t linkoff);
inline int ddsrt_atomic_casvoidp2 (volatile ddsrt_atomic_uintptr2_t *x, uintptr_t a0, uintptr_t b0, uintptr_t a1, uintptr_t b1) {
ddsrt_atomic_uintptr2_t o, n;
o.s.a = a0; o.s.b = b0;
n.s.a = a1; n.s.b = b1;
return __sync_bool_compare_and_swap (&x->x, o.x, n.x);
}
#endif
/* FENCES */
inline void ddsrt_atomic_fence (void) {
__sync_synchronize ();
}
inline void ddsrt_atomic_fence_ldld (void) {
#if !(defined __i386__ || defined __x86_64__ || defined _M_IX86 || defined _M_X64)
__sync_synchronize ();
#endif
}
inline void ddsrt_atomic_fence_acq (void) {
ddsrt_atomic_fence ();
}
inline void ddsrt_atomic_fence_rel (void) {
ddsrt_atomic_fence ();
}
#endif /* DDSRT_ATOMICS_GCC_H */

View file

@ -0,0 +1,299 @@
/*
* 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 DDSRT_ATOMICS_MSVC_H
#define DDSRT_ATOMICS_MSVC_H
#include "dds/ddsrt/misc.h"
/* 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 DDSRT_HAVE_ATOMIC64
#define DDSRT_ATOMIC_PTROP(name) name##64
#else
#define DDSRT_ATOMIC_PTROP(name) name
#endif
/* LD, ST */
inline uint32_t ddsrt_atomic_ld32 (const volatile ddsrt_atomic_uint32_t *x) { return x->v; }
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_ld64 (const volatile ddsrt_atomic_uint64_t *x) { return x->v; }
#endif
inline uintptr_t ddsrt_atomic_ldptr (const volatile ddsrt_atomic_uintptr_t *x) { return x->v; }
inline void *ddsrt_atomic_ldvoidp (const volatile ddsrt_atomic_voidp_t *x) { return (void *) ddsrt_atomic_ldptr (x); }
inline void ddsrt_atomic_st32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { x->v = v; }
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_st64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) { x->v = v; }
#endif
inline void ddsrt_atomic_stptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) { x->v = v; }
inline void ddsrt_atomic_stvoidp (volatile ddsrt_atomic_voidp_t *x, void *v) { ddsrt_atomic_stptr (x, (uintptr_t) v); }
/* CAS */
inline int ddsrt_atomic_cas32 (volatile ddsrt_atomic_uint32_t *x, uint32_t exp, uint32_t des) {
return InterlockedCompareExchange (&x->v, des, exp) == exp;
}
#if DDSRT_HAVE_ATOMIC64
inline int ddsrt_atomic_cas64 (volatile ddsrt_atomic_uint64_t *x, uint64_t exp, uint64_t des) {
return InterlockedCompareExchange64 (&x->v, des, exp) == exp;
}
#endif
inline int ddsrt_atomic_casptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t exp, uintptr_t des) {
return DDSRT_ATOMIC_PTROP (InterlockedCompareExchange) (&x->v, des, exp) == exp;
}
inline int ddsrt_atomic_casvoidp (volatile ddsrt_atomic_voidp_t *x, void *exp, void *des) {
return ddsrt_atomic_casptr ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) exp, (uintptr_t) des);
}
/* INC */
inline void ddsrt_atomic_inc32 (volatile ddsrt_atomic_uint32_t *x) {
InterlockedIncrement (&x->v);
}
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x) {
InterlockedIncrement64 (&x->v);
}
#endif
inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x) {
DDSRT_ATOMIC_PTROP (InterlockedIncrement) (&x->v);
}
inline uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x) {
return InterlockedIncrement (&x->v);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_inc64_nv (volatile ddsrt_atomic_uint64_t *x) {
return InterlockedIncrement64 (&x->v);
}
#endif
inline uintptr_t ddsrt_atomic_incptr_nv (volatile ddsrt_atomic_uintptr_t *x) {
return DDSRT_ATOMIC_PTROP (InterlockedIncrement) (&x->v);
}
/* DEC */
inline void ddsrt_atomic_dec32 (volatile ddsrt_atomic_uint32_t *x) {
InterlockedDecrement (&x->v);
}
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_dec64 (volatile ddsrt_atomic_uint64_t *x) {
InterlockedDecrement64 (&x->v);
}
#endif
inline void ddsrt_atomic_decptr (volatile ddsrt_atomic_uintptr_t *x) {
DDSRT_ATOMIC_PTROP (InterlockedDecrement) (&x->v);
}
inline uint32_t ddsrt_atomic_dec32_nv (volatile ddsrt_atomic_uint32_t *x) {
return InterlockedDecrement (&x->v);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_dec64_nv (volatile ddsrt_atomic_uint64_t *x) {
return InterlockedDecrement64 (&x->v);
}
#endif
inline uintptr_t ddsrt_atomic_decptr_nv (volatile ddsrt_atomic_uintptr_t *x) {
return DDSRT_ATOMIC_PTROP (InterlockedDecrement) (&x->v);
}
inline uint32_t ddsrt_atomic_dec32_ov (volatile ddsrt_atomic_uint32_t *x) {
return InterlockedDecrement (&x->v) + 1;
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_dec64_ov (volatile ddsrt_atomic_uint64_t *x) {
return InterlockedDecrement64 (&x->v) + 1;
}
#endif
inline uintptr_t ddsrt_atomic_decptr_ov (volatile ddsrt_atomic_uintptr_t *x) {
return DDSRT_ATOMIC_PTROP (InterlockedDecrement) (&x->v) + 1;
}
/* ADD */
inline void ddsrt_atomic_add32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
InterlockedExchangeAdd (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_add64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
InterlockedExchangeAdd64 (&x->v, v);
}
#endif
inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
DDSRT_ATOMIC_PTROP (InterlockedExchangeAdd) (&x->v, v);
}
inline void ddsrt_atomic_addvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
ddsrt_atomic_addptr ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v);
}
inline uint32_t ddsrt_atomic_add32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return InterlockedExchangeAdd (&x->v, v) + v;
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_add64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return InterlockedExchangeAdd64 (&x->v, v) + v;
}
#endif
inline uintptr_t ddsrt_atomic_addptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return DDSRT_ATOMIC_PTROP (InterlockedExchangeAdd) (&x->v, v) + v;
}
inline void *ddsrt_atomic_addvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
return (void *) ddsrt_atomic_addptr_nv ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v);
}
/* SUB */
inline void ddsrt_atomic_sub32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
/* disable unary minus applied to unsigned type, result still unsigned */
DDSRT_WARNING_MSVC_OFF(4146)
InterlockedExchangeAdd (&x->v, -v);
DDSRT_WARNING_MSVC_ON(4146)
}
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_sub64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
/* disable unary minus applied to unsigned type, result still unsigned */
DDSRT_WARNING_MSVC_OFF(4146)
InterlockedExchangeAdd64 (&x->v, -v);
DDSRT_WARNING_MSVC_ON(4146)
}
#endif
inline void ddsrt_atomic_subptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
/* disable unary minus applied to unsigned type, result still unsigned */
DDSRT_WARNING_MSVC_OFF(4146)
DDSRT_ATOMIC_PTROP (InterlockedExchangeAdd) (&x->v, -v);
DDSRT_WARNING_MSVC_ON(4146)
}
inline void ddsrt_atomic_subvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
ddsrt_atomic_subptr ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v);
}
inline uint32_t ddsrt_atomic_sub32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
/* disable unary minus applied to unsigned type, result still unsigned */
DDSRT_WARNING_MSVC_OFF(4146)
return InterlockedExchangeAdd (&x->v, -v) - v;
DDSRT_WARNING_MSVC_ON(4146)
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_sub64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
/* disable unary minus applied to unsigned type, result still unsigned */
DDSRT_WARNING_MSVC_OFF(4146)
return InterlockedExchangeAdd64 (&x->v, -v) - v;
DDSRT_WARNING_MSVC_ON(4146)
}
#endif
inline uintptr_t ddsrt_atomic_subptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
/* disable unary minus applied to unsigned type, result still unsigned */
DDSRT_WARNING_MSVC_OFF(4146)
return DDSRT_ATOMIC_PTROP (InterlockedExchangeAdd) (&x->v, -v) - v;
DDSRT_WARNING_MSVC_ON(4146)
}
inline void *ddsrt_atomic_subvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
return (void *) ddsrt_atomic_subptr_nv ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v);
}
/* AND */
inline void ddsrt_atomic_and32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
InterlockedAnd (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_and64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
InterlockedAnd64 (&x->v, v);
}
#endif
inline void ddsrt_atomic_andptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
DDSRT_ATOMIC_PTROP (InterlockedAnd) (&x->v, v);
}
inline uint32_t ddsrt_atomic_and32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return InterlockedAnd (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_and64_ov (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return InterlockedAnd64 (&x->v, v);
}
#endif
inline uintptr_t ddsrt_atomic_andptr_ov (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return DDSRT_ATOMIC_PTROP (InterlockedAnd) (&x->v, v);
}
inline uint32_t ddsrt_atomic_and32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return InterlockedAnd (&x->v, v) & v;
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_and64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return InterlockedAnd64 (&x->v, v) & v;
}
#endif
inline uintptr_t ddsrt_atomic_andptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return DDSRT_ATOMIC_PTROP (InterlockedAnd) (&x->v, v) & v;
}
/* OR */
inline void ddsrt_atomic_or32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
InterlockedOr (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline void ddsrt_atomic_or64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
InterlockedOr64 (&x->v, v);
}
#endif
inline void ddsrt_atomic_orptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
DDSRT_ATOMIC_PTROP (InterlockedOr) (&x->v, v);
}
inline uint32_t ddsrt_atomic_or32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return InterlockedOr (&x->v, v);
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_or64_ov (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return InterlockedOr64 (&x->v, v);
}
#endif
inline uintptr_t ddsrt_atomic_orptr_ov (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return DDSRT_ATOMIC_PTROP (InterlockedOr) (&x->v, v);
}
inline uint32_t ddsrt_atomic_or32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return InterlockedOr (&x->v, v) | v;
}
#if DDSRT_HAVE_ATOMIC64
inline uint64_t ddsrt_atomic_or64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return InterlockedOr64 (&x->v, v) | v;
}
#endif
inline uintptr_t ddsrt_atomic_orptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return DDSRT_ATOMIC_PTROP (InterlockedOr) (&x->v, v) | v;
}
/* FENCES */
inline void ddsrt_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. */
DDSRT_WARNING_MSVC_OFF(28113)
volatile LONG tmp = 0;
InterlockedExchange (&tmp, 0);
DDSRT_WARNING_MSVC_ON(28113)
}
inline void ddsrt_atomic_fence_ldld (void) {
#if !(defined _M_IX86 || defined _M_X64)
ddsrt_atomic_fence ();
#endif
}
inline void ddsrt_atomic_fence_acq (void) {
ddsrt_atomic_fence ();
}
inline void ddsrt_atomic_fence_rel (void) {
ddsrt_atomic_fence ();
}
#undef DDSRT_ATOMIC_PTROP
#endif /* DDSRT_ATOMICS_MSVC_H */

View file

@ -0,0 +1,241 @@
/*
* 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 <atomic.h>
#define DDSRT_ATOMIC64_SUPPORT 1
/* LD, ST */
inline uint32_t ddsrt_atomic_ld32 (const volatile ddsrt_atomic_uint32_t *x) { return x->v; }
inline uint64_t ddsrt_atomic_ld64 (const volatile ddsrt_atomic_uint64_t *x) { return x->v; }
inline uintptr_t ddsrt_atomic_ldptr (const volatile ddsrt_atomic_uintptr_t *x) { return x->v; }
inline void *ddsrt_atomic_ldvoidp (const volatile ddsrt_atomic_voidp_t *x) { return (void *) ddsrt_atomic_ldptr (x); }
inline void ddsrt_atomic_st32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { x->v = v; }
inline void ddsrt_atomic_st64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) { x->v = v; }
inline void ddsrt_atomic_stptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) { x->v = v; }
inline void ddsrt_atomic_stvoidp (volatile ddsrt_atomic_voidp_t *x, void *v) { ddsrt_atomic_stptr (x, (uintptr_t) v); }
/* INC */
inline void ddsrt_atomic_inc32 (volatile ddsrt_atomic_uint32_t *x) {
atomic_inc_32 (&x->v);
}
inline void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x) {
atomic_inc_64 (&x->v);
}
inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x) {
atomic_inc_ulong (&x->v);
}
inline uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x) {
return atomic_inc_32_nv (&x->v);
}
inline uint64_t ddsrt_atomic_inc64_nv (volatile ddsrt_atomic_uint64_t *x) {
return atomic_inc_64_nv (&x->v);
}
inline uintptr_t ddsrt_atomic_incptr_nv (volatile ddsrt_atomic_uintptr_t *x) {
return atomic_inc_ulong_nv (&x->v);
}
/* DEC */
inline void ddsrt_atomic_dec32 (volatile ddsrt_atomic_uint32_t *x) {
atomic_dec_32 (&x->v);
}
inline void ddsrt_atomic_dec64 (volatile ddsrt_atomic_uint64_t *x) {
atomic_dec_64 (&x->v);
}
inline void ddsrt_atomic_decptr (volatile ddsrt_atomic_uintptr_t *x) {
atomic_dec_ulong (&x->v);
}
inline uint32_t ddsrt_atomic_dec32_nv (volatile ddsrt_atomic_uint32_t *x) {
return atomic_dec_32_nv (&x->v);
}
inline uint64_t ddsrt_atomic_dec64_nv (volatile ddsrt_atomic_uint64_t *x) {
return atomic_dec_64_nv (&x->v);
}
inline uintptr_t ddsrt_atomic_decptr_nv (volatile ddsrt_atomic_uintptr_t *x) {
return atomic_dec_ulong_nv (&x->v);
}
inline uint32_t ddsrt_atomic_dec32_ov (volatile ddsrt_atomic_uint32_t *x) {
uint32_t oldval, newval;
do { oldval = x->v; newval = oldval - 1; } while (atomic_cas_32 (&x->v, oldval, newval) != oldval);
return oldval;
}
inline uint64_t ddsrt_atomic_dec64_ov (volatile ddsrt_atomic_uint64_t *x) {
uint64_t oldval, newval;
do { oldval = x->v; newval = oldval - 1; } while (atomic_cas_64 (&x->v, oldval, newval) != oldval);
return oldval;
}
inline uintptr_t ddsrt_atomic_decptr_ov (volatile ddsrt_atomic_uintptr_t *x) {
uintptr_t oldval, newval;
do { oldval = x->v; newval = oldval - 1; } while (atomic_cas_64 (&x->v, oldval, newval) != oldval);
return oldval;
}
/* ADD */
inline void ddsrt_atomic_add32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
atomic_add_32 (&x->v, v);
}
inline void ddsrt_atomic_add64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
atomic_add_64 (&x->v, v);
}
inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
atomic_add_long (&x->v, v);
}
inline void ddsrt_atomic_addvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
atomic_add_ptr (&x->v, v);
}
inline uint32_t ddsrt_atomic_add32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return atomic_add_32_nv (&x->v, v);
}
inline uint64_t ddsrt_atomic_add64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return atomic_add_64_nv (&x->v, v);
}
inline uintptr_t ddsrt_atomic_addptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return atomic_add_long_nv (&x->v, v);
}
inline void *ddsrt_atomic_addvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
return atomic_add_ptr_nv (&x->v, v);
}
/* SUB */
inline void ddsrt_atomic_sub32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
atomic_add_32 (&x->v, -v);
}
inline void ddsrt_atomic_sub64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
atomic_add_64 (&x->v, -v);
}
inline void ddsrt_atomic_subptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
atomic_add_long (&x->v, -v);
}
inline void ddsrt_atomic_subvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
atomic_add_ptr (&x->v, -v);
}
inline uint32_t ddsrt_atomic_sub32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return atomic_add_32_nv (&x->v, -v);
}
inline uint64_t ddsrt_atomic_sub64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return atomic_add_64_nv (&x->v, -v);
}
inline uintptr_t ddsrt_atomic_subptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return atomic_add_long_nv (&x->v, -v);
}
inline void *ddsrt_atomic_subvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) {
return atomic_add_ptr_nv (&x->v, -v);
}
/* AND */
inline void ddsrt_atomic_and32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
atomic_and_32 (&x->v, v);
}
inline void ddsrt_atomic_and64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
atomic_and_64 (&x->v, v);
}
inline void ddsrt_atomic_andptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
atomic_and_ulong (&x->v, v);
}
inline uint32_t ddsrt_atomic_and32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
uint32_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (atomic_cas_32 (&x->v, oldval, newval) != oldval);
return oldval;
}
inline uint64_t ddsrt_atomic_and64_ov (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
uint64_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (atomic_cas_64 (&x->v, oldval, newval) != oldval);
return oldval;
}
inline uintptr_t ddsrt_atomic_andptr_ov (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
uintptr_t oldval, newval;
do { oldval = x->v; newval = oldval & v; } while (atomic_cas_ulong (&x->v, oldval, newval) != oldval);
return oldval;
}
inline uint32_t ddsrt_atomic_and32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return atomic_and_32_nv (&x->v, v);
}
inline uint64_t ddsrt_atomic_and64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return atomic_and_64_nv (&x->v, v);
}
inline uintptr_t ddsrt_atomic_andptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return atomic_and_ulong_nv (&x->v, v);
}
/* OR */
inline void ddsrt_atomic_or32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
atomic_or_32 (&x->v, v);
}
inline void ddsrt_atomic_or64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
atomic_or_64 (&x->v, v);
}
inline void ddsrt_atomic_orptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
atomic_or_ulong (&x->v, v);
}
inline uint32_t ddsrt_atomic_or32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
uint32_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (atomic_cas_32 (&x->v, oldval, newval) != oldval);
return oldval;
}
inline uint64_t ddsrt_atomic_or64_ov (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
uint64_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (atomic_cas_64 (&x->v, oldval, newval) != oldval);
return oldval;
}
inline uintptr_t ddsrt_atomic_orptr_ov (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
uintptr_t oldval, newval;
do { oldval = x->v; newval = oldval | v; } while (atomic_cas_ulong (&x->v, oldval, newval) != oldval);
return oldval;
}
inline uint32_t ddsrt_atomic_or32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return atomic_or_32_nv (&x->v, v);
}
inline uint64_t ddsrt_atomic_or64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) {
return atomic_or_64_nv (&x->v, v);
}
inline uintptr_t ddsrt_atomic_orptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
return atomic_or_ulong_nv (&x->v, v);
}
/* CAS */
inline int ddsrt_atomic_cas32 (volatile ddsrt_atomic_uint32_t *x, uint32_t exp, uint32_t des) {
return atomic_cas_32 (&x->v, exp, des) == exp;
}
inline int ddsrt_atomic_cas64 (volatile ddsrt_atomic_uint64_t *x, uint64_t exp, uint64_t des) {
return atomic_cas_64 (&x->v, exp, des) == exp;
}
inline int ddsrt_atomic_casptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t exp, uintptr_t des) {
return atomic_cas_ulong (&x->v, exp, des) == exp;
}
inline int ddsrt_atomic_casvoidp (volatile ddsrt_atomic_voidp_t *x, void *exp, void *des) {
return atomic_cas_ptr (&x->v, exp, des) == exp;
}
/* FENCES */
inline void ddsrt_atomic_fence (void) {
membar_exit ();
membar_enter ();
}
inline void ddsrt_atomic_fence_ldld (void) {
membar_enter ();
}
inline void ddsrt_atomic_fence_acq (void) {
membar_enter ();
}
inline void ddsrt_atomic_fence_rel (void) {
membar_exit ();
}

View file

@ -0,0 +1,104 @@
/*
* 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 DDSRT_ATTRIBUTES_H
#define DDSRT_ATTRIBUTES_H
#if __clang__
# define ddsrt_gnuc (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#else
# define ddsrt_gnuc (0)
#endif
#if __GNUC__
# define ddsrt_clang (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
#else
# define ddsrt_clang (0)
#endif
#if defined(__has_attribute)
# define ddsrt_has_attribute(params) __has_attribute(params)
#elif ddsrt_gnuc
# define ddsrt_has_attribute(params) (1) /* GCC < 5 */
#else
# define ddsrt_has_attribute(params) (0)
#endif
#if ddsrt_has_attribute(malloc)
# define ddsrt_attribute_malloc __attribute__ ((__malloc__))
#else
# define ddsrt_attribute_malloc
#endif
#if ddsrt_has_attribute(unused)
# define ddsrt_attribute_unused __attribute__((__unused__))
#else
# define ddsrt_attribute_unused
#endif
#if ddsrt_has_attribute(noreturn)
# define ddsrt_attribute_noreturn __attribute__ ((__noreturn__))
#else
# define ddsrt_attribute_noreturn
#endif
#if ddsrt_has_attribute(nonnull)
# define ddsrt_nonnull(params) __attribute__ ((__nonnull__ params))
# define ddsrt_nonnull_all __attribute__ ((__nonnull__))
#else
# define ddsrt_nonnull(params)
# define ddsrt_nonnull_all
#endif
#if ddsrt_has_attribute(returns_nonnull) && (ddsrt_clang || ddsrt_gnuc >= 40900)
# define ddsrt_attribute_returns_nonnull __attribute__ ((__returns_nonnull__))
#else
# define ddsrt_attribute_returns_nonnull
#endif
/* GCC <= 4.2.4 has the attribute, but warns that it ignores it. */
#if !ddsrt_has_attribute(alloc_size) || (ddsrt_gnuc <= 40204)
# define ddsrt_attribute_alloc_size(params)
#else
# define ddsrt_attribute_alloc_size(params) __attribute__ ((__alloc_size__ params))
#endif
#if ddsrt_has_attribute(const)
# define ddsrt_attribute_const __attribute__ ((__const__))
#else
# define ddsrt_attribute_const
#endif
#if ddsrt_has_attribute(pure)
# define ddsrt_attribute_pure __attribute__ ((__pure__))
#else
# define ddsrt_attribute_pure
#endif
#if ddsrt_has_attribute(format)
# define ddsrt_attribute_format(params) __attribute__ ((__format__ params))
#else
# define ddsrt_attribute_format(params)
#endif
#if ddsrt_has_attribute(warn_unused_result)
# define ddsrt_attribute_warn_unused_result __attribute__ ((__warn_unused_result__))
#else
# define ddsrt_attribute_warn_unused_result
#endif
#if ddsrt_has_attribute(assume_aligned)
# define ddsrt_attribute_assume_aligned(params) __attribute__ ((__assume_aligned__ params))
#else
# define ddsrt_attribute_assume_aligned(params)
#endif
#endif /* DDSRT_ATTRIBUTES_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 DDSRT_CDTORS_H
#define DDSRT_CDTORS_H
#include "dds/export.h"
#include "dds/ddsrt/sync.h"
DDS_EXPORT void ddsrt_init(void);
DDS_EXPORT void ddsrt_fini(void);
DDS_EXPORT ddsrt_mutex_t *ddsrt_get_singleton_mutex(void);
#endif /* DDSRT_CDTORS_H */

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
*/
#ifndef DDSRT_ENDIAN_H
#define DDSRT_ENDIAN_H
#if defined(__cplusplus)
extern "C" {
#endif
#define DDSRT_LITTLE_ENDIAN 1
#define DDSRT_BIG_ENDIAN 2
#if _WIN32
# if defined(__BIG_ENDIAN)
# define DDSRT_ENDIAN DDSRT_BIG_ENDIAN
# else
# define DDSRT_ENDIAN DDSRT_LITTLE_ENDIAN
# endif
#else /* _WIN32 */
# if defined(__BYTE_ORDER__)
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define DDSRT_ENDIAN DDSRT_BIG_ENDIAN
# elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define DDSRT_ENDIAN DDSRT_LITTLE_ENDIAN
# endif
# endif
#endif /* _WIN32 */
#if (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN) && \
(DDSRT_ENDIAN != DDSRT_BIG_ENDIAN)
# error "Endianness cannot be determined"
#endif
#if defined(__cplusplus)
}
#endif
#endif /* DDSRT_ENDIAN_H */

View file

@ -0,0 +1,103 @@
/*
* 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 DDSRT_ENVIRON_H
#define DDSRT_ENVIRON_H
#include "dds/export.h"
#include "dds/ddsrt/attributes.h"
#include "dds/ddsrt/retcode.h"
#if defined(__cplusplus)
extern "C" {
#endif
/**
* @brief Get value for environment variable.
*
* @param[in] name Environment variable name.
* @param[in] buf Buffer to write value to.
* @param[in] sz Size of buffer.
* @param[out] reqsz Number of bytes written (excluding the terminating null
* byte), or would have been written would @buf have been
* sufficiently large enough.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Environment variable written to @buf.
* @retval DDS_RETCODE_NOT_FOUND
* Environment variable not found.
* @retval DDS_RETCODE_BAD_PARAMETER
* FIXME: document
* @retval DDS_RETCODE_OUT_OF_RESOURCES
* FIXME: document
* @retval DDS_RETCODE_ERROR
* Unspecified error.
*/
DDS_EXPORT dds_retcode_t
ddsrt_getenv(
const char *name,
char **value)
ddsrt_nonnull_all;
/**
* @brief Set environment variable value.
*
* Sets the environment variable to the value specified in value, or
* alternatively, unsets the environment variable if value is an empty string.
*
* @param[in] name Environment variable name.
* @param[in] value Value to set environment variable to.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Environment variable successfully set to @value.
* @retval DDS_RETCODE_BAD_PARAMETER
* Invalid environment variable name.
* @retval DDS_RETCODE_OUT_OF_RESOURCES
* Not enough system resources to set environment variable.
* @retval DDS_RETCODE_ERROR
* Unspecified system error.
*/
DDS_EXPORT dds_retcode_t
ddsrt_setenv(
const char *name,
const char *value)
ddsrt_nonnull_all;
/**
* @brief Unset environment variable value.
*
* @param[in] name Environment variable name.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Environment variable successfully unset.
* @retval DDS_RETCODE_BAD_PARAMETER
* Invalid environment variable name.
* @retval DDS_RETCODE_OUT_OF_RESOURCES
* Not enough system resources to unset environment variable.
* @retval DDS_RETCODE_ERROR
* Unspecified system error.
*/
DDS_EXPORT dds_retcode_t
ddsrt_unsetenv(
const char *name)
ddsrt_nonnull_all;
#if defined(__cplusplus)
}
#endif
#endif /* DDSRT_ENVIRON_H */

View file

@ -0,0 +1,155 @@
/*
* 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 heap.h
* @brief Heap memory management.
*
* Platform independent interface to heap memory management.
*/
#ifndef DDSRT_HEAP_H
#define DDSRT_HEAP_H
#include <stddef.h>
#include "dds/export.h"
#include "dds/ddsrt/attributes.h"
#if defined (__cplusplus)
extern "C" {
#endif
/**
* @brief Allocate memory from heap.
*
* The allocated block of memory must be freed by calling @ddsrt_free when no
* longer used.
*
* @param[in] size The size, in bytes, of the block of memory to allocate.
*
* @returns A pointer to the allocated block of memory. abort() is called if
* not enough free memory was available.
*/
DDS_EXPORT void *
ddsrt_malloc(
size_t size)
ddsrt_attribute_malloc
ddsrt_attribute_alloc_size((1));
/**
* @brief Allocate memory from heap.
*
* Allocate a block of memory from heap with the given size. The allocated
* block of memory must be freed by calling @ddsrt_free when no longer used.
*
* @param[in] size The size, in bytes, of memory to allocate.
*
* @returns A pointer to the allocated block of memory, NULL if not enough
* memory was available.
*/
DDS_EXPORT void *
ddsrt_malloc_s(
size_t size)
ddsrt_attribute_malloc
ddsrt_attribute_alloc_size((1));
/**
* @brief Allocate memory from heap for an array of @count elements of @size
* bytes.
*
* The allocated memory is initialized to zero. The allocated memory must be
* freed by calling @ddsrt_free when no longer used.
*
* A non-NULL pointer, that must be freed is always returned, even if the sum
* @count and @size equals zero.
*
* @returns A pointer to the allocated memory. abort() is called if not enough
* free memory was available.
*/
DDS_EXPORT void *
ddsrt_calloc(
size_t count,
size_t size)
ddsrt_attribute_malloc
ddsrt_attribute_alloc_size((1,2));
/**
* @brief Allocate memory from heap for an array of @count elements of @size
* bytes.
*
* The allocated memory is initialized to zero. The allocated memory must be
* freed by calling @ddsrt_free when no longer used.
*
* A non-NULL pointer, that must be freed is always returned, even if the sum
* @count and @size equals zero.
*
* @returns A pointer to the allocated memory, or NULL if not enough memory was
* available.
*/
DDS_EXPORT void *
ddsrt_calloc_s(
size_t count,
size_t size)
ddsrt_attribute_malloc
ddsrt_attribute_alloc_size((1,2));
/**
* @brief Reallocate memory from heap.
*
* Reallocate memory from heap. If memblk is NULL the function returns
* ddsrt_malloc_s(size). If size is 0, ddsrt_realloc_s free's the memory
* pointed to by memblk and returns a pointer as if ddsrt_malloc_s(0) was
* invoked. The returned pointer must be free'd with ddsrt_free.
*
* @returns A pointer to reallocated memory. Calls abort() if not enough free
* memory was available.
*/
DDS_EXPORT void *
ddsrt_realloc(
void *memblk,
size_t size)
ddsrt_attribute_malloc
ddsrt_attribute_alloc_size((2));
/**
* @brief Reallocate memory from heap.
*
* Reallocate memory from heap. If memblk is NULL the function returns
* ddsrt_malloc_s(size). If size is 0, ddsrt_realloc_s free's the memory
* pointed to by memblk and returns a pointer as if ddsrt_malloc_s(0) was
* invoked. The returned pointer must be free'd with ddsrt_free.
*
* @returns A pointer to reallocated memory, or NULL if not enough free memory
* was available.
*/
DDS_EXPORT void *
ddsrt_realloc_s(
void *memblk,
size_t size)
ddsrt_attribute_malloc
ddsrt_attribute_alloc_size((2));
/**
* @brief Free a previously allocated block of memory and return it to heap.
*
* Free the allocated memory pointed to by @ptr and release it to the heap. No
* action will be taken if @ptr is NULL.
*
* @param[in] ptr Pointer to previously allocated block of memory.
*/
DDS_EXPORT void
ddsrt_free(void *ptr);
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_HEAP_H */

View file

@ -0,0 +1,46 @@
/*
* 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 DDSRT_IFADDRS_H
#define DDSRT_IFADDRS_H
#include "dds/ddsrt/sockets.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct ddsrt_ifaddrs {
struct ddsrt_ifaddrs *next;
char *name;
uint32_t index;
uint32_t flags;
struct sockaddr *addr;
struct sockaddr *netmask;
struct sockaddr *broadaddr;
};
typedef struct ddsrt_ifaddrs ddsrt_ifaddrs_t;
DDS_EXPORT dds_retcode_t
ddsrt_getifaddrs(
ddsrt_ifaddrs_t **ifap,
const int *afs);
DDS_EXPORT void
ddsrt_freeifaddrs(
ddsrt_ifaddrs_t *ifa);
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_IFADDRS_H */

View file

@ -0,0 +1,41 @@
/*
* 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 DDSRT_IO_H
#define DDSRT_IO_H
#include <stdarg.h>
#include <stdio.h>
#include "dds/export.h"
#if defined(__cplusplus)
extern "C" {
#endif
/**
* @brief Write a formatted string to a newly allocated buffer.
*/
DDS_EXPORT int
ddsrt_asprintf(
char **strp,
const char *fmt,
...);
#if defined(_MSC_VER) && (_MSC_VER < 1900)
extern int snprintf(char *s, size_t n, const char *format, ...);
#endif
#if defined(__cplusplus)
}
#endif
#endif /* DDSRT_IO_H */

View file

@ -0,0 +1,302 @@
/*
* 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 DDS C Logging API
*
* This header file defines the public API for logging and controlling logging
* in the DDS C language binding.
*/
#ifndef DDS_LOG_H
#define DDS_LOG_H
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include "dds/export.h"
#if defined (__cplusplus)
extern "C" {
#endif
/** @defgroup log_categories Convenience log category definitions.
*
* These defines expand into numeric values that can be ORed together to
* specify messages of which categories must be passed to the respective sinks.
*
* Every category other than DDS_LC_FATAL, DDS_LC_ERROR, DDS_LC_WARNING and
* DDS_LC_INFO automatically falls into the trace category.
*
* @{
*/
/** Fatal error condition. Immediate abort on sink return. */
#define DDS_LC_FATAL (1u)
/** Error condition. */
#define DDS_LC_ERROR (2u)
/** Warning condition. */
#define DDS_LC_WARNING (4u)
/** Informational message. */
#define DDS_LC_INFO (8u)
/** Debug/trace messages related to configuration settings. */
#define DDS_LC_CONFIG (16u)
/** Debug/trace messages related to node discovery. */
#define DDS_LC_DISCOVERY (32u)
/** Currently unused. */
#define DDS_LC_DATA (64u)
/** Debug/trace messages for which no specialized category exists (yet). */
#define DDS_LC_TRACE (128u)
/** Debug/trace messages related to receive administration. */
#define DDS_LC_RADMIN (256u)
/** Debug/trace messages related to timing. */
#define DDS_LC_TIMING (512u)
/** Debug/trace messages related to send administration. */
#define DDS_LC_TRAFFIC (1024u)
/** Currently unused. */
#define DDS_LC_TOPIC (2048u)
/** Debug/trace messages related to TCP communication. */
#define DDS_LC_TCP (4096u)
/** Debug/trace messages related to parameter list processing. */
#define DDS_LC_PLIST (8192u)
/** Debug/trace messages related to the writer history cache. */
#define DDS_LC_WHC (16384u)
/** Debug/trace messages related to throttling. */
#define DDS_LC_THROTTLE (32768u)
/** All common trace categories. */
#define DDS_LC_RHC (65536u)
/** All common trace categories. */
#define DDS_LC_ALL \
(DDS_LC_FATAL | DDS_LC_ERROR | DDS_LC_WARNING | DDS_LC_INFO | \
DDS_LC_CONFIG | DDS_LC_DISCOVERY | DDS_LC_DATA | DDS_LC_TRACE | \
DDS_LC_TIMING | DDS_LC_TRAFFIC | DDS_LC_TCP | DDS_LC_THROTTLE)
/** @}*/
#define DDS_LOG_MASK \
(DDS_LC_FATAL | DDS_LC_ERROR | DDS_LC_WARNING | DDS_LC_INFO)
#define DDS_TRACE_MASK \
(~DDS_LOG_MASK)
/** Structure with log message and meta data passed to callbacks. */
typedef struct {
/** Log category the message falls into. */
uint32_t priority;
/** Filename where message was generated. */
const char *file;
/** Line number in file where message was generated. */
uint32_t line;
/** Name of function message where message was generated. */
const char *function;
/** Log message. */
const char *message;
/** Size of log message. */
size_t size;
} dds_log_data_t;
/** Function signature that log and trace callbacks must adhere too. */
typedef void(*dds_log_write_fn_t)(void *, const dds_log_data_t *);
extern uint32_t *const dds_log_mask;
/**
* @brief Get currently enabled log and trace categories.
*
* @returns A uint32_t with enabled categories set.
*/
inline uint32_t
dds_get_log_mask(void)
{
return *dds_log_mask;
}
/**
* @brief Set enabled log and trace categories.
*
* @param[in] cats Log and trace categories to enable.
*/
DDS_EXPORT void
dds_set_log_mask(
uint32_t cats);
/**
* @private
*/
DDS_EXPORT void
dds_set_log_file(
FILE *file);
/**
* @private
*/
DDS_EXPORT void
dds_set_trace_file(
FILE *file);
/**
* @brief Register callback to receive log messages
*
* Callbacks registered to handle log messages will receive messages of type
* info, warning, error and fatal. Messages that fall into the trace category
* will never be delivered to the callback.
*
* This operation is synchronous and only returns once the operation is
* registered with all threads. Meaning that neither callback or userdata will
* be referenced by the DDS stack on return.
*
* @param[in] callback Function pointer matching dds_log_write_fn signature
* or a null pointer to restore the default sink.
* @param[in] userdata User specified data passed along with each invocation
* of callback.
*/
DDS_EXPORT void
dds_set_log_sink(
dds_log_write_fn_t callback,
void *userdata);
/**
* @brief Register callback to receive trace messages
*
* Callbacks registered to handle trace messages will receive messages of type
* info, warning, error and fatal as well as all message types that fall into
* the trace category depending on the log mask.
*
* This operation is synchronous and only returns once the operation is
* registered with all threads. Meaning that neither callback or
* userdata will be referenced by the DDS stack on return.
*
* @param[in] callback Function pointer matching dds_log_write_fn_t signature
* or a null pointer to restore the default sink.
* @param[in] userdata User specified data passed along with each invocation
* of callback.
*/
DDS_EXPORT void
dds_set_trace_sink(
dds_log_write_fn_t callback,
void *userdata);
/**
* @brief Write a log or trace message.
*
* Write a log or trace message to one (or both) of the currently active sinks.
*
* Direct use of #dds_log is discouraged. Use #DDS_INFO, #DDS_WARNING,
* #DDS_ERROR, #DDS_FATAL or #DDS_LOG instead.
*/
DDS_EXPORT int
dds_log(
uint32_t prio,
const char *file,
uint32_t line,
const char *func,
const char *fmt,
...);
/**
* @brief Undecorated function name of the current function.
*
* Behavior of DDS_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 DDS_FUNCTION __func__
#elif defined(__cplusplus) && (__cplusplus >= 201103)
# define DDS_FUNCTION __func__
#elif defined(__GNUC__)
# define DDS_FUNCTION __FUNCTION__
#elif defined(__clang__)
# define DDS_FUNCTION __FUNCTION__
#elif defined(__ghs__)
# define DDS_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 DDS_FUNCTION __func__
#elif defined(__FUNCTION__)
/* Visual Studio */
# define DDS_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 DDS_FUNCTION __FUNCTION__
#else
# warning "DDS_FUNCTION is not supported"
# define DDS_FUNCTION ""
#endif
/**
* @brief Function signature of the current function.
*
* See comments on DDS_FUNCTION for details.
*/
#if defined(__GNUC__)
# define DDS_PRETTY_FUNCTION __PRETTY_FUNCTION__
#elif defined(__clang__)
# define DDS_PRETTY_FUNCTION __PRETTY_FUNCTION__
#elif defined(__ghs__)
# define DDS_PRETTY_FUNCTION __PRETTY_FUNCTION__
#elif (defined(__SUNPRO_C) && __SUNPRO_C >= 0x5100)
/* Solaris Studio supports __PRETTY_FUNCTION__ in C since version 12.1 */
# define DDS_PRETTY_FUNCTION __PRETTY_FUNCTION__
#elif (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5120)
/* Solaris Studio supports __PRETTY_FUNCTION__ in C++ since version 12.3 */
# define DDS_PRETTY_FUNCTION __PRETTY_FUNCTION__
#elif defined(__FUNCSIG__)
/* Visual Studio */
# define DDS_PRETTY_FUNCTION __FUNCSIG__
#elif defined(__vxworks)
/* See comments on __vxworks macro above. */
# define DDS_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
/* Fall back to DDS_FUNCTION. */
# define DDS_PRETTY_FUNCTION DDS_FUNCTION
#endif
/**
* @brief Write a log message.
*
* Write a log or trace message to the currently active log and/or trace sinks
* if the log category is enabled. Whether or not the category is enabled is
* checked before any dds_log-related activities to save a couple of % CPU.
*
* Only messages that fall into one of the log categories are passed onto
* dds_log. While messages that fall into a trace category could have been
* passed just as easily, they are rejected so that tracing is kept entirely
* separate from logging, if only cosmetic.
*/
#define DDS_LOG(cat, ...) \
((dds_get_log_mask() & (cat)) ? \
dds_log(cat, __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0)
/** Write a log message of type #DDS_LC_INFO. */
#define DDS_INFO(...) \
DDS_LOG(DDS_LC_INFO, __VA_ARGS__)
/** Write a log message of type #DDS_LC_WARNING. */
#define DDS_WARNING(...) \
DDS_LOG(DDS_LC_WARNING, __VA_ARGS__)
/** Write a log message of type #DDS_LC_ERROR. */
#define DDS_ERROR(...) \
DDS_LOG(DDS_LC_ERROR, __VA_ARGS__)
/** Write a log message of type #DDS_LC_ERROR and abort. */
#define DDS_FATAL(...) \
dds_log(DDS_LC_FATAL, __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__)
/** Write a #DDS_LC_TRACE message. */
#define DDS_TRACE(...) \
DDS_LOG(DDS_LC_TRACE, __VA_ARGS__)
#if defined (__cplusplus)
}
#endif
#endif /* DDS_LOG_H */

View file

@ -0,0 +1,81 @@
/*
* 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 DDSRT_MISC_H
#define DDSRT_MISC_H
#include <limits.h>
#if defined (__cplusplus)
extern "C" {
#endif
#if defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
# define DDSRT_GNUC_STR(s) #s
# define DDSRT_GNUC_JOINSTR(x,y) DDSRT_GNUC_DIAG_STR(x ## y)
# define DDSRT_GNUC_DO_PRAGMA(x) _Pragma (#x)
# define DDSRT_GNUC_PRAGMA(x) DDSRT_GNUC_DO_PRAGMA(GCC diagnostic x)
# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
# define DDSRT_WARNING_GNUC_OFF(x) \
DDSRT_GNUC_PRAGMA(push) \
DDSRT_GNUC_PRAGMA(ignored DDSRT_GNUC_JOINSTR(-W,x))
# define DDSRT_WARNING_GNUC_ON(x) \
DDSRT_GNUC_PRAGMA(pop)
# else
# define DDSRT_WARNING_GNUC_OFF(x) \
DDSRT_GNUC_PRAGMA(ignored DDSRT_GNUC_JOINSTR(-W,x))
# define DDSRT_WARNING_GNUC_ON(x) \
DDSRT_GNUC_PRAGMA(warning DDSRT_GNUC_JOINSTR(-W,x))
# endif
#else
# define DDSRT_WARNING_GNUC_OFF(x)
# define DDSRT_WARNING_GNUC_ON(x)
#endif
#if defined(_MSC_VER)
# define DDSRT_WARNING_MSVC_OFF(x) \
__pragma (warning(push)) \
__pragma (warning(disable: ## x))
# define DDSRT_WARNING_MSVC_ON(x) \
__pragma (warning(pop))
#else
# define DDSRT_WARNING_MSVC_OFF(x)
# define DDSRT_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 DDSRT_MAX_INTEGER(T) \
((T)(((T)~0) ^ ((T)!((T)~0 > 0) << (CHAR_BIT * sizeof(T) - 1))))
/**
* @brief Calculate minimum value of an integer type
*/
#define DDSRT_MIN_INTEGER(T) \
((-DDSRT_MAX_INTEGER(T)) - 1)
/**
* @brief Macro to disable unused argument warnings
*/
#define DDSRT_UNUSED_ARG(a) (void)(a)
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_MISC_H */

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
*/
#ifndef DDSRT_PROCESS_H
#define DDSRT_PROCESS_H
#include "dds/export.h"
#include "dds/ddsrt/types.h"
#if defined (__cplusplus)
extern "C" {
#endif
#if defined(_WIN32)
typedef DWORD ddsrt_pid_t;
#define PRIdPID "u"
#else /* _WIN32 */
#include <unistd.h>
#if defined(_WRS_KERNEL)
typedef RTP_ID ddsrt_pid_t; /* typedef struct wind_rtp *RTP_ID */
#define PRIdPID PRIuPTR
#else
typedef pid_t ddsrt_pid_t;
#define PRIdPID "d"
#endif
#endif /* _WIN32 */
/**
* @brief Return process ID (PID) of the calling process.
*
* @returns The process ID of the calling process.
*/
DDS_EXPORT ddsrt_pid_t
ddsrt_getpid(void);
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_PROCESS_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 DDSRT_RANDOM_H
#define DDSRT_RANDOM_H
#include "dds/export.h"
#if defined (__cplusplus)
extern "C" {
#endif
DDS_EXPORT long ddsrt_random(void);
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_RANDOM_H */

View file

@ -0,0 +1,89 @@
#ifndef DDS_RETCODE_H
#define DDS_RETCODE_H
#include <stdint.h>
#include "dds/export.h"
typedef int32_t dds_retcode_t;
/*
State is unchanged following a function call returning an error
other than UNSPECIFIED, OUT_OF_RESOURCES and ALREADY_DELETED.
Error handling functions. Three components to returned int status value.
1 - The DDS_ERR_xxx error number
2 - The file identifier
3 - The line number
All functions return >= 0 on success, < 0 on error
*/
/**
* @name DDS_Error_Type
* @{
*/
#define DDS_RETCODE_OK 0 /**< Success */
#define DDS_RETCODE_ERROR 1 /**< Non specific error */
#define DDS_RETCODE_UNSUPPORTED 2 /**< Feature unsupported */
#define DDS_RETCODE_BAD_PARAMETER 3 /**< Bad parameter value */
#define DDS_RETCODE_PRECONDITION_NOT_MET 4 /**< Precondition for operation not met */
#define DDS_RETCODE_OUT_OF_RESOURCES 5 /**< When an operation fails because of a lack of resources */
#define DDS_RETCODE_NOT_ENABLED 6 /**< When a configurable feature is not enabled */
#define DDS_RETCODE_IMMUTABLE_POLICY 7 /**< When an attempt is made to modify an immutable policy */
#define DDS_RETCODE_INCONSISTENT_POLICY 8 /**< When a policy is used with inconsistent values */
#define DDS_RETCODE_ALREADY_DELETED 9 /**< When an attempt is made to delete something more than once */
#define DDS_RETCODE_TIMEOUT 10 /**< When a timeout has occurred */
#define DDS_RETCODE_NO_DATA 11 /**< When expected data is not provided */
#define DDS_RETCODE_ILLEGAL_OPERATION 12 /**< When a function is called when it should not be */
#define DDS_RETCODE_NOT_ALLOWED_BY_SECURITY 13 /**< When credentials are not enough to use the function */
/* Extended return codes are not in the DDS specification and are meant
exclusively for internal use and must not be returned by the C API. */
#define DDS_XRETCODE_BASE (50)
#define DDS_XRETCODE(x) (DDS_XRETCODE_BASE + (x))
/** Requested resource is busy */
#define DDS_RETCODE_IN_PROGRESS DDS_XRETCODE(1)
/** Resource unavailable, try again */
#define DDS_RETCODE_TRY_AGAIN DDS_XRETCODE(2)
/** Operation was interrupted */
#define DDS_RETCODE_INTERRUPTED DDS_XRETCODE(3)
/** Permission denied */
#define DDS_RETCODE_NOT_ALLOWED DDS_XRETCODE(4)
/** Host not found */
#define DDS_RETCODE_HOST_NOT_FOUND DDS_XRETCODE(5)
/** Network is not available */
#define DDS_RETCODE_NO_NETWORK DDS_XRETCODE(6)
/** Connection is not available */
#define DDS_RETCODE_NO_CONNECTION DDS_XRETCODE(7)
/* Host not reachable is used to indicate that a connection was refused
(ECONNREFUSED), reset by peer (ECONNRESET) or that a host or network cannot
be reached (EHOSTUNREACH, ENETUNREACH). Generally all system errors that
indicate a connection cannot be made or that a message cannot be delivered,
map onto host not reachable. */
/** Not enough space available */
#define DDS_RETCODE_NOT_ENOUGH_SPACE DDS_XRETCODE(8)
/* Not enough space is used to indicate there is not enough buffer space to
read a message from the network (i.e. EMSGSIZE), but is also used to
indicate there is not enough space left on a device, etc. */
/** Result too large */
#define DDS_RETCODE_OUT_OF_RANGE DDS_XRETCODE(9)
/** Not found */
#define DDS_RETCODE_NOT_FOUND DDS_XRETCODE(10)
/**
* @}
*/
/**
* @brief Takes the error value and outputs a string corresponding to it.
*
* @param[in] err Error value to be converted to a string
*
* @returns String corresponding to the error value
*/
DDS_EXPORT const char *dds_strretcode(dds_retcode_t ret);
#endif /* DDS_RETCODE_H */

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
*/
#ifndef DDSRT_RUSAGE_H
#define DDSRT_RUSAGE_H
#include <stddef.h>
#include "dds/ddsrt/time.h"
#include "dds/ddsrt/retcode.h"
typedef struct {
dds_time_t utime; /* User CPU time used. */
dds_time_t stime; /* System CPU time used. */
size_t maxrss; /* Maximum resident set size in bytes. */
size_t idrss; /* Integral unshared data size. Not maintained on (at least)
Linux and Windows. */
size_t nvcsw; /* Voluntary context switches. Not maintained on Windows. */
size_t nivcsw; /* Involuntary context switches. Not maintained on Windows. */
} ddsrt_rusage_t;
#define DDSRT_RUSAGE_SELF (0)
#define DDSRT_RUSAGE_THREAD (1)
/**
* @brief Get resource usage for the current thread or process.
*
* @param[in] who DDSRT_RUSAGE_SELF or DDSRT_RUSAGE_THREAD.
* @param[in] usage Structure where resource usage is returned.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Resource usage successfully returned in @usage.
* @retval DDS_RETCODE_OUT_OF_RESOURCES
* There were not enough resources to get resource usage.
* @retval DDS_RETCODE_ERROR
* An unidentified error occurred.
*/
DDS_EXPORT dds_retcode_t ddsrt_getrusage(int who, ddsrt_rusage_t *usage);
#endif /* DDSRT_RUSAGE_H */

View file

@ -0,0 +1,262 @@
#ifndef DDSRT_SOCKETS_H
#define DDSRT_SOCKETS_H
#include <stdbool.h>
#include "dds/export.h"
#include "dds/ddsrt/types.h"
#include "dds/ddsrt/attributes.h"
#include "dds/ddsrt/retcode.h"
#include "dds/ddsrt/time.h"
#if !defined(_WIN32)
#include "dds/ddsrt/sockets/posix.h"
#else
#include "dds/ddsrt/sockets/windows.h"
#endif
#if DDSRT_HAVE_IPV6
#define INET6_ADDRSTRLEN_EXTENDED (INET6_ADDRSTRLEN + 8) /* "[]:12345" */
extern const struct in6_addr ddsrt_in6addr_any;
extern const struct in6_addr ddsrt_in6addr_loopback;
#endif /* DDSRT_HAVE_IPV6 */
#define DDSRT_AF_TERM (-1)
DDS_EXPORT dds_retcode_t
ddsrt_gethostname(
char *hostname,
size_t buffersize);
DDS_EXPORT dds_retcode_t
ddsrt_socket(
ddsrt_socket_t *sockptr,
int domain,
int type,
int protocol);
DDS_EXPORT dds_retcode_t
ddsrt_close(
ddsrt_socket_t sock);
DDS_EXPORT dds_retcode_t
ddsrt_connect(
ddsrt_socket_t sock,
const struct sockaddr *addr,
socklen_t addrlen);
DDS_EXPORT dds_retcode_t
ddsrt_accept(
ddsrt_socket_t sock,
struct sockaddr *addr,
socklen_t *addrlen,
ddsrt_socket_t *connptr);
DDS_EXPORT dds_retcode_t
ddsrt_listen(
ddsrt_socket_t sock,
int backlog);
DDS_EXPORT dds_retcode_t
ddsrt_bind(
ddsrt_socket_t sock,
const struct sockaddr *addr,
socklen_t addrlen);
DDS_EXPORT dds_retcode_t
ddsrt_getsockname(
ddsrt_socket_t sock,
struct sockaddr *addr,
socklen_t *addrlen);
DDS_EXPORT dds_retcode_t
ddsrt_send(
ddsrt_socket_t sock,
const void *buf,
size_t len,
int flags,
ssize_t *sent);
DDS_EXPORT dds_retcode_t
ddsrt_sendmsg(
ddsrt_socket_t sock,
const ddsrt_msghdr_t *msg,
int flags,
ssize_t *sent);
DDS_EXPORT dds_retcode_t
ddsrt_recv(
ddsrt_socket_t sock,
void *buf,
size_t len,
int flags,
ssize_t *rcvd);
DDS_EXPORT dds_retcode_t
ddsrt_recvmsg(
ddsrt_socket_t sock,
ddsrt_msghdr_t *msg,
int flags,
ssize_t *rcvd);
DDS_EXPORT dds_retcode_t
ddsrt_getsockopt(
ddsrt_socket_t sock,
int32_t level, /* SOL_SOCKET */
int32_t optname, /* SO_REUSEADDR, SO_DONTROUTE, SO_BROADCAST, SO_SNDBUF, SO_RCVBUF */
void *optval,
socklen_t *optlen);
DDS_EXPORT dds_retcode_t
ddsrt_setsockopt(
ddsrt_socket_t sock,
int32_t level, /* SOL_SOCKET */
int32_t optname, /* SO_REUSEADDR, SO_DONTROUTE, SO_BROADCAST, SO_SNDBUF, SO_RCVBUF */
const void *optval,
socklen_t optlen);
/**
* @brief Set the I/O on the socket to blocking or non-nonblocking.
*
* @param[in] sock Socket to set I/O mode for.
* @param[in] nonblock true for nonblocking, or false for blocking I/O.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* I/O mode successfully set to (non)blocking.
* @retval DDS_RETCODE_TRY_AGAIN
* A blocking call is in progress.
* @retval DDS_RETCODE_BAD_PARAMETER
* @sock is not a valid socket.
* @retval DDS_RETCODE_ERROR
* An unknown error error occurred.
*/
DDS_EXPORT dds_retcode_t
ddsrt_setsocknonblocking(
ddsrt_socket_t sock,
bool nonblock);
DDS_EXPORT int32_t
ddsrt_select(
int32_t nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *errorfds,
dds_duration_t reltime,
int32_t *ready);
#if _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 ddsrt_select is redefined to discard the
parameter on Windows. */
#define ddsrt_select(nfds, readfds, writefds, errorfds, timeout, ready) \
ddsrt_select(-1, readfds, writefds, errorfds, timeout, ready)
#endif /* _WIN32 */
/**
* @brief Get the size of a socket address.
*
* @param[in] sa Socket address to return the size for.
*
* @returns Size of the socket address based on the address family, or 0 if
* the address family is unknown.
*/
DDS_EXPORT socklen_t
ddsrt_sockaddr_get_size(
const struct sockaddr *const sa) ddsrt_nonnull_all;
/**
* @brief Get the port number from a socket address.
*
* @param[in] sa Socket address to retrieve the port from.
*
* @return Port number in host order.
*/
DDS_EXPORT uint16_t
ddsrt_sockaddr_get_port(
const struct sockaddr *const sa) ddsrt_nonnull_all;
/**
* @brief Check if the given address is unspecified.
*
* @param[in] sa Socket address to check.
*
* @return true if the address is unspecified, false otherwise.
*/
DDS_EXPORT bool
ddsrt_sockaddr_isunspecified(
const struct sockaddr *__restrict sa) ddsrt_nonnull_all;
/**
* @brief Check if the given address is a loopback address.
*
* @param[in] sa Socket address to check.
*
* @return true if the address is a loopback address, false otherwise.
*/
DDS_EXPORT bool
ddsrt_sockaddr_isloopback(
const struct sockaddr *__restrict sa) ddsrt_nonnull_all;
/**
* @brief Check if given socket IP addresses reside in the same subnet.
*
* Checks if two socket IP addresses reside in the same subnet, considering the
* given subnetmask. IPv6 mapped IPv4 addresses are not taken in account.
*
* @param[in] sa1 First address
* @param[in] sa2 Second address.
* @param[in] mask Subnetmask.
*
* @returns true if both addresses reside in the same subnet, false otherwise.
*/
DDS_EXPORT bool
ddsrt_sockaddr_insamesubnet(
const struct sockaddr *sa1,
const struct sockaddr *sa2,
const struct sockaddr *mask)
ddsrt_nonnull_all;
DDS_EXPORT dds_retcode_t
ddsrt_sockaddrfromstr(
int af, const char *str, void *sa);
DDS_EXPORT dds_retcode_t
ddsrt_sockaddrtostr(
const void *sa, char *buf, size_t size);
#if DDSRT_HAVE_DNS
typedef struct {
size_t naddrs;
struct sockaddr_storage addrs[];
} ddsrt_hostent_t;
/**
* @brief Lookup addresses for given host name.
*
* @param[in] name Host name to resolve.
* @param[in] af Address family, either AF_INET, AF_INET6 or AF_UNSPEC.
* @param[out] hent Structure of type ddsrt_hostent_t.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Host name successfully resolved to address(es).
* @retval DDS_RETCODE_HOST_NOT_FOUND
* Host not found.
* @retval DDS_RETCODE_NO_DATA
* Valid name, no data record of requested type.
* @retval DDS_RETCODE_ERROR
* Nonrecoverable error.
* @retval DDS_RETCODE_TRY_AGAIN
* Nonauthoratitative host not found.
*/
DDS_EXPORT dds_retcode_t
ddsrt_gethostbyname(
const char *name,
int af,
ddsrt_hostent_t **hentp);
#endif
#endif /* DDSRT_SOCKETS_H */

View file

@ -0,0 +1,54 @@
/*
* 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 DDSRT_SOCKETS_POSIX_H
#define DDSRT_SOCKETS_POSIX_H
#include <net/if.h>
#include <netinet/in.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#if defined(__cplusplus)
extern "C" {
#endif
typedef int ddsrt_socket_t;
#define DDSRT_INVALID_SOCKET (-1)
#define PRIdSOCK "d"
#define DDSRT_HAVE_IPV6 1
#define DDSRT_HAVE_DNS 1
#define DDSRT_HAVE_SSM 1
typedef struct iovec ddsrt_iovec_t;
typedef size_t ddsrt_iov_len_t;
#if defined(__linux)
typedef size_t ddsrt_msg_iovlen_t;
#else /* POSIX says int (which macOS, FreeBSD, Solaris do) */
typedef int ddsrt_msg_iovlen_t;
#endif
typedef struct msghdr ddsrt_msghdr_t;
#if defined(__sun) && !defined(_XPG4_2)
# define DDSRT_MSGHDR_FLAGS 0
#else
# define DDSRT_MSGHDR_FLAGS 1
#endif
#if defined(__cplusplus)
}
#endif
#endif /* DDSRT_SOCKETS_POSIX_H */

View file

@ -0,0 +1,52 @@
#ifndef DDSRT_WINDOWS_SOCKET_H
#define DDSRT_WINDOWS_SOCKET_H
#include <winsock2.h>
#include <ws2tcpip.h>
#if defined(__cplusplus)
extern "C" {
#endif
typedef SOCKET ddsrt_socket_t;
#define DDSRT_INVALID_SOCKET (INVALID_SOCKET)
#define PRIdSOCK PRIuPTR
#define DDSRT_HAVE_IPV6 1
#define DDSRT_HAVE_DNS 1
#if defined(NTDDI_VERSION) && \
defined(_WIN32_WINNT_WS03) && \
(NTDDI_VERSION >= _WIN32_WINNT_WS03)
#define DDSRT_HAVE_SSM 1
#else
#define DDSRT_HAVE_SSM 0
#endif
#define IFF_POINTOPOINT IFF_POINTTOPOINT
typedef unsigned ddsrt_iov_len_t;
typedef struct ddsrt_iovec {
ddsrt_iov_len_t iov_len;
void *iov_base;
} ddsrt_iovec_t;
typedef DWORD ddsrt_msg_iovlen_t;
typedef struct ddsrt_msghdr {
void *msg_name;
socklen_t msg_namelen;
ddsrt_iovec_t *msg_iov;
ddsrt_msg_iovlen_t msg_iovlen;
void *msg_control;
size_t msg_controllen;
int msg_flags;
} ddsrt_msghdr_t;
#define DDSRT_MSGHDR_FLAGS 1
#if defined(__cplusplus)
}
#endif
#endif /* DDSRT_WINDOWS_SOCKET_H */

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 DDSRT_STRING_H
#define DDSRT_STRING_H
#include "dds/export.h"
#include "dds/ddsrt/attributes.h"
#include "dds/ddsrt/retcode.h"
#if defined (__cplusplus)
extern "C" {
#endif
/**
* @brief Compare two strings ignoring case.
*
* @param[in] s1 String to compare.
* @param[in] s2 String to compare.
*
* @returns Zero if @s1 and @s2 match, a negative integer if @s1 is less than
* @s2 or a positive integer if @s1 is greater than @s2.
*/
DDS_EXPORT int
ddsrt_strcasecmp(
const char *s1,
const char *s2)
ddsrt_nonnull_all;
/**
* @brief Compare two strings ignoring case, but no more than @n bytes.
*
* @param[in] s1 String to compare.
* @param[in] s2 String to compare.
* @param[in] n Maximum number of bytes to compare.
*
* @returns Zero if @s1 and @s2 match, a negative integer if @s1 is less than
* @s2 or a positive integer if @s1 is greater than @s2.
*/
DDS_EXPORT int
ddsrt_strncasecmp(
const char *s1,
const char *s2,
size_t n)
ddsrt_nonnull((1,2));
/**
* @brief Split string into tokens.
*
* @param[in] str String to split into tokens.
* @param[in] delim Characters that delimit a token.
* @param[inout] saveptr Pointer to a char * used internally.
*
* @returns The next token or NULL if there are no more tokens.
*/
DDS_EXPORT char *
ddsrt_strtok_r(
char *str,
const char *delim,
char **saveptr);
/**
* @brief Extract token from string.
*
* Finds the first token in @stringp delimited by one of the characters in
* @delim. The delimiter is overwritten with a null byte, terminating the
* token and @stringp is updated to point past the delimiter.
*
* @param[inout] stringp String to extract token from.
* @param[in] delim Characters that delimit a token.
*
* @returns The original value of @stringp.
*/
DDS_EXPORT char *
ddsrt_strsep(
char **stringp,
const char *delim);
/**
* @brief Duplicate block of memory.
*
* Copy a block of memory into a newly allocated block of memory. The memory
* is obtained with @ddsrt_malloc and must be freed with @ddsrt_free when it
* is no longer used.
*
* @param[in] ptr Pointer to block of memory to duplicate.
* @param[in] len Number of bytes to copy into newly allocated buffer.
*
* @returns A new block of memory that is a duplicate of the block pointed to
* by @ptr or NULL if not enough memory was available.
*/
DDS_EXPORT void *
ddsrt_memdup(
const void *ptr,
size_t len)
ddsrt_nonnull((1))
ddsrt_attribute_malloc;
/**
* @brief Duplicate string.
*
* Copy string into a newly allocated block of memory. The memory is obtained
* with @ddsrt_malloc and must freed with @ddsrt_free when it is no longer
* used.
*
* @param[in] str String to duplicate.
*
* @returns A new string that is a duplicate of @str or NULL if not enough
* memory was available.
*/
DDS_EXPORT char *
ddsrt_strdup(
const char *str)
ddsrt_nonnull_all
ddsrt_attribute_malloc;
/**
* @brief Copy string.
*
* Copy string to buffer with specified size. The string is truncated if there
* is not enough space. The resulting string is guaranteed to be null
* terminated if there is space.
*
* @param[out] dest Destination buffer.
* @param[in] src Null terminated string to copy to dest.
* @param[in] size Number of bytes available in dest.
*
* @returns Number of characters copied to dest (excluding the null byte), or
* the number of characters that would have been copied if dest is not
* sufficiently large enough.
*/
DDS_EXPORT
size_t
ddsrt_strlcpy(
char * __restrict dest,
const char * __restrict src,
size_t size)
ddsrt_nonnull((1,2));
/**
* @brief Concatenate strings.
*
* Append the string specified by src to the string specified by dest. The
* terminating null byte at the end of dest is overwritten. The resulting
* string is truncated if there is not enough space. The resulting string
* guaranteed to be null terminated if there is space.
*
* @param[inout] dest Destination buffer.
* @param[in] src Null terminated string to append to dest.
* @param[in] size Number of bytes available in dest.
*
* @returns Number of characters copied to dest (excluding the null byte), or
* the number of characters that would have been copied if dest is not
* sufficiently large enough.
*/
DDS_EXPORT
size_t
ddsrt_strlcat(
char * __restrict dest,
const char * __restrict src,
size_t size)
ddsrt_nonnull((1,2));
/**
* @brief Get description for specified system error number.
*
* @param[in] errnum System error number.
* @param[in] buf Buffer where description is copied to.
* @param[in] buflen Number of bytes available in @buf.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Description for @errnum was successfully copied to @buf.
* @retval DDS_RETCODE_BAD_PARAMETER
* Unknown error number.
* @retval DDS_RETCODE_NOT_ENOUGH_SPACE
* Buffer was not large enough to hold the description.
*/
DDS_EXPORT dds_retcode_t
ddsrt_strerror_r(
int errnum,
char *buf,
size_t buflen);
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_STRING_H */

View file

@ -0,0 +1,75 @@
/*
* 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 strtod.h
* @brief Floating-point number to/from string conversion functions.
*
* Locale independent versions of the floating-point number conversion
* functions found in the standard library.
*/
#ifndef DDSRT_STRTOD_H
#define DDSRT_STRTOD_H
#include "dds/export.h"
#include "dds/ddsrt/retcode.h"
/**
* @brief Convert a string to a double precision floating point number.
*
* @param[in] nptr A string to convert into a double.
* @param[out] endptr If not NULL, a char* where the address of first invalid
* character is stored.
* @param[out] dblptr A double where the result is stored.
*
* @returns A dds_retcode_t indicating success or failure.
*/
DDS_EXPORT dds_retcode_t
ddsrt_strtod(const char *nptr, char **endptr, double *dblptr);
/**
* @brief Convert a string to a floating point number.
*
* @param[in] nptr A string to convert into a float.
* @param[in] endptr If not NULL, a char* where the address of first invalid
* character is stored.
* @param[out] fltptr A float where the floating-point number is stored.
*
* @returns A dds_retcode_t indicating success or failure.
*/
DDS_EXPORT dds_retcode_t
ddsrt_strtof(const char *nptr, char **endptr, float *fltptr);
/**
* @brief Convert a double-precision floating-point number to a string.
*
* @param[in] src Double-precision floating-point number to convert.
* @param[in] str Buffer where string representation is written.
* @param[in] size Number of bytes available in @str.
*
* @returns The number of bytes written (excluding the null terminating byte).
*/
DDS_EXPORT int
ddsrt_dtostr(double src, char *str, size_t size);
/**
* @brief convert a floating-point number to a string.
*
* @param[in] src Floating-point number to conver.
* @param[in] str Buffer where string representation is written.
* @param[in] size Number of bytes available in @str.
*
* @returns The number of bytes written (exluding the null terminating byte).
*/
DDS_EXPORT int
ddsrt_ftostr(float src, char *str, size_t size);
#endif /* DDSRT_STRTOD_H */

View file

@ -0,0 +1,168 @@
/*
* 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 DDSRT_STRTOL_H
#define DDSRT_STRTOL_H
#include <stdint.h>
#include "dds/export.h"
#include "dds/ddsrt/retcode.h"
#if defined(__cplusplus)
extern "C" {
#endif
/**
* @brief Convert a string to a long long integer.
*
* Translate @str to a long long integer considering base, and sign. If @base
* is 0, base is determined from @str. A prefix of "0x" or "0X" will cause the
* number be read in base 16 (hexadecimal), otherwise base 10 (decimal) is
* used, unless the first character is '0', in which case the number will be
* read in base 8 (octal).
*
* @param[in] str String to convert into a number.
* @param[out] endptr If not NULL, a char* where the address of first invalid
* character is stored.
* @param[in] base Base to use. Must be a base between 2 and 36, or 0 to
* determine from @str.
* @param[out] llng A long long integer where the number is stored.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* String successfully converted to an integer.
* @retval DDS_RETCODE_BAD_PARAMETER
* Base is invalid.
* @retval DDS_RETCODE_OUT_OF_RANGE
* String converted to an integer, but was out of range.
*/
DDS_EXPORT dds_retcode_t
ddsrt_strtoll(
const char *str,
char **endptr,
int32_t base,
long long *llng);
/**
* @brief Convert a string to an unsigned long long integer.
*
* Translate @str to an unsigned long long integer considering base, and sign.
* If @base is 0, base is determined from @str. A prefix of "0x" or "0X" will
* cause the number be read in base 16 (hexadecimal), otherwise base 10
* (decimal) is used, unless the first character is '0', in which case the
* number will be read in base 8 (octal).
*
* @param[in] str String to convert into a number.
* @param[out] endptr If not NULL, a char* where the address of first invalid
* character is stored.
* @param[in] base Base to use. Must be a base between 2 and 36, or 0 to
* determine from @str.
* @param[out] ullng A long long integer where the number is stored.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* String successfully converted to an integer.
* @retval DDS_RETCODE_BAD_PARAMETER
* Base is invalid.
* @retval DDS_RETCODE_OUT_OF_RANGE
* String converted to an integer, but was out of range.
*/
DDS_EXPORT dds_retcode_t
ddsrt_strtoull(
const char *str,
char **endptr,
int32_t base,
unsigned long long *ullng);
/**
* @brief Convert a string to a long long integer.
*
* @param[in] str String to convert into a long long integer.
* @param[in] llng A long long integer where the number is stored.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* String successfully converted to an integer.
* @retval DDS_RETCODE_BAD_PARAMETER
* Base is invalid.
* @retval DDS_RETCODE_OUT_OF_RANGE
* String converted to an integer, but was out of range.
*/
DDS_EXPORT dds_retcode_t
ddsrt_atoll(
const char *str,
long long *llng);
/**
* @brief Convert a string to an unsigned long long integer.
*
* @param[in] str String to conver into an unsigned long long integer.
* @param[out] ullng An unsigned long long integer where the number is stored.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* String successfully converted to an integer.
* @retval DDS_RETCODE_BAD_PARAMETER
* Base is invalid.
* @retval DDS_RETCODE_OUT_OF_RANGE
* String converted to an integer, but was out of range.
*/
DDS_EXPORT dds_retcode_t
ddsrt_atoull(
const char *str,
unsigned long long *ullng);
/**
* @brief Convert a long long integer into a string.
*
* @param[in] num Long long integer to convert into a string.
* @param[in] str Buffer where string representation is written.
* @param[in] len Number of bytes available in buffer.
* @param[out] endptr A char* where the address of the null terminating byte
* is stored.
*
* @returns The value of @str on success, otherwise NULL.
*/
DDS_EXPORT char *
ddsrt_lltostr(
long long num,
char *str,
size_t len,
char **endptr);
/**
* @brief Convert an unsigned long long integer into a string.
*
* @param[in] num Unsigned long long integer to covert into a string.
* @param[in] str Buffer where string representation is stored.
* @param[in] len Number of bytes available in buffer.
* @param[out] endptr A char* where the adress of the null terminating byte
* is stored.
*
* @returns The value of @str on success, otherwise NULL.
*/
DDS_EXPORT char *
ddsrt_ulltostr(
unsigned long long num,
char *str,
size_t len,
char **endptr);
#if defined(__cplusplus)
}
#endif
#endif /* DDSRT_STRTOL_H */

View file

@ -0,0 +1,298 @@
/*
* 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 DDSRT_SYNC_H
#define DDSRT_SYNC_H
#include <stdbool.h>
#include "dds/ddsrt/time.h"
#include "dds/ddsrt/retcode.h"
#include "dds/ddsrt/attributes.h"
#if _WIN32
#include "dds/ddsrt/sync/windows.h"
#else
#include "dds/ddsrt/sync/posix.h"
#endif
#if defined (__cplusplus)
extern "C" {
#endif
/**
* @brief Initialize a mutex.
*
* @param[in] mutex Mutex to itialize.
*/
DDS_EXPORT void
ddsrt_mutex_init(
ddsrt_mutex_t *mutex)
ddsrt_nonnull_all;
/**
* @brief Destroy a mutex.
*
* @param[in] mutex Mutex to destroy.
*/
DDS_EXPORT void
ddsrt_mutex_destroy(
ddsrt_mutex_t *mutex)
ddsrt_nonnull_all;
/**
* @brief Acquire a mutex.
*
* @param[in] mutex Mutex to acquire.
*/
DDS_EXPORT void
ddsrt_mutex_lock(
ddsrt_mutex_t *mutex)
ddsrt_nonnull_all;
/**
* @brief Acquire a mutex if it is not already acquired.
*
* @param[in] mutex Mutex to acquire.
*
* @returns true if the mutex was acquired, false otherwise.
*/
DDS_EXPORT bool
ddsrt_mutex_trylock(
ddsrt_mutex_t *mutex)
ddsrt_nonnull_all
ddsrt_attribute_warn_unused_result;
/**
* @brief Release an acquired mutex.
*
* @param[in] mutex Mutex to release.
*/
DDS_EXPORT void
ddsrt_mutex_unlock (
ddsrt_mutex_t *mutex)
ddsrt_nonnull_all;
/**
* @brief Initialize a condition variable.
*
* @param[in] cond Condition variable to initialize.
*/
DDS_EXPORT void
ddsrt_cond_init(
ddsrt_cond_t *cond)
ddsrt_nonnull_all;
/**
* @brief Destroy a condition variable.
*
* @param[in] cond Condition variable to destroy.
*/
DDS_EXPORT void
ddsrt_cond_destroy(
ddsrt_cond_t *cond)
ddsrt_nonnull_all;
/**
* @brief Wait for a condition variable to be signalled.
*
* @param[in] cond Condition variable to block on.
* @param[in] mutex Mutex to associate with condition variable.
*
* @pre The calling thread must hold the mutex specified by @mutex.
*
* @post The calling thread will hold the mutex specified by @mutex.
*/
DDS_EXPORT void
ddsrt_cond_wait(
ddsrt_cond_t *cond,
ddsrt_mutex_t *mutex)
ddsrt_nonnull_all;
/**
* @brief Wait until @abstime for a condition variable to be signalled.
*
* @param[in] cond Condition variable to block on.
* @param[in] mutex Mutex to associate with condition variable.
* @param[in] abstime Time in nanoseconds since UNIX Epoch.
*
* @pre The calling thread must hold the mutex specified by @mutex.
*
* @post The calling thread will hold the mutex specified by @mutex.
*
* @returns false if the condition variable was not signalled before the
* absolute time specified by @abstime passed, otherwise true.
*/
DDS_EXPORT bool
ddsrt_cond_waituntil(
ddsrt_cond_t *cond,
ddsrt_mutex_t *mutex,
dds_time_t abstime)
ddsrt_nonnull((1,2));
/**
* @brief Wait for @reltime for a condition variable to be signalled.
*
* @param[in] cond Condition variable to block on.
* @param[in] mutex Mutex to associate with condition variable.
* @param[in] reltime Time in nanoseconds since UNIX Epoch.
*
* @pre The calling thread must hold the mutex specified by @mutex.
*
* @post The calling thread will hold the mutex specified by @mutex.
*
* @returns false if the condition variable was not signalled before the
* relative time specified by @reltime passed, otherwise true.
*/
DDS_EXPORT bool
ddsrt_cond_waitfor(
ddsrt_cond_t *cond,
ddsrt_mutex_t *mutex,
dds_duration_t reltime)
ddsrt_nonnull((1,2));
/**
* @brief Signal a condition variable and unblock at least one thread.
*
* @param[in] cond Condition variable to signal.
*
* @pre The mutex associated with the condition in general should be acquired
* by the calling thread before setting the condition state and
* signalling.
*/
DDS_EXPORT void
ddsrt_cond_signal(
ddsrt_cond_t *cond)
ddsrt_nonnull_all;
/**
* @brief Signal a condition variable and unblock all threads.
*
* @param[in] cond Condition variable to signal.
*
* @pre The mutex associated with the condition in general should be acquired
* by the calling thread before setting the condition state and
* signalling
*/
DDS_EXPORT void
ddsrt_cond_broadcast(
ddsrt_cond_t *cond)
ddsrt_nonnull_all;
/**
* @brief Initialize a read-write lock.
*
* @param[in] rwlock Read-write lock to initialize.
*/
DDS_EXPORT void
ddsrt_rwlock_init(
ddsrt_rwlock_t *rwlock)
ddsrt_nonnull_all;
/**
* @brief Destroy a read-write lock.
*
* @param[in] rwlock Read-write lock to destroy.
*/
DDS_EXPORT void
ddsrt_rwlock_destroy(
ddsrt_rwlock_t *rwlock);
/**
* @brief Acquire a read-write lock for reading.
*
* @param[in] rwlock Read-write lock to acquire.
*
* @post Data related to the critical section must not be changed by the
* calling thread.
*/
DDS_EXPORT void
ddsrt_rwlock_read(
ddsrt_rwlock_t *rwlock)
ddsrt_nonnull_all;
/**
* @brief Acquire a read-write lock for writing.
*
* @param[in] rwlock Read-write lock to acquire.
*/
DDS_EXPORT void
ddsrt_rwlock_write(
ddsrt_rwlock_t *rwlock)
ddsrt_nonnull_all;
/**
* @brief Try to acquire a read-write lock for reading.
*
* Try to acquire a read-write lock while for reading, immediately return if
* the lock is already exclusively acquired by another thread.
*
* @param[in] rwlock Read-write lock to aqcuire.
*
* @post Data related to the critical section must not changed by the
* calling thread.
*
* @returns true if the lock was acquired, otherwise false.
*/
DDS_EXPORT bool
ddsrt_rwlock_tryread(
ddsrt_rwlock_t *rwlock)
ddsrt_nonnull_all
ddsrt_attribute_warn_unused_result;
/**
* @brief Try to acquire a read-write lock for writing.
*
* Try to acquire a read-write lock for writing, immediately return if the
* lock is already acquired, either for reading or writing, by another thread.
*
* @param[in] rwlock Read-write lock to acquire.
*
* @returns true if the lock was acquired, otherwise false.
*/
DDS_EXPORT bool
ddsrt_rwlock_trywrite(
ddsrt_rwlock_t *rwlock)
ddsrt_nonnull_all
ddsrt_attribute_warn_unused_result;
/**
* @brief Release a previously acquired read-write lock.
*
* @param[in] rwlock Read-write lock to release.
*/
DDS_EXPORT void
ddsrt_rwlock_unlock(
ddsrt_rwlock_t *rwlock)
ddsrt_nonnull_all;
/* Initialization callback used by ddsrt_once */
typedef void (*ddsrt_once_fn)(void);
/**
* @brief Invoke init_fn exactly once for a given control.
*
* The first thread to call this function with a given control will call the
* function specified by @init_fn with no arguments. All following calls with
* the same control will not call the specified function.
*
* @pre The control parameter is properly initialized with DDSRT_ONCE_INIT.
*/
DDS_EXPORT void
ddsrt_once(
ddsrt_once_t *control,
ddsrt_once_fn init_fn);
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_SYNC_H */

View file

@ -0,0 +1,44 @@
/*
* 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 DDSRT_POSIX_SYNC_H
#define DDSRT_POSIX_SYNC_H
#include <stdint.h>
#include <pthread.h>
#if HAVE_LKST
#include "lkst.h"
#endif
#if defined (__cplusplus)
extern "C" {
#endif
typedef struct {
pthread_cond_t cond;
} ddsrt_cond_t;
typedef struct {
pthread_mutex_t mutex;
} ddsrt_mutex_t;
typedef struct {
pthread_rwlock_t rwlock;
} ddsrt_rwlock_t;
typedef pthread_once_t ddsrt_once_t;
#define DDSRT_ONCE_INIT PTHREAD_ONCE_INIT
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_POSIX_SYNC_H */

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
*/
#ifndef DDSRT_WINDOWS_SYNC_H
#define DDSRT_WINDOWS_SYNC_H
#if defined (__cplusplus)
extern "C" {
#endif
typedef struct {
CONDITION_VARIABLE cond;
} ddsrt_cond_t;
typedef struct {
SRWLOCK lock;
} ddsrt_mutex_t;
typedef struct os_rwlock {
SRWLOCK lock;
int state; /* -1: exclusive, 0: free, 1: shared */
} ddsrt_rwlock_t;
typedef INIT_ONCE ddsrt_once_t;
#define DDSRT_ONCE_INIT INIT_ONCE_STATIC_INIT
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_WINDOWS_SYNC_H */

View file

@ -0,0 +1,262 @@
/*
* 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 threads.h
* @brief Thread management and creation.
*
* Platform independent interface for managing and creating execution threads.
*/
#ifndef DDSRT_THREADS_H
#define DDSRT_THREADS_H
#include <stdbool.h>
#include <stdint.h>
#include "dds/export.h"
#include "dds/ddsrt/attributes.h"
#include "dds/ddsrt/retcode.h"
#if _WIN32
#include "dds/ddsrt/threads/windows.h"
#else
#include "dds/ddsrt/threads/posix.h"
#endif
#if defined (__cplusplus)
extern "C" {
#endif
#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 ddsrt_thread_local __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 ddsrt_thread_local __thread
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
#define ddsrt_thread_local __thread
#else
#error "Thread-local storage is not supported"
#endif
/**
* @brief Definition for a thread routine invoked on thread create.
*/
typedef uint32_t (*ddsrt_thread_routine_t)(void*);
/**
* @brief Thread scheduling classes
* @{
*/
typedef enum {
/** Schedule processes and threads according a platform default.
* DDSRT_SCHED_REALTIME for timesharing platforms and
* DDSRT_SCHED_TIMESHARE for realtime platforms
*/
DDSRT_SCHED_DEFAULT,
/** Schedule processes and threads on realtime basis,
* on most platforms implying:
* - Fixed Priority
* - Preemption
* - Either "First In First Out" or "Round Robin"
*/
DDSRT_SCHED_REALTIME,
/** Schedule processes and threads on timesharing basis,
* on most platforms implying:
* - Dynamic Priority to guarantee fair share
* - Preemption
*/
DDSRT_SCHED_TIMESHARE
} ddsrt_sched_t;
/** @} */
/**
* @brief Definition of the thread attributes
*/
typedef struct {
/** Specifies the scheduling class */
ddsrt_sched_t schedClass;
/** Specifies the thread priority */
int32_t schedPriority;
/** Specifies the thread stack size */
uint32_t stackSize;
} ddsrt_threadattr_t;
/**
* @brief Initialize thread attributes to platform defaults.
*/
DDS_EXPORT void
ddsrt_threadattr_init(
ddsrt_threadattr_t *attr)
ddsrt_nonnull_all;
/**
* @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.
*
* @param[out] thread Location where thread id is stored.
* @param[in] name Name assigned to created thread.
* @param[in] attr Attributes to create thread with.
* @param[in] start_routine Function to execute in created thread.
* @param[in] arg Argument passed to @start_routine.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Thread successfully created.
* @retval DDS_RETCODE_ERROR
* Thread could not be created.
*/
DDS_EXPORT dds_retcode_t
ddsrt_thread_create(
ddsrt_thread_t *thread,
const char *name,
const ddsrt_threadattr_t *attr,
ddsrt_thread_routine_t start_routine,
void *arg)
ddsrt_nonnull((1,2,3,4));
/**
* @brief Retrieve integer representation of the given thread id.
*
* @returns The integer representation of the given thread.
*/
DDS_EXPORT ddsrt_tid_t
ddsrt_gettid(void);
/**
* @brief Return thread ID of the calling thread.
*
* @returns Thread ID of the calling thread.
*/
DDS_EXPORT ddsrt_thread_t
ddsrt_thread_self(void);
/**
* @brief Compare thread identifiers.
*
* @returns true if thread ids match, otherwise false.
*/
DDS_EXPORT bool
ddsrt_thread_equal(ddsrt_thread_t t1, ddsrt_thread_t t2);
/**
* @brief Wait for termination of the specified thread.
*
* If the specified thread is still running, wait for its termination
* else return immediately. In thread_result it returns the exit status
* of the thread. If NULL is passed for @thread_result, no exit status is
* returned, but ddsrt_thread_join still waits for the thread to terminate.
*
* @param[in] thread Id of thread to wait for.
* @param[out] thread_result Location where thread result is stored.
*
* @returns A dds_retcode_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Target thread terminated.
* @retval DDS_RETCODE_ERROR
* An error occurred while waiting for the thread to terminate.
*/
DDS_EXPORT dds_retcode_t
ddsrt_thread_join(
ddsrt_thread_t thread,
uint32_t *thread_result);
/**
* @brief Get name of current thread.
*
* @param[in] name Buffer where the name is copied to.
* @param[in] size Number of bytes available in the buffer.
*
* @returns The number of bytes (excluding the null terminating bytes) that
* are written. If the buffer is not sufficiently large enough, the
* name is truncated and the number of bytes that would have been
* written is returned.
*/
DDS_EXPORT size_t
ddsrt_thread_getname(
char *__restrict name,
size_t size);
/**
* @brief Set name of current thread.
*
* Set name of the current thread to @name. If the name is longer than the
* platform maximum, it is silently truncated.
*
* @param[in] name Name for current thread.
*/
DDS_EXPORT void
ddsrt_thread_setname(
const char *__restrict name);
/**
* @brief Push cleanup handler onto the 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.
*
* @param[in] routine Cleanup handler to push onto the thread cleanup stack.
* @param[in] arg Argument that will be passed to the cleanup handler.
*/
DDS_EXPORT dds_retcode_t
ddsrt_thread_cleanup_push(
void (*routine)(void*),
void *arg);
/**
* @brief Pop cleanup handler from the top of the cleanup stack
*
* Remove routine at the top of the calling thread's cleanup stack and
* optionally invoke it (if execute is non-zero).
*/
DDS_EXPORT dds_retcode_t
ddsrt_thread_cleanup_pop(
int execute);
/**
* @brief Initialize thread internals.
*
* Initialize internals for threads not created with @ddsrt_create_thread. By
* default initialization is done automatically.
*/
DDS_EXPORT void
ddsrt_thread_init(void);
/**
* @brief Free thread resources and execute cleanup handlers.
*
* Platforms that support it, automatically free resources claimed by the
* current thread and call any registered cleanup routines. This function only
* needs to be called on platforms that do not support thread destructors and
* only for threads that were not created with @ddsrt_thread_create.
*/
DDS_EXPORT void
ddsrt_thread_fini(void);
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_THREADS_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 DDSRT_POSIX_THREAD_H
#define DDSRT_POSIX_THREAD_H
#include <pthread.h>
#if defined (__cplusplus)
extern "C" {
#endif
#if defined(__linux)
typedef long int ddsrt_tid_t;
#define PRIdTID "ld"
/* __linux */
#elif defined(__FreeBSD__) && (__FreeBSD_version >= 900031)
/* FreeBSD >= 9.0 */
typedef int ddsrt_tid_t;
#define PRIdTID "d"
/* __FreeBSD__ */
#elif defined(__APPLE__) && !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \
__MAC_OS_X_VERSION_MIN_REQUIRED < 1060)
/* macOS X >= 10.6 */
typedef uint64_t ddsrt_tid_t;
#define PRIdTID PRIu64
/* __APPLE__ */
#elif defined(__VXWORKS__)
/* TODO: Verify taskIdSelf is the right function to use on VxWorks */
typedef TASK_ID ddsrt_tid_t;
# if defined(_WRS_CONFIG_LP64)
# define PRIdPID PRIuPTR /* typedef struct windTcb *TASK_ID */
# else
# define PRIdPID "d" /* typedef int TASK_ID */
# endif
/* __VXWORKS__ */
#else
typedef uintmax_t ddsrt_tid_t;
#define PRIdTID PRIuPTR
#endif
/* Wrapped in a struct to force conformation to abstraction. */
typedef struct {
pthread_t v;
} ddsrt_thread_t;
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_POSIX_THREAD_H */

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 DDSRT_WINDOWS_THREADS_H
#define DDSRT_WINDOWS_THREADS_H
#include "dds/ddsrt/types.h"
#if defined (__cplusplus)
extern "C" {
#endif
typedef struct {
DWORD tid;
HANDLE handle;
} ddsrt_thread_t;
typedef DWORD ddsrt_tid_t;
#define PRIdTID "u"
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_WINDOWS_THREADS_H */

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
* @brief DDS C Time support API
*
* This header file defines the public API of the in the
* CycloneDDS C language binding.
*/
#ifndef DDS_TIME_H
#define DDS_TIME_H
#include <stdint.h>
#include "dds/export.h"
#include "dds/ddsrt/types.h"
#if defined (__cplusplus)
extern "C" {
#endif
/*
Times are represented using a 64-bit signed integer, encoding
nanoseconds since the epoch. Considering the nature of these
systems, one would best use TAI, International Atomic Time, rather
than something UTC, but availability may be limited.
Valid times are non-negative and times up to 2**63-2 can be
represented. 2**63-1 is defined to represent, essentially, "never".
This is good enough for a couple of centuries.
*/
/** Absolute Time definition */
typedef int64_t dds_time_t;
/** Relative Time definition */
typedef int64_t dds_duration_t;
/** @name Macro definition for time units in nanoseconds.
@{**/
#define DDS_NSECS_IN_SEC INT64_C(1000000000)
#define DDS_NSECS_IN_MSEC INT64_C(1000000)
#define DDS_NSECS_IN_USEC INT64_C(1000)
/** @}*/
/** @name Infinite timeout for indicate absolute time */
#define DDS_NEVER ((dds_time_t) INT64_MAX)
/** @name Infinite timeout for relative time */
#define DDS_INFINITY ((dds_duration_t) INT64_MAX)
/** @name Macro definition for time conversion to nanoseconds
@{**/
#define DDS_SECS(n) ((n) * DDS_NSECS_IN_SEC)
#define DDS_MSECS(n) ((n) * DDS_NSECS_IN_MSEC)
#define DDS_USECS(n) ((n) * DDS_NSECS_IN_USEC)
/** @}*/
/**
* @brief Get the current time in nanoseconds since the UNIX Epoch.
*
* @returns Current time.
*/
DDS_EXPORT dds_time_t dds_time(void);
/**
* @brief Suspend execution of calling thread until relative time n elapsed.
*
* Execution is suspended for n nanoseconds. Should the call be interrupted,
* the call is re-entered with the remaining time.
*
* @param[in] reltime Relative time in nanoseconds.
*/
DDS_EXPORT void dds_sleepfor (dds_duration_t reltime);
/**
* @brief Suspend execution of calling thread until absolute time n elapsed.
*
* Execution is suspended until the given absolute time elapsed. Should the
* call be interrupted, it is re-entered with the remaining time.
*
* @param[in] abstime Absolute time in nanoseconds since UNIX Epoch.
*/
DDS_EXPORT void dds_sleepuntil (dds_time_t abstime);
/**
* @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).
*
* @returns Monotonic time if available, otherwise real time.
*/
DDS_EXPORT dds_time_t ddsrt_time_monotonic(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.
*
* @returns Elapsed time if available, otherwise return monotonic time.
*/
DDS_EXPORT dds_time_t ddsrt_time_elapsed(void);
/**
* @brief Convert time into a human readable string in RFC 3339 format.
*
* Converts the calender time into a null-terminated string in RFC 3339 format.
* e.g. "2014-10-24 15:32:27-04:00".
*
* UTC offset is omitted if time-zone information is unknown.
*
* @param[in] abstime Time in nanoseconds since UNIX Epoch.
* @param[in] str String to write human readable timestamp to.
* @param[in] size Number of bytes available in @str.
*
* @returns Number of bytes written (excluding terminating null byte). The
* string is truncated if str is not sufficiently large enough. Thus,
* a return value of size or more means the output was truncated.
*/
#define DDSRT_RFC3339STRLEN (25)
DDS_EXPORT size_t ddsrt_ctime(dds_time_t abstime, char *str, size_t size);
#if defined(__cplusplus)
}
#endif
#endif /* DDSRT_TIME_H */

View file

@ -0,0 +1,30 @@
/*
* 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 DDSRT_TYPES_H
#define DDSRT_TYPES_H
#include <stdbool.h>
#include <stdint.h>
#if _WIN32
# include "dds/ddsrt/types/windows.h"
#elif __VXWORKS__
# include "dds/ddsrt/types/vxworks.h"
#else
# include "dds/ddsrt/types/posix.h"
#endif
#define PRIdSIZE "zd"
#define PRIuSIZE "zu"
#define PRIxSIZE "zx"
#endif /* DDSRT_TYPES_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 DDSRT_TYPES_POSIX_H
#define DDSRT_TYPES_POSIX_H
#include <stdint.h>
#include <inttypes.h>
#include <unistd.h>
#endif /* DDSRT_TYPES_POSIX_H */

View file

@ -0,0 +1,74 @@
/*
* 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 DDSRT_TYPES_VXWORKS_H
#define DDSRT_TYPES_VXWORKS_H
#if defined(_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
/* Not a complete replacement for inttypes.h (yet); No SCN/PRI?LEAST/FAST/etc. */
#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 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 PRIXPTR _PFX_64 "X"
#else /* _WRS_KERNEL */
#include <inttypes.h>
#endif /* _WRS_KERNEL */
#endif /* DDSRT_TYPES_VXWORKS_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 DDSRT_TYPES_WINDOWS_H
#define DDSRT_TYPES_WINDOWS_H
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <VersionHelpers.h>
#include <stdint.h>
#include <inttypes.h>
#include <wchar.h>
typedef SSIZE_T ssize_t;
#endif /* DDSRT_TYPES_WINDOWS_H */

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
*/
#ifndef DDS_VERSION_H
#define DDS_VERSION_H
#define DDS_VERSION "@CycloneDDS_VERSION@"
#define DDS_VERSION_MAJOR @CycloneDDS_VERSION_MAJOR@
#define DDS_VERSION_MINOR @CycloneDDS_VERSION_MINOR@
#define DDS_VERSION_PATCH @CycloneDDS_VERSION_PATCH@
#define DDS_VERSION_TWEAK @CycloneDDS_VERSION_TWEAK@
#define DDS_PROJECT_NAME_NOSPACE_CAPS "@CMAKE_PROJECT_NAME_CAPS@"
#define DDS_PROJECT_NAME_NOSPACE_SMALL "@CMAKE_PROJECT_NAME_SMALL@"
#define DDS_PROJECT_NAME_NOSPACE "@CMAKE_PROJECT_NAME@"
#define DDS_PROJECT_NAME "@CMAKE_PROJECT_NAME@"
#define DDS_HOST_NAME "@CMAKE_HOST_SYSTEM_NAME@"
#define DDS_TARGET_NAME "@CMAKE_SYSTEM_NAME@"
#endif /* DDS_VERSION_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 GETOPT_H
#define GETOPT_H
#include "dds/export.h"
DDS_EXPORT extern int opterr;
DDS_EXPORT extern int optind;
DDS_EXPORT extern int optopt;
DDS_EXPORT extern char *optarg;
DDS_EXPORT int getopt(int argc, char **argv, const char *opts);
#endif /* GETOPT_H */

163
src/ddsrt/src/atomics.c Normal file
View file

@ -0,0 +1,163 @@
/*
* 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 "dds/ddsrt/atomics.h"
/* LD, ST */
extern inline uint32_t ddsrt_atomic_ld32 (const volatile ddsrt_atomic_uint32_t *x);
#if DDSRT_HAVE_ATOMIC64
extern inline uint64_t ddsrt_atomic_ld64 (const volatile ddsrt_atomic_uint64_t *x);
#endif
extern inline uintptr_t ddsrt_atomic_ldptr (const volatile ddsrt_atomic_uintptr_t *x);
extern inline void *ddsrt_atomic_ldvoidp (const volatile ddsrt_atomic_voidp_t *x);
extern inline void ddsrt_atomic_st32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v);
#if DDSRT_HAVE_ATOMIC64
extern inline void ddsrt_atomic_st64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
#endif
extern inline void ddsrt_atomic_stptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v);
extern inline void ddsrt_atomic_stvoidp (volatile ddsrt_atomic_voidp_t *x, void *v);
/* INC */
extern inline void ddsrt_atomic_inc32 (volatile ddsrt_atomic_uint32_t *x);
#if DDSRT_HAVE_ATOMIC64
extern inline void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x);
#endif
extern inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x);
extern inline uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x);
#if DDSRT_HAVE_ATOMIC64
extern inline uint64_t ddsrt_atomic_inc64_nv (volatile ddsrt_atomic_uint64_t *x);
#endif
extern inline uintptr_t ddsrt_atomic_incptr_nv (volatile ddsrt_atomic_uintptr_t *x);
/* DEC */
extern inline void ddsrt_atomic_dec32 (volatile ddsrt_atomic_uint32_t *x);
#if DDSRT_HAVE_ATOMIC64
extern inline void ddsrt_atomic_dec64 (volatile ddsrt_atomic_uint64_t *x);
#endif
extern inline void ddsrt_atomic_decptr (volatile ddsrt_atomic_uintptr_t *x);
extern inline uint32_t ddsrt_atomic_dec32_nv (volatile ddsrt_atomic_uint32_t *x);
#if DDSRT_HAVE_ATOMIC64
extern inline uint64_t ddsrt_atomic_dec64_nv (volatile ddsrt_atomic_uint64_t *x);
#endif
extern inline uintptr_t ddsrt_atomic_decptr_nv (volatile ddsrt_atomic_uintptr_t *x);
extern inline uint32_t ddsrt_atomic_dec32_ov (volatile ddsrt_atomic_uint32_t *x);
#if DDSRT_HAVE_ATOMIC64
extern inline uint64_t ddsrt_atomic_dec64_ov (volatile ddsrt_atomic_uint64_t *x);
#endif
extern inline uintptr_t ddsrt_atomic_decptr_ov (volatile ddsrt_atomic_uintptr_t *x);
/* ADD */
extern inline void ddsrt_atomic_add32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v);
#if DDSRT_HAVE_ATOMIC64
extern inline void ddsrt_atomic_add64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
#endif
extern inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v);
extern inline void ddsrt_atomic_addvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v);
extern inline uint32_t ddsrt_atomic_add32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v);
#if DDSRT_HAVE_ATOMIC64
extern inline uint64_t ddsrt_atomic_add64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
#endif
extern inline uintptr_t ddsrt_atomic_addptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v);
extern inline void *ddsrt_atomic_addvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v);
/* SUB */
extern inline void ddsrt_atomic_sub32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v);
#if DDSRT_HAVE_ATOMIC64
extern inline void ddsrt_atomic_sub64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
#endif
extern inline void ddsrt_atomic_subptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v);
extern inline void ddsrt_atomic_subvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v);
extern inline uint32_t ddsrt_atomic_sub32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v);
#if DDSRT_HAVE_ATOMIC64
extern inline uint64_t ddsrt_atomic_sub64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
#endif
extern inline uintptr_t ddsrt_atomic_subptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v);
extern inline void *ddsrt_atomic_subvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v);
/* AND */
extern inline void ddsrt_atomic_and32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v);
#if DDSRT_HAVE_ATOMIC64
extern inline void ddsrt_atomic_and64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
#endif
extern inline void ddsrt_atomic_andptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v);
extern inline uint32_t ddsrt_atomic_and32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v);
#if DDSRT_HAVE_ATOMIC64
extern inline uint64_t ddsrt_atomic_and64_ov (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
#endif
extern inline uintptr_t ddsrt_atomic_andptr_ov (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v);
extern inline uint32_t ddsrt_atomic_and32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v);
#if DDSRT_HAVE_ATOMIC64
extern inline uint64_t ddsrt_atomic_and64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
#endif
extern inline uintptr_t ddsrt_atomic_andptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v);
/* OR */
extern inline void ddsrt_atomic_or32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v);
#if DDSRT_HAVE_ATOMIC64
extern inline void ddsrt_atomic_or64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
#endif
extern inline void ddsrt_atomic_orptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v);
extern inline uint32_t ddsrt_atomic_or32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v);
#if DDSRT_HAVE_ATOMIC64
extern inline uint64_t ddsrt_atomic_or64_ov (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
#endif
extern inline uintptr_t ddsrt_atomic_orptr_ov (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v);
extern inline uint32_t ddsrt_atomic_or32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v);
#if DDSRT_HAVE_ATOMIC64
extern inline uint64_t ddsrt_atomic_or64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
#endif
extern inline uintptr_t ddsrt_atomic_orptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v);
/* CAS */
extern inline int ddsrt_atomic_cas32 (volatile ddsrt_atomic_uint32_t *x, uint32_t exp, uint32_t des);
#if DDSRT_HAVE_ATOMIC64
extern inline int ddsrt_atomic_cas64 (volatile ddsrt_atomic_uint64_t *x, uint64_t exp, uint64_t des);
#endif
extern inline int ddsrt_atomic_casptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t exp, uintptr_t des);
extern inline int ddsrt_atomic_casvoidp (volatile ddsrt_atomic_voidp_t *x, void *exp, void *des);
#if DDSRT_ATOMIC_LIFO_SUPPORT
extern inline int ddsrt_atomic_casvoidp2 (volatile ddsrt_atomic_uintptr2_t *x, uintptr_t a0, uintptr_t b0, uintptr_t a1, uintptr_t b1);
#endif
/* FENCES */
extern inline void ddsrt_atomic_fence (void);
extern inline void ddsrt_atomic_fence_ldld (void);
extern inline void ddsrt_atomic_fence_acq (void);
extern inline void ddsrt_atomic_fence_rel (void);
#if DDSRT_ATOMIC_LIFO_SUPPORT
void ddsrt_atomic_lifo_init (ddsrt_atomic_lifo_t *head)
{
head->aba_head.s.a = head->aba_head.s.b = 0;
}
void ddsrt_atomic_lifo_push (ddsrt_atomic_lifo_t *head, void *elem, size_t linkoff)
{
uintptr_t a0, b0;
do {
a0 = *((volatile uintptr_t *) &head->aba_head.s.a);
b0 = *((volatile uintptr_t *) &head->aba_head.s.b);
*((volatile uintptr_t *) ((char *) elem + linkoff)) = b0;
} while (!ddsrt_atomic_casvoidp2 (&head->aba_head, a0, b0, a0+1, (uintptr_t)elem));
}
void *ddsrt_atomic_lifo_pop (ddsrt_atomic_lifo_t *head, size_t linkoff) {
uintptr_t a0, b0, b1;
do {
a0 = *((volatile uintptr_t *) &head->aba_head.s.a);
b0 = *((volatile uintptr_t *) &head->aba_head.s.b);
if (b0 == 0) {
return NULL;
}
b1 = (*((volatile uintptr_t *) ((char *) b0 + linkoff)));
} while (!ddsrt_atomic_casvoidp2 (&head->aba_head, a0, b0, a0+1, b1));
return (void *) b0;
}
void ddsrt_atomic_lifo_pushmany (ddsrt_atomic_lifo_t *head, void *first, void *last, size_t linkoff)
{
uintptr_t a0, b0;
do {
a0 = *((volatile uintptr_t *) &head->aba_head.s.a);
b0 = *((volatile uintptr_t *) &head->aba_head.s.b);
*((volatile uintptr_t *) ((char *) last + linkoff)) = b0;
} while (!ddsrt_atomic_casvoidp2 (&head->aba_head, a0, b0, a0+1, (uintptr_t)first));
}
#endif

149
src/ddsrt/src/cdtors.c Normal file
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
*/
#include "dds/ddsrt/atomics.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/time.h"
#if _WIN32
/* Sockets API initialization is only necessary on Microsoft Windows. The
overly correct approach would be to abstract this a little further, but for
now a pragmatic approach will suffice. */
extern void ddsrt_winsock_init(void);
extern void ddsrt_winsock_fini(void);
extern void ddsrt_time_init(void);
extern void ddsrt_time_fini(void);
#endif
#define INIT_STATUS_OK 0x80000000u
static ddsrt_atomic_uint32_t init_status = DDSRT_ATOMIC_UINT32_INIT(0);
static ddsrt_mutex_t init_mutex;
void ddsrt_init (void)
{
uint32_t v;
v = ddsrt_atomic_inc32_nv(&init_status);
retry:
if (v > INIT_STATUS_OK)
return;
else if (v == 1) {
ddsrt_mutex_init(&init_mutex);
#if _WIN32
ddsrt_winsock_init();
ddsrt_time_init();
#endif
ddsrt_atomic_or32(&init_status, INIT_STATUS_OK);
} else {
while (v > 1 && !(v & INIT_STATUS_OK)) {
dds_sleepfor(10000000);
v = ddsrt_atomic_ld32(&init_status);
}
goto retry;
}
}
void ddsrt_fini (void)
{
uint32_t v, nv;
do {
v = ddsrt_atomic_ld32(&init_status);
if (v == (INIT_STATUS_OK | 1)) {
nv = 1;
} else {
nv = v - 1;
}
} while (!ddsrt_atomic_cas32(&init_status, v, nv));
if (nv == 1)
{
ddsrt_mutex_destroy(&init_mutex);
#if _WIN32
ddsrt_winsock_fini();
ddsrt_time_fini();
#endif
ddsrt_atomic_dec32(&init_status);
}
}
ddsrt_mutex_t *ddsrt_get_singleton_mutex(void)
{
return &init_mutex;
}
#ifdef _WIN32
#include "dds/ddsrt/threads.h"
/* Executed before DllMain within the context of the thread. Located here too
avoid removal due to link time optimization. */
void WINAPI
ddsrt_cdtor(
PVOID handle,
DWORD reason,
PVOID reserved)
{
switch (reason) {
case DLL_PROCESS_ATTACH:
ddsrt_init();
/* fall through */
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH: /* Specified when thread exits. */
ddsrt_thread_fini();
break;
case DLL_PROCESS_DETACH: /* Specified when main thread exits. */
ddsrt_thread_fini();
ddsrt_fini();
break;
default:
break;
}
}
/* 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 = ddsrt_cdtor;
#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 = ddsrt_cdtor;
#pragma data_seg()
#endif
#else /* _WIN32 */
void __attribute__((constructor)) ddsrt_ctor(void)
{
ddsrt_init();
}
void __attribute__((destructor)) ddsrt_dtor(void)
{
ddsrt_fini();
}
#endif /* _WIN32 */

View file

@ -0,0 +1,88 @@
/*
* 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 <errno.h>
#include <stdlib.h>
#include <string.h>
#include "dds/ddsrt/environ.h"
#include "dds/ddsrt/retcode.h"
static int
isenvvar(const char *name)
{
return (*name == '\0' || strchr(name, '=') != NULL) == 0;
}
dds_retcode_t
ddsrt_getenv(const char *name, char **value)
{
char *env;
assert(name != NULL);
assert(value != NULL);
if (!isenvvar(name))
return DDS_RETCODE_BAD_PARAMETER;
if ((env = getenv(name)) != NULL) {
*value = env;
return DDS_RETCODE_OK;
}
return DDS_RETCODE_NOT_FOUND;
}
dds_retcode_t
ddsrt_setenv(const char *name, const char *value)
{
assert(name != NULL);
assert(value != NULL);
if (strlen(value) == 0)
return ddsrt_unsetenv(name);
if (!isenvvar(name))
return DDS_RETCODE_BAD_PARAMETER;
if (setenv(name, value, 1) == 0)
return DDS_RETCODE_OK;
switch (errno) {
case EINVAL:
return DDS_RETCODE_BAD_PARAMETER;
case ENOMEM:
return DDS_RETCODE_OUT_OF_RESOURCES;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_unsetenv(const char *name)
{
assert(name != NULL);
if (!isenvvar(name))
return DDS_RETCODE_BAD_PARAMETER;
if (unsetenv(name) == 0)
return DDS_RETCODE_OK;
switch (errno) {
case EINVAL:
return DDS_RETCODE_BAD_PARAMETER;
case ENOMEM:
return DDS_RETCODE_OUT_OF_RESOURCES;
default:
break;
}
return DDS_RETCODE_ERROR;
}

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
*/
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/environ.h"
#include "dds/ddsrt/retcode.h"
static int
isenvvar(const char *name)
{
return (*name == '\0' || strchr(name, '=') != NULL) == 0;
}
DDSRT_WARNING_MSVC_OFF(4996)
dds_retcode_t
ddsrt_getenv(const char *name, char **value)
{
char *env;
assert(name != NULL);
assert(value != NULL);
if (!isenvvar(name))
return DDS_RETCODE_BAD_PARAMETER;
if ((env = getenv(name)) != NULL) {
*value = env;
return DDS_RETCODE_OK;
}
return DDS_RETCODE_NOT_FOUND;
}
DDSRT_WARNING_MSVC_ON(4996)
dds_retcode_t
ddsrt_setenv(const char *name, const char *value)
{
assert(name != NULL);
assert(value != NULL);
if (!isenvvar(name))
return DDS_RETCODE_BAD_PARAMETER;
switch (_putenv_s(name, value)) {
case 0:
return DDS_RETCODE_OK;
case EINVAL:
return DDS_RETCODE_BAD_PARAMETER;
case ENOMEM:
return DDS_RETCODE_OUT_OF_RESOURCES;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_unsetenv(const char *name)
{
assert(name != NULL);
return ddsrt_setenv(name, "");
}

83
src/ddsrt/src/getopt.c Normal file
View file

@ -0,0 +1,83 @@
#include <stdio.h>
#include <string.h>
#include <getopt.h>
/* ::[[ @(#) getopt.c 1.5 89/03/11 05:40:23 ]]:: */
#ifndef LINT
static const char Id[] = "$Id: os_stdlib_getopt.c,v 1.2 2008-11-17 09:53:45 hansv Exp $";
#endif
/*
* Here's something you've all been waiting for: the AT&T public domain
* source for getopt(3). It is the code which was given out at the 1985
* UNIFORUM conference in Dallas. I obtained it by electronic mail
* directly from AT&T. The people there assure me that it is indeed
* in the public domain.
*
* There is no manual page. That is because the one they gave out at
* UNIFORUM was slightly different from the current System V Release 2
* manual page. The difference apparently involved a note about the
* famous rules 5 and 6, recommending using white space between an option
* and its first argument, and not grouping options that have arguments.
* Getopt itself is currently lenient about both of these things White
* space is allowed, but not mandatory, and the last option in a group can
* have an argument. That particular version of the man page evidently
* has no official existence, and my source at AT&T did not send a copy.
* The current SVR2 man page reflects the actual behavor of this getopt.
* However, I am not about to post a copy of anything licensed by AT&T.
*/
#define ERR(szz,czz) if(opterr){fprintf(stderr,"%s%s%c\n",argv[0],szz,czz);}
int opterr = 1;
int optind = 1;
int optopt;
char *optarg;
int
getopt(
int argc,
char **argv,
const char *opts)
{
static int sp = 1;
register int c;
register char *cp;
if (sp == 1) {
if (optind >= argc ||
argv[optind][0] != '-' || argv[optind][1] == '\0')
return (EOF);
else if (strcmp(argv[optind], "--") == 0) {
optind++;
return (EOF);
}
}
optopt = c = argv[optind][sp];
if (c == ':' || (cp = strchr(opts, c)) == NULL) {
ERR(": illegal option -- ", c);
if (argv[optind][++sp] == '\0') {
optind++;
sp = 1;
}
return ('?');
}
if (*++cp == ':') {
if (argv[optind][sp + 1] != '\0')
optarg = &argv[optind++][sp + 1];
else if (++optind >= argc) {
ERR(": option requires an argument -- ", c);
sp = 1;
return ('?');
} else
optarg = argv[optind++];
sp = 1;
} else {
if (argv[optind][++sp] == '\0') {
sp = 1;
optind++;
}
optarg = NULL;
}
return (c);
}

View file

@ -0,0 +1,91 @@
/*
* 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 <stdlib.h>
#include "dds/ddsrt/attributes.h"
#include "dds/ddsrt/heap.h"
void *
ddsrt_malloc_s(size_t size)
{
return malloc(size ? size : 1); /* Allocate memory even if size == 0 */
}
void *
ddsrt_malloc(size_t size)
{
void *ptr = ddsrt_malloc_s(size);
if (ptr == NULL) {
/* Heap exhausted */
abort();
}
return ptr;
}
void *
ddsrt_calloc(size_t count, size_t size)
{
char *ptr;
ptr = ddsrt_calloc_s(count, size);
if (ptr == NULL) {
/* Heap exhausted */
abort();
}
return ptr;
}
void *
ddsrt_calloc_s(size_t count, size_t size)
{
if (count == 0 || size == 0) {
count = size = 1;
}
return calloc(count, size);
}
void *
ddsrt_realloc(void *memblk, size_t size)
{
void *ptr;
ptr = ddsrt_realloc_s(memblk, size);
if (ptr == NULL){
/* Heap exhausted */
abort();
}
return ptr;
}
void *
ddsrt_realloc_s(void *memblk, 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 ddsrt_realloc_s always needs to be free'd, like
ddsrt_malloc_s(0). */
return realloc(memblk, size ? size : 1);
}
void
ddsrt_free(void *ptr)
{
if (ptr) {
free (ptr);
}
}

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 *
ddsrt_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 *ddsrt_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 (ddsrt_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
ddsrt_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 */

30
src/ddsrt/src/ifaddrs.c Normal file
View file

@ -0,0 +1,30 @@
/*
* 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 "dds/ddsrt/heap.h"
#include "dds/ddsrt/ifaddrs.h"
void
ddsrt_freeifaddrs(ddsrt_ifaddrs_t *ifa)
{
ddsrt_ifaddrs_t *next;
while (ifa != NULL) {
next = ifa->next;
ddsrt_free(ifa->name);
ddsrt_free(ifa->addr);
ddsrt_free(ifa->netmask);
ddsrt_free(ifa->broadaddr);
ddsrt_free(ifa);
ifa = next;
}
}

View file

@ -0,0 +1,135 @@
/*
* 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 <errno.h>
#include <ifaddrs.h>
#include <string.h>
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/ifaddrs.h"
#include "dds/ddsrt/retcode.h"
#include "dds/ddsrt/string.h"
extern const int *const os_supp_afs;
static dds_retcode_t
copyaddr(ddsrt_ifaddrs_t **ifap, const struct ifaddrs *sys_ifa)
{
dds_retcode_t err = DDS_RETCODE_OK;
ddsrt_ifaddrs_t *ifa;
size_t sz;
assert(ifap != NULL);
assert(sys_ifa != NULL);
sz = ddsrt_sockaddr_get_size(sys_ifa->ifa_addr);
ifa = ddsrt_calloc_s(1, sizeof(*ifa));
if (ifa == NULL) {
err = DDS_RETCODE_OUT_OF_RESOURCES;
} else {
ifa->index = if_nametoindex(sys_ifa->ifa_name);
ifa->flags = sys_ifa->ifa_flags;
if ((ifa->name = ddsrt_strdup(sys_ifa->ifa_name)) == NULL ||
(ifa->addr = ddsrt_memdup(sys_ifa->ifa_addr, sz)) == NULL ||
(sys_ifa->ifa_netmask != NULL &&
(ifa->netmask = ddsrt_memdup(sys_ifa->ifa_netmask, sz)) == NULL) ||
(sys_ifa->ifa_broadaddr != NULL &&
(sys_ifa->ifa_flags & IFF_BROADCAST) &&
(ifa->broadaddr = ddsrt_memdup(sys_ifa->ifa_broadaddr, sz)) == NULL))
{
err = DDS_RETCODE_OUT_OF_RESOURCES;
}
/* Seen on macOS using OpenVPN: netmask without an address family,
in which case copy it from the interface address */
if (ifa->addr && ifa->netmask && ifa->netmask->sa_family == 0) {
ifa->netmask->sa_family = ifa->addr->sa_family;
}
}
if (err == 0) {
*ifap = ifa;
} else {
ddsrt_freeifaddrs(ifa);
}
return err;
}
dds_retcode_t
ddsrt_getifaddrs(
ddsrt_ifaddrs_t **ifap,
const int *afs)
{
dds_retcode_t err = DDS_RETCODE_OK;
int use;
ddsrt_ifaddrs_t *ifa, *ifa_root, *ifa_next;
struct ifaddrs *sys_ifa, *sys_ifa_root;
struct sockaddr *sa;
assert(ifap != NULL);
if (afs == NULL) {
afs = os_supp_afs;
}
if (getifaddrs(&sys_ifa_root) == -1) {
switch (errno) {
case EACCES:
err = DDS_RETCODE_NOT_ALLOWED;
break;
case ENOMEM:
case ENOBUFS:
err = DDS_RETCODE_OUT_OF_RESOURCES;
break;
default:
err = DDS_RETCODE_ERROR;
break;
}
} else {
ifa = ifa_root = NULL;
for (sys_ifa = sys_ifa_root;
sys_ifa != NULL && err == 0;
sys_ifa = sys_ifa->ifa_next)
{
sa = sys_ifa->ifa_addr;
if (sa != NULL) {
use = 0;
for (int i = 0; !use && afs[i] != DDSRT_AF_TERM; i++) {
use = (sa->sa_family == afs[i]);
}
if (use) {
err = copyaddr(&ifa_next, sys_ifa);
if (err == DDS_RETCODE_OK) {
if (ifa == NULL) {
ifa = ifa_root = ifa_next;
} else {
ifa->next = ifa_next;
ifa = ifa_next;
}
}
}
}
}
freeifaddrs(sys_ifa_root);
if (err == 0) {
*ifap = ifa_root;
} else {
ddsrt_freeifaddrs(ifa_root);
}
}
return err;
}

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 <errno.h>
#include "dds/ddsrt/sockets.h"
#include <iphlpapi.h>
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/ifaddrs.h"
#include "dds/ddsrt/io.h"
#include "dds/ddsrt/string.h"
extern const int *const os_supp_afs;
static dds_retcode_t
getifaces(PIP_ADAPTER_ADDRESSES *ptr)
{
dds_retcode_t err = DDS_RETCODE_NOT_ENOUGH_SPACE;
PIP_ADAPTER_ADDRESSES buf = NULL;
ULONG bufsz = 0; /* Size is determined on first iteration. */
ULONG ret;
size_t i;
static const size_t max = 2;
static const ULONG filter = GAA_FLAG_INCLUDE_PREFIX |
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER;
assert(ptr != NULL);
for (i = 0; err == DDS_RETCODE_NOT_ENOUGH_SPACE && i < max; i++) {
ret = GetAdaptersAddresses(AF_UNSPEC, filter, NULL, buf, &bufsz);
assert(ret != ERROR_INVALID_PARAMETER);
switch (ret) {
case ERROR_BUFFER_OVERFLOW:
err = DDS_RETCODE_NOT_ENOUGH_SPACE;
ddsrt_free(buf);
if ((buf = (IP_ADAPTER_ADDRESSES *)ddsrt_malloc(bufsz)) == NULL) {
err = DDS_RETCODE_OUT_OF_RESOURCES;
}
break;
case ERROR_NOT_ENOUGH_MEMORY:
err = DDS_RETCODE_OUT_OF_RESOURCES;
break;
case ERROR_SUCCESS:
case ERROR_ADDRESS_NOT_ASSOCIATED: /* No address associated yet. */
case ERROR_NO_DATA: /* No adapters that match the filter. */
default:
err = DDS_RETCODE_OK;
break;
}
}
if (err == DDS_RETCODE_OK) {
*ptr = buf;
} else {
ddsrt_free(buf);
}
return err;
}
static dds_retcode_t
getaddrtable(PMIB_IPADDRTABLE *ptr)
{
dds_retcode_t err = DDS_RETCODE_NOT_ENOUGH_SPACE;
PMIB_IPADDRTABLE buf = NULL;
ULONG bufsz = 0;
DWORD ret;
size_t i;
static const size_t max = 2;
assert(ptr != NULL);
for (i = 0; err == DDS_RETCODE_NOT_ENOUGH_SPACE && i < max; i++) {
ret = GetIpAddrTable(buf, &bufsz, 0);
assert(ret != ERROR_INVALID_PARAMETER &&
ret != ERROR_NOT_SUPPORTED);
switch (ret) {
case ERROR_INSUFFICIENT_BUFFER:
err = DDS_RETCODE_NOT_ENOUGH_SPACE;
ddsrt_free(buf);
if ((buf = (PMIB_IPADDRTABLE)ddsrt_malloc(bufsz)) == NULL) {
err = DDS_RETCODE_OUT_OF_RESOURCES;
}
break;
case NO_ERROR:
err = DDS_RETCODE_OK;
break;
default:
err = DDS_RETCODE_ERROR;
break;
}
}
if (err == 0) {
*ptr = buf;
} else {
ddsrt_free(buf);
}
return err;
}
static uint32_t
getflags(const PIP_ADAPTER_ADDRESSES iface)
{
uint32_t flags = 0;
if (iface->OperStatus == IfOperStatusUp) {
flags |= IFF_UP;
}
if (!(iface->Flags & IP_ADAPTER_NO_MULTICAST) &&
(iface->IfType != IF_TYPE_SOFTWARE_LOOPBACK))
{
/* multicast over loopback doesn't seem to work despite the NO_MULTICAST
flag being clear assuming an interface is multicast-capable when in fact
it isn't is disastrous, so it makes more sense to err by assuming it
won't work as there is always the AssumeMulticastCapable setting to
overrule it */
flags |= IFF_MULTICAST;
}
switch (iface->IfType) {
case IF_TYPE_SOFTWARE_LOOPBACK:
flags |= IFF_LOOPBACK;
break;
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 int
copyaddr(
ddsrt_ifaddrs_t **ifap,
const PIP_ADAPTER_ADDRESSES iface,
const PMIB_IPADDRTABLE addrtable,
const PIP_ADAPTER_UNICAST_ADDRESS addr)
{
dds_retcode_t err = DDS_RETCODE_OK;
ddsrt_ifaddrs_t *ifa;
struct sockaddr *sa;
size_t sz;
assert(iface != NULL);
assert(addrtable != NULL);
assert(addr != NULL);
sa = (struct sockaddr *)addr->Address.lpSockaddr;
sz = (size_t)addr->Address.iSockaddrLength;
if ((ifa = ddsrt_calloc_s(1, sizeof(*ifa))) == NULL) {
err = DDS_RETCODE_OUT_OF_RESOURCES;
} else {
ifa->flags = getflags(iface);
ifa->addr = ddsrt_memdup(sa, sz);
(void)ddsrt_asprintf(&ifa->name, "%wS", iface->FriendlyName);
if (ifa->addr == NULL || ifa->name == NULL) {
err = DDS_RETCODE_OUT_OF_RESOURCES;
} else if (ifa->addr->sa_family == AF_INET6) {
ifa->index = iface->Ipv6IfIndex;
/* Address is not in addrtable if the interface is not connected. */
} else if (ifa->addr->sa_family == AF_INET && (ifa->flags & IFF_UP)) {
DWORD i = 0;
struct sockaddr_in nm, bc, *sin = (struct sockaddr_in *)sa;
assert(sz == sizeof(nm));
memset(&nm, 0, sz);
memset(&bc, 0, sz);
nm.sin_family = bc.sin_family = AF_INET;
for (; i < addrtable->dwNumEntries; i++) {
if (sin->sin_addr.s_addr == addrtable->table[i].dwAddr) {
ifa->index = addrtable->table[i].dwIndex;
nm.sin_addr.s_addr = addrtable->table[i].dwMask;
bc.sin_addr.s_addr = sin->sin_addr.s_addr | ~(nm.sin_addr.s_addr);
break;
}
}
assert(i < addrtable->dwNumEntries);
if ((ifa->netmask = ddsrt_memdup(&nm, sz)) == NULL ||
(ifa->broadaddr = ddsrt_memdup(&bc, sz)) == NULL)
{
err = DDS_RETCODE_OUT_OF_RESOURCES;
}
}
}
if (err == 0) {
*ifap = ifa;
} else {
ddsrt_freeifaddrs(ifa);
}
return err;
}
dds_retcode_t
ddsrt_getifaddrs(
ddsrt_ifaddrs_t **ifap,
const int *afs)
{
int err = 0;
int use;
PIP_ADAPTER_ADDRESSES ifaces = NULL, iface;
PIP_ADAPTER_UNICAST_ADDRESS addr = NULL;
PMIB_IPADDRTABLE addrtable = NULL;
ddsrt_ifaddrs_t *ifa, *ifa_root, *ifa_next;
struct sockaddr *sa;
assert(ifap != NULL);
if (afs == NULL) {
afs = os_supp_afs;
}
ifa = ifa_root = ifa_next = NULL;
if ((err = getifaces(&ifaces)) == DDS_RETCODE_OK &&
(err = getaddrtable(&addrtable)) == DDS_RETCODE_OK)
{
for (iface = ifaces; !err && iface != NULL; iface = iface->Next) {
for (addr = iface->FirstUnicastAddress;
addr != NULL;
addr = addr->Next)
{
sa = (struct sockaddr *)addr->Address.lpSockaddr;
use = 0;
for (int i = 0; !use && afs[i] != DDSRT_AF_TERM; i++) {
use = (afs[i] == sa->sa_family);
}
if (use) {
err = copyaddr(&ifa_next, iface, addrtable, addr);
if (err == DDS_RETCODE_OK) {
if (ifa == NULL) {
ifa = ifa_root = ifa_next;
} else {
ifa->next = ifa_next;
ifa = ifa_next;
}
}
}
}
}
}
ddsrt_free(ifaces);
ddsrt_free(addrtable);
if (err == DDS_RETCODE_OK) {
*ifap = ifa_root;
} else {
ddsrt_freeifaddrs(ifa_root);
}
return err;
}

72
src/ddsrt/src/io.c Normal file
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
*/
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/io.h"
int
ddsrt_asprintf(
char **strp,
const char *fmt,
...)
{
int ret;
unsigned int len;
char buf[1] = { '\0' };
char *str = NULL;
va_list args1, args2;
assert(strp != NULL);
assert(fmt != NULL);
va_start(args1, fmt);
va_copy(args2, args1); /* va_list cannot be reused */
if ((ret = vsnprintf(buf, sizeof(buf), fmt, args1)) >= 0) {
len = (unsigned int)ret; /* +1 for null byte */
if ((str = ddsrt_malloc(len + 1)) == NULL) {
ret = -1;
} else if ((ret = vsnprintf(str, len + 1, fmt, args2)) >= 0) {
assert(((unsigned int)ret) == len);
*strp = str;
} else {
ddsrt_free(str);
}
}
va_end(args1);
va_end(args2);
return ret;
}
#if defined(_MSC_VER) && (_MSC_VER < 1900)
int
snprintf(
char *str,
size_t size,
const char *fmt,
...)
{
int cnt;
va_list args;
va_start(args, fmt);
cnt = vsnprintf(str, size, fmt, args);
va_end(args);
return cnt;
}
#endif

302
src/ddsrt/src/log.c Normal file
View file

@ -0,0 +1,302 @@
/*
* 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 <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/threads.h"
#define MAX_TIMESTAMP_LEN (10 + 1 + 6)
#define MAX_TID_LEN (10)
#define HDR_LEN (MAX_TIMESTAMP_LEN + 1 + MAX_TID_LEN + 2)
#define BUF_OFFSET HDR_LEN
typedef struct {
char buf[2048];
size_t pos;
} log_buffer_t;
typedef struct {
dds_log_write_fn_t funcs[2];
void *ptr;
FILE *out;
} log_sink_t;
static ddsrt_thread_local log_buffer_t log_buffer;
static ddsrt_once_t lock_inited = DDSRT_ONCE_INIT;
static ddsrt_rwlock_t lock;
static uint32_t log_mask = DDS_LC_ERROR | DDS_LC_WARNING;
static void default_sink(void *ptr, const dds_log_data_t *data)
{
fwrite(data->message - HDR_LEN, 1, HDR_LEN + data->size + 1, (FILE *)ptr);
fflush((FILE *)ptr);
}
static void nop_sink(void *ptr, const dds_log_data_t *data)
{
(void)ptr;
(void)data;
return;
}
#define LOG (0)
#define TRACE (1)
#define USE (0)
#define SET (1)
static log_sink_t sinks[] = {
/* Log */
{ .funcs = { default_sink, default_sink }, .ptr = NULL, .out = NULL },
/* Trace */
{ .funcs = { nop_sink, default_sink }, .ptr = NULL, .out = NULL }
};
uint32_t *const dds_log_mask = &log_mask;
#define RDLOCK (1)
#define WRLOCK (2)
static void init_lock(void)
{
ddsrt_rwlock_init(&lock);
sinks[LOG].ptr = sinks[TRACE].ptr = stderr;
sinks[LOG].out = sinks[TRACE].out = stderr;
}
static void lock_sink(int type)
{
assert(type == RDLOCK || type == WRLOCK);
ddsrt_once(&lock_inited, &init_lock);
if (type == RDLOCK) {
ddsrt_rwlock_read(&lock);
} else {
ddsrt_rwlock_write(&lock);
}
}
static void unlock_sink(void)
{
ddsrt_rwlock_unlock(&lock);
}
static void set_active_log_sinks(void)
{
if (dds_get_log_mask() & DDS_LOG_MASK) {
sinks[LOG].funcs[USE] = sinks[LOG].funcs[SET];
} else {
sinks[LOG].funcs[USE] = nop_sink;
}
if (dds_get_log_mask() & DDS_TRACE_MASK) {
sinks[TRACE].funcs[USE] = sinks[TRACE].funcs[SET];
} else {
sinks[TRACE].funcs[USE] = nop_sink;
}
if (sinks[LOG].funcs[USE] == sinks[TRACE].funcs[USE] &&
sinks[LOG].ptr == sinks[TRACE].ptr)
{
sinks[LOG].funcs[USE] = nop_sink;
}
}
static void
set_log_sink(
log_sink_t *sink,
dds_log_write_fn_t func,
void *ptr)
{
assert(sink != NULL);
/* No life cycle management is done for log sinks, the caller is
responsible for that. Ensure this operation is deterministic and that on
return, no thread in the DDS stack still uses the deprecated sink. */
lock_sink(WRLOCK);
if (func == 0) {
sink->funcs[SET] = default_sink;
sink->ptr = sink->out;
} else {
sink->funcs[SET] = func;
sink->ptr = ptr;
}
set_active_log_sinks();
unlock_sink();
}
/* dds_set_log_file must be considered private. */
void dds_set_log_file(FILE *file)
{
lock_sink(WRLOCK);
sinks[LOG].out = (file == NULL ? stderr : file);
if (sinks[LOG].funcs[SET] == default_sink) {
sinks[LOG].ptr = sinks[LOG].out;
}
set_active_log_sinks();
unlock_sink();
}
void dds_set_trace_file(FILE *file)
{
lock_sink(WRLOCK);
sinks[TRACE].out = (file == NULL ? stderr : file);
if (sinks[TRACE].funcs[SET] == default_sink) {
sinks[TRACE].ptr = sinks[TRACE].out;
}
set_active_log_sinks();
unlock_sink();
}
void dds_set_log_sink(
dds_log_write_fn_t callback,
void *userdata)
{
set_log_sink(&sinks[LOG], callback, userdata);
}
void dds_set_trace_sink(
dds_log_write_fn_t callback,
void *userdata)
{
set_log_sink(&sinks[TRACE], callback, userdata);
}
extern inline uint32_t
dds_get_log_mask(void);
void
dds_set_log_mask(uint32_t cats)
{
lock_sink(WRLOCK);
*dds_log_mask = (cats & (DDS_LOG_MASK | DDS_TRACE_MASK));
set_active_log_sinks();
unlock_sink();
}
static void print_header(char *str)
{
int cnt;
char *tid, buf[MAX_TID_LEN+1] = { 0 };
static const char fmt[] = "%10u.%06d/%*.*s:";
dds_time_t time;
unsigned sec;
int usec;
(void)ddsrt_thread_getname(buf, sizeof(buf));
tid = (buf[0] == '\0' ? "(anon)" : buf);
time = dds_time();
sec = (unsigned)(time / DDS_NSECS_IN_SEC);
usec = (int)((time % DDS_NSECS_IN_SEC) / DDS_NSECS_IN_USEC);
cnt = snprintf(
str, HDR_LEN, fmt, sec, usec, MAX_TID_LEN, MAX_TID_LEN, tid);
assert(cnt == (HDR_LEN - 1));
str[cnt] = ' '; /* Replace snprintf null byte by space. */
}
static void vlog(
uint32_t cat,
const char *file,
uint32_t line,
const char *func,
const char *fmt,
va_list ap)
{
int n, trunc = 0;
size_t nrem;
log_buffer_t *lb;
dds_log_data_t data;
if (*fmt == 0) {
return;
}
lock_sink(RDLOCK);
lb = &log_buffer;
/* Thread-local buffer is always initialized with all zeroes. The pos
member must always be greater or equal to BUF_OFFSET. */
if (lb->pos < BUF_OFFSET) {
lb->pos = BUF_OFFSET;
lb->buf[lb->pos] = 0;
}
nrem = sizeof (lb->buf) - lb->pos;
if (nrem > 0) {
n = vsnprintf(lb->buf + lb->pos, nrem, fmt, ap);
if (n >= 0 && (size_t) n < nrem) {
lb->pos += (size_t) n;
} else {
lb->pos += nrem;
trunc = 1;
}
if (trunc) {
static const char msg[] = "(trunc)\n";
const size_t msglen = sizeof (msg) - 1;
assert(lb->pos <= sizeof (lb->buf));
assert(lb->pos >= msglen);
memcpy(lb->buf + lb->pos - msglen, msg, msglen);
}
}
if (fmt[strlen (fmt) - 1] == '\n') {
print_header(lb->buf);
data.priority = cat;
data.file = file;
data.function = func;
data.line = line;
data.message = lb->buf + BUF_OFFSET;
data.size = strlen(data.message) - 1;
for (size_t i = (cat & DDS_LOG_MASK) ? LOG : TRACE;
i < sizeof(sinks) / sizeof(sinks[0]);
i++)
{
sinks[i].funcs[USE](sinks[i].ptr, &data);
}
lb->pos = BUF_OFFSET;
lb->buf[lb->pos] = 0;
}
unlock_sink();
}
int
dds_log(
uint32_t cat,
const char *file,
uint32_t line,
const char *func,
const char *fmt,
...)
{
if ((dds_get_log_mask() & cat) || (cat & DDS_LC_FATAL)) {
va_list ap;
va_start(ap, fmt);
vlog(cat, file, line, func, fmt, ap);
va_end(ap);
}
if (cat & DDS_LC_FATAL) {
abort();
}
return 0;
}

27
src/ddsrt/src/process.c Normal file
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
*/
#include "dds/ddsrt/process.h"
#if !defined(_WIN32)
# include <unistd.h>
#endif
ddsrt_pid_t
ddsrt_getpid(void)
{
#if defined(_WIN32)
return GetCurrentProcessId();
#else
/* Mapped to taskIdSelf() in VxWorks kernel mode. */
return getpid();
#endif
}

44
src/ddsrt/src/random.c Normal file
View file

@ -0,0 +1,44 @@
/*
* 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 <stdlib.h>
#include "dds/ddsrt/random.h"
#if _WIN32
#define _CRT_RAND_S
#include <errno.h>
long random (void)
{
/* rand() is a really terribly bad PRNG */
/* FIXME: Indeed (especially if not seeded), use rand_s instead. */
union { long x; unsigned char c[4]; } t;
int i;
for (i = 0; i < 4; i++)
t.c[i] = (unsigned char) ((rand () >> 4) & 0xff);
#if RAND_MAX == INT32_MAX || RAND_MAX == 0x7fff
t.x &= RAND_MAX;
#elif RAND_MAX <= 0x7ffffffe
t.x %= (RAND_MAX+1);
#else
#error "RAND_MAX out of range"
#endif
return t.x;
}
#endif
long ddsrt_random(void)
{
/* FIXME: Not MT-safe, should use random_r (or a real PRNG) instead. */
return random();
}

60
src/ddsrt/src/retcode.c Normal file
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
*/
#include "dds/ddsrt/retcode.h"
static const char *retcodes[] =
{
"Success",
"Error",
"Unsupported",
"Bad Parameter",
"Precondition Not Met",
"Out Of Resources",
"Not Enabled",
"Immutable Policy",
"Inconsistent Policy",
"Already Deleted",
"Timeout",
"No Data",
"Illegal Operation",
"Not Allowed By Security"
};
static const char *xretcodes[] = {
"Operation in progress",
"Try again",
"Interrupted",
"Not allowed",
"Host not found",
"Network not available",
"Connection not available",
"No space left",
"Result too large",
"Not found"
};
const char *
dds_strretcode (dds_retcode_t rc)
{
if (rc >= 0 &&
rc < (dds_retcode_t)(sizeof(retcodes) / sizeof(retcodes[0])))
{
return retcodes[rc];
} else if (rc >= (DDS_XRETCODE_BASE) &&
rc < (dds_retcode_t)(DDS_XRETCODE_BASE + (sizeof(xretcodes) / sizeof(xretcodes[0]))))
{
return xretcodes[rc - DDS_XRETCODE_BASE];
}
return "Unknown return code";
}

View file

@ -0,0 +1,101 @@
/*
* 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 _GNU_SOURCE /* Required for RUSAGE_THREAD. */
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/resource.h>
#if defined(__APPLE__)
#include <mach/mach_init.h>
#include <mach/mach_port.h>
#include <mach/thread_act.h>
#endif
#include "dds/ddsrt/rusage.h"
dds_retcode_t
ddsrt_getrusage(int who, ddsrt_rusage_t *usage)
{
int err = 0;
struct rusage buf;
dds_retcode_t rc;
assert(who == DDSRT_RUSAGE_SELF || who == DDSRT_RUSAGE_THREAD);
assert(usage != NULL);
memset(&buf, 0, sizeof(buf));
#if defined(__linux)
if ((who == DDSRT_RUSAGE_SELF && getrusage(RUSAGE_SELF, &buf) == -1) ||
(who == DDSRT_RUSAGE_THREAD && getrusage(RUSAGE_THREAD, &buf) == -1))
{
err = errno;
} else {
buf.ru_maxrss *= 1024;
}
#else
if (getrusage(RUSAGE_SELF, &buf) == -1) {
err = errno;
} else if (who == DDSRT_RUSAGE_THREAD) {
memset(&buf.ru_utime, 0, sizeof(buf.ru_utime));
memset(&buf.ru_stime, 0, sizeof(buf.ru_stime));
buf.ru_nvcsw = 0;
buf.ru_nivcsw = 0;
#if defined(__APPLE__)
kern_return_t ret;
mach_port_t thr;
mach_msg_type_number_t cnt;
thread_basic_info_data_t info;
thr = mach_thread_self();
assert(thr != MACH_PORT_DEAD);
if (thr == MACH_PORT_NULL) {
/* Resource shortage prevented reception of send right. */
err = ENOMEM;
} else {
cnt = THREAD_BASIC_INFO_COUNT;
ret = thread_info(
thr, THREAD_BASIC_INFO, (thread_info_t)&info, &cnt);
assert(ret != KERN_INVALID_ARGUMENT);
/* Assume MIG_ARRAY_TOO_LARGE will not happen. */
buf.ru_utime.tv_sec = info.user_time.seconds;
buf.ru_utime.tv_usec = info.user_time.microseconds;
buf.ru_stime.tv_sec = info.system_time.seconds;
buf.ru_stime.tv_usec = info.system_time.microseconds;
mach_port_deallocate(mach_task_self(), thr);
}
#endif /* __APPLE__ */
}
#endif /* __linux */
if (err == 0) {
rc = DDS_RETCODE_OK;
usage->utime =
(buf.ru_utime.tv_sec * DDS_NSECS_IN_SEC) +
(buf.ru_utime.tv_usec * DDS_NSECS_IN_USEC);
usage->stime =
(buf.ru_stime.tv_sec * DDS_NSECS_IN_SEC) +
(buf.ru_stime.tv_usec * DDS_NSECS_IN_USEC);
usage->maxrss = (size_t)buf.ru_maxrss;
usage->idrss = (size_t)buf.ru_idrss;
usage->nvcsw = (size_t)buf.ru_nvcsw;
usage->nivcsw = (size_t)buf.ru_nivcsw;
} else if (err == ENOMEM) {
rc = DDS_RETCODE_OUT_OF_RESOURCES;
} else {
rc = DDS_RETCODE_ERROR;
}
return rc;
}

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 <assert.h>
#include <stdint.h>
#include <string.h>
#include "dds/ddsrt/rusage.h"
#include <psapi.h>
dds_time_t
filetime_to_time(const FILETIME *ft)
{
/* FILETIME structures express times in 100-nanosecond time units. */
return ((ft->dwHighDateTime << 31) + (ft->dwLowDateTime)) * 100;
}
dds_retcode_t
ddsrt_getrusage(int who, ddsrt_rusage_t *usage)
{
FILETIME stime, utime, ctime, etime;
PROCESS_MEMORY_COUNTERS pmctrs;
assert(who == DDSRT_RUSAGE_SELF || who == DDSRT_RUSAGE_THREAD);
assert(usage != NULL);
/* Memory counters are per process, but populate them if thread resource
usage is requested to keep in sync with Linux. */
if ((!GetProcessMemoryInfo(GetCurrentProcess(), &pmctrs, sizeof(pmctrs)))
|| (who == DDSRT_RUSAGE_SELF &&
!GetProcessTimes(GetCurrentProcess(), &ctime, &etime, &stime, &utime))
|| (who == DDSRT_RUSAGE_THREAD &&
!GetThreadTimes(GetCurrentThread(), &ctime, &etime, &stime, &utime)))
{
return GetLastError();
}
memset(usage, 0, sizeof(*usage));
usage->stime = filetime_to_time(&stime);
usage->utime = filetime_to_time(&utime);
usage->maxrss = pmctrs.PeakWorkingSetSize;
return DDS_RETCODE_OK;
}

354
src/ddsrt/src/sockets.c Normal file
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
*/
#define _GNU_SOURCE
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#if !defined(_WIN32)
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
# if defined(__linux)
# include <linux/if_packet.h> /* sockaddr_ll */
# endif /* __linux */
#endif /* _WIN32 */
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/sockets_priv.h"
extern inline struct timeval *
ddsrt_duration_to_timeval_ceil(dds_duration_t reltime, struct timeval *tv);
#if DDSRT_HAVE_IPV6
const struct in6_addr ddsrt_in6addr_any = IN6ADDR_ANY_INIT;
const struct in6_addr ddsrt_in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
#endif
const int afs[] = {
#ifdef __linux
AF_PACKET,
#endif /* __linux */
#if DDSRT_HAVE_IPV6
AF_INET6,
#endif /* DDSRT_HAVE_IPV6 */
AF_INET,
DDSRT_AF_TERM /* Terminator */
};
const int *const os_supp_afs = afs;
socklen_t
ddsrt_sockaddr_get_size(const struct sockaddr *const sa)
{
socklen_t sz;
assert(sa != NULL);
switch(sa->sa_family) {
#if DDSRT_HAVE_IPV6
case AF_INET6:
sz = sizeof(struct sockaddr_in6);
break;
#endif /* DDSRT_HAVE_IPV6 */
#ifdef __linux
case AF_PACKET:
sz = sizeof(struct sockaddr_ll);
break;
#endif /* __linux */
default:
assert(sa->sa_family == AF_INET);
sz = sizeof(struct sockaddr_in);
break;
}
return sz;
}
uint16_t ddsrt_sockaddr_get_port(const struct sockaddr *const sa)
{
unsigned short port = 0;
switch(sa->sa_family) {
#if DDSRT_HAVE_IPV6
case AF_INET6:
port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
break;
#endif /* DDSRT_HAVE_IPV6 */
default:
assert(sa->sa_family == AF_INET);
port = ntohs(((struct sockaddr_in *)sa)->sin_port);
break;
}
return port;
}
bool
ddsrt_sockaddr_isunspecified(const struct sockaddr *__restrict sa)
{
assert(sa != NULL);
switch(sa->sa_family) {
#if DDSRT_HAVE_IPV6
case AF_INET6:
return IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6*)sa)->sin6_addr);
#endif
case AF_INET:
return (((struct sockaddr_in *)sa)->sin_addr.s_addr == 0);
}
return false;
}
bool
ddsrt_sockaddr_isloopback(const struct sockaddr *__restrict sa)
{
assert(sa != NULL);
switch (sa->sa_family) {
#if DDSRT_HAVE_IPV6
case AF_INET6:
return IN6_IS_ADDR_LOOPBACK(
&((const struct sockaddr_in6 *)sa)->sin6_addr);
#endif /* DDSRT_HAVE_IPV6 */
case AF_INET:
return (((const struct sockaddr_in *)sa)->sin_addr.s_addr
== htonl(INADDR_LOOPBACK));
}
return false;
}
bool
ddsrt_sockaddr_insamesubnet(
const struct sockaddr *sa1,
const struct sockaddr *sa2,
const struct sockaddr *mask)
{
bool eq = false;
if (sa1->sa_family != sa2->sa_family ||
sa1->sa_family != mask->sa_family)
{
return false;
}
switch (sa1->sa_family) {
case AF_INET: {
eq = ((((struct sockaddr_in *)sa1)->sin_addr.s_addr &
((struct sockaddr_in *)mask)->sin_addr.s_addr)
==
(((struct sockaddr_in *)sa2)->sin_addr.s_addr &
((struct sockaddr_in *)mask)->sin_addr.s_addr));
} break;
#if DDSRT_HAVE_IPV6
case AF_INET6: {
struct sockaddr_in6 *sin61, *sin62, *mask6;
size_t i, n = sizeof(sin61->sin6_addr.s6_addr);
sin61 = (struct sockaddr_in6 *)sa1;
sin62 = (struct sockaddr_in6 *)sa2;
mask6 = (struct sockaddr_in6 *)mask;
eq = true;
for (i = 0; eq && i < n; i++) {
eq = ((sin61->sin6_addr.s6_addr[i] &
mask6->sin6_addr.s6_addr[i])
==
(sin62->sin6_addr.s6_addr[i] &
mask6->sin6_addr.s6_addr[i]));
}
} break;
#endif
}
return eq;
}
dds_retcode_t
ddsrt_sockaddrfromstr(int af, const char *str, void *sa)
{
assert(str != NULL);
assert(sa != NULL);
switch (af) {
case AF_INET: {
struct in_addr buf;
if (inet_pton(af, str, &buf) != 1) {
return DDS_RETCODE_BAD_PARAMETER;
} else {
memset(sa, 0, sizeof(struct sockaddr_in));
((struct sockaddr_in *)sa)->sin_family = AF_INET;
memcpy(&((struct sockaddr_in *)sa)->sin_addr, &buf, sizeof(buf));
}
} break;
#if DDSRT_HAVE_IPV6
case AF_INET6: {
struct in6_addr buf;
if (inet_pton(af, str, &buf) != 1) {
return DDS_RETCODE_BAD_PARAMETER;
} else {
memset(sa, 0, sizeof(struct sockaddr_in6));
((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6;
memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &buf, sizeof(buf));
}
} break;
#endif
default:
return DDS_RETCODE_BAD_PARAMETER;
}
return DDS_RETCODE_OK;
}
dds_retcode_t ddsrt_sockaddrtostr(const void *sa, char *buf, size_t size)
{
const char *ptr;
assert(sa != NULL);
assert(buf != NULL);
switch (((struct sockaddr *)sa)->sa_family) {
case AF_INET:
ptr = inet_ntop(
AF_INET, &((struct sockaddr_in *)sa)->sin_addr, buf, (socklen_t)size);
break;
#if DDSRT_HAVE_IPV6
case AF_INET6:
ptr = inet_ntop(
AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, buf, (socklen_t)size);
break;
#endif
default:
return DDS_RETCODE_BAD_PARAMETER;
}
if (ptr == NULL) {
return DDS_RETCODE_NOT_ENOUGH_SPACE;
}
return DDS_RETCODE_OK;
}
#if DDSRT_HAVE_DNS
dds_retcode_t
ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp)
{
int gai_err = 0;
struct addrinfo hints, *res = NULL;
ddsrt_hostent_t *hent = NULL;
assert(name != NULL);
assert(hentp != NULL);
switch (af) {
#if DDSRT_HAVE_IPV6
case AF_INET6:
#endif
case AF_INET:
case AF_UNSPEC:
break;
default:
return DDS_RETCODE_BAD_PARAMETER;
}
/* Windows returns all registered addresses on the local computer if the
"nodename" parameter is an empty string. *NIX return HOST_NOT_FOUND.
Deny empty hostnames to keep behavior across platforms consistent. */
if (strlen(name) == 0) {
return DDS_RETCODE_HOST_NOT_FOUND;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = af;
gai_err = getaddrinfo(name, NULL, &hints, &res);
/* gai_strerror cannot be used because Windows does not offer a thread-safe
implementation and lwIP (there maybe others as well) does not offer an
implementation at all.
NOTE: Error codes returned by getaddrinfo map directly onto Windows
Socket error codes and WSAGetLastError can be used instead. */
DDS_TRACE("getaddrinfo for %s returned %d\n", name, gai_err);
switch (gai_err) {
#if defined(EAI_AGAIN)
case EAI_AGAIN:
/* Name server returned a temporary failure indication. */
return DDS_RETCODE_TRY_AGAIN;
#endif
case EAI_FAIL:
/* Name server returned a permanent failure indication. */
return DDS_RETCODE_ERROR;
/* Windows defines EAI_NODATA to EAI_NONAME. */
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
case EAI_NODATA:
/* Host exists, but does not have any network addresses defined. */
return DDS_RETCODE_NO_DATA;
#endif
#if defined(EAI_ADDRFAMILY)
case EAI_ADDRFAMILY: /* Host has no addresses in requested family. */
#endif
#if defined(EAI_NOSECURENAME) /* Windows */
case EAI_NOSECURENAME:
#endif
case EAI_NONAME:
/* Host does not exist. */
return DDS_RETCODE_HOST_NOT_FOUND;
case EAI_MEMORY:
/* Out of memory. */
return DDS_RETCODE_OUT_OF_RESOURCES;
#if defined(EAI_SYSTEM)
case EAI_SYSTEM:
/* Other system error. */
return DDS_RETCODE_ERROR;
#endif
case EAI_BADFLAGS: /* Invalid flags in hints.ai_flags. */
case EAI_FAMILY: /* Address family not supported. */
case EAI_SERVICE: /* Service not available for socket type. */
case EAI_SOCKTYPE: /* Socket type not supported. */
case 0: {
struct addrinfo *ai;
size_t addrno, naddrs, size;
assert(gai_err == 0);
assert(res != NULL);
naddrs = 0;
for (ai = res; ai != NULL; ai = ai->ai_next) {
naddrs++;
}
size = sizeof(*hent) + (naddrs * sizeof(hent->addrs[0]));
if ((hent = ddsrt_calloc_s(1, size)) != NULL) {
hent->naddrs = naddrs;
for (addrno = 0, ai = res;
addrno < naddrs && ai != NULL;
addrno++, ai = ai->ai_next)
{
memcpy(&hent->addrs[addrno], res->ai_addr, res->ai_addrlen);
}
} else {
return DDS_RETCODE_OUT_OF_RESOURCES;
}
freeaddrinfo(res);
} break;
default:
DDS_ERROR("getaddrinfo returned unkown error %d\n", gai_err);
return DDS_RETCODE_ERROR;
}
*hentp = hent;
return DDS_RETCODE_OK;
}
#endif /* DDSRT_HAVE_DNS */

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
*/
#ifndef DDSRT_SOCKETS_PRIV_H
#define DDSRT_SOCKETS_PRIV_H
#include <assert.h>
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/sockets.h"
#include "dds/ddsrt/time.h"
#if defined(__cplusplus)
extern "C" {
#endif
#if _WIN32
typedef long ddsrt_tv_sec_t;
typedef long ddsrt_tv_usec_t;
#else
typedef time_t ddsrt_tv_sec_t;
typedef suseconds_t ddsrt_tv_usec_t;
#endif
#define DDSRT_TIME_T_MAX \
(DDSRT_MAX_INTEGER(ddsrt_tv_sec_t))
/**
* @brief Convert a relative time to a timeval rounding up.
*
* @param[in] reltime Relative time to convert.
* @param[out] tv struct timeval* where timeout is stored.
*
* @returns NULL if @reltime was @DDS_INFINITY, the value of @tv otherwise.
*/
inline struct timeval *
ddsrt_duration_to_timeval_ceil(dds_duration_t reltime, struct timeval *tv)
{
assert(tv != NULL);
if (reltime == DDS_INFINITY) {
tv->tv_sec = 0;
tv->tv_usec = 0;
return NULL;
} else if (reltime > 0) {
dds_duration_t max_nsecs;
if (DDS_INFINITY > DDSRT_TIME_T_MAX) {
assert(DDSRT_TIME_T_MAX == INT32_MAX);
max_nsecs = INT32_MAX * DDS_NSECS_IN_SEC;
} else {
max_nsecs = DDSRT_TIME_T_MAX / DDS_NSECS_IN_SEC;
}
if (reltime < (max_nsecs - DDS_NSECS_IN_USEC - 1)) {
reltime += (DDS_NSECS_IN_USEC - 1);
tv->tv_sec = (ddsrt_tv_sec_t)(reltime / DDS_NSECS_IN_SEC);
tv->tv_usec = (ddsrt_tv_usec_t)((reltime % DDS_NSECS_IN_SEC) / DDS_NSECS_IN_USEC);
} else {
tv->tv_sec = DDSRT_TIME_T_MAX;
tv->tv_usec = 999999;
}
} else {
tv->tv_sec = 0;
tv->tv_usec = 0;
}
return tv;
}
#if defined(__cplusplus)
}
#endif
#endif /* DDSRT_SOCKETS_PRIV_H */

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
*/
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#if defined(__VXWORKS__)
#include <hostLib.h>
#endif /* __VXWORKS__ */
#if !defined(HOST_NAME_MAX) && defined(_POSIX_HOST_NAME_MAX)
# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
#endif
#include "dds/ddsrt/sockets.h"
#include "dds/ddsrt/string.h"
dds_retcode_t
ddsrt_gethostname(
char *name,
size_t len)
{
char buf[HOST_NAME_MAX + 1 /* '\0' */];
memset(buf, 0, sizeof(buf));
if (gethostname(buf, HOST_NAME_MAX) == 0) {
/* If truncation occurrs, no error is returned whether or not the buffer
is null-terminated. */
if (buf[HOST_NAME_MAX - 1] != '\0' ||
ddsrt_strlcpy(name, buf, len) >= len)
{
return DDS_RETCODE_NOT_ENOUGH_SPACE;
}
return DDS_RETCODE_OK;
} else {
switch (errno) {
case EFAULT: /* Invalid address (cannot happen). */
return DDS_RETCODE_ERROR;
case EINVAL: /* Negative length (cannot happen). */
return DDS_RETCODE_ERROR;
case ENAMETOOLONG:
return DDS_RETCODE_NOT_ENOUGH_SPACE;
default:
break;
}
}
return DDS_RETCODE_ERROR;
}

View file

@ -0,0 +1,530 @@
/*
* 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 <errno.h>
#include <string.h>
#include <unistd.h>
#if defined(__VXWORKS__)
#include <vxWorks.h>
#include <sockLib.h>
#include <ioLib.h>
#else
#include <sys/fcntl.h>
#endif /* __VXWORKS__ */
#include <sys/types.h>
#include <sys/socket.h>
#ifdef __APPLE__
#include <sys/sockio.h>
#endif /* __APPLE__ */
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/sockets_priv.h"
dds_retcode_t
ddsrt_socket(ddsrt_socket_t *sockptr, int domain, int type, int protocol)
{
ddsrt_socket_t sock;
assert(sockptr != NULL);
sock = socket(domain, type, protocol);
if (sock != -1) {
*sockptr = sock;
return DDS_RETCODE_OK;
}
switch (errno) {
case EACCES:
return DDS_RETCODE_NOT_ALLOWED;
case EAFNOSUPPORT:
case EINVAL:
return DDS_RETCODE_BAD_PARAMETER;
case EMFILE:
case ENFILE:
case ENOBUFS:
case ENOMEM:
return DDS_RETCODE_OUT_OF_RESOURCES;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_close(
ddsrt_socket_t sock)
{
if (close(sock) != -1)
return DDS_RETCODE_OK;
switch (errno) {
case EBADF:
return DDS_RETCODE_BAD_PARAMETER;
case EINTR:
return DDS_RETCODE_INTERRUPTED;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_bind(
ddsrt_socket_t sock,
const struct sockaddr *addr,
socklen_t addrlen)
{
if (bind(sock, addr, addrlen) == 0)
return DDS_RETCODE_OK;
switch (errno) {
case EACCES:
return DDS_RETCODE_NOT_ALLOWED;
case EADDRINUSE:
return DDS_RETCODE_PRECONDITION_NOT_MET;
case EBADF:
case EINVAL:
case ENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_listen(
ddsrt_socket_t sock,
int backlog)
{
if (listen(sock, backlog) == 0)
return DDS_RETCODE_OK;
switch (errno) {
case EADDRINUSE:
return DDS_RETCODE_PRECONDITION_NOT_MET;
case EBADF:
return DDS_RETCODE_BAD_PARAMETER;
case ENOTSOCK:
case EOPNOTSUPP:
return DDS_RETCODE_ILLEGAL_OPERATION;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_connect(
ddsrt_socket_t sock,
const struct sockaddr *addr,
socklen_t addrlen)
{
if (connect(sock, addr, addrlen) == 0)
return DDS_RETCODE_OK;
switch (errno) {
case EACCES:
case EPERM:
case EISCONN:
return DDS_RETCODE_NOT_ALLOWED;
case EADDRINUSE:
case EADDRNOTAVAIL:
return DDS_RETCODE_PRECONDITION_NOT_MET;
case EAFNOSUPPORT:
case EBADF:
case ENOTSOCK:
case EPROTOTYPE:
return DDS_RETCODE_BAD_PARAMETER;
case EAGAIN:
return DDS_RETCODE_OUT_OF_RESOURCES;
case EALREADY:
return DDS_RETCODE_TRY_AGAIN;
case ECONNREFUSED:
case ENETUNREACH:
return DDS_RETCODE_NO_CONNECTION;
case EINPROGRESS:
return DDS_RETCODE_IN_PROGRESS;
case EINTR:
return DDS_RETCODE_INTERRUPTED;
case ETIMEDOUT:
return DDS_RETCODE_TIMEOUT;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_accept(
ddsrt_socket_t sock,
struct sockaddr *addr,
socklen_t *addrlen,
ddsrt_socket_t *connptr)
{
ddsrt_socket_t conn;
if ((conn = accept(sock, addr, addrlen)) != -1) {
*connptr = conn;
return DDS_RETCODE_OK;
}
switch (errno) {
case EAGAIN:
#if EAGAIN != EWOULDBLOCK
case EWOULDBLOCK:
#endif
return DDS_RETCODE_TRY_AGAIN;
case EBADF:
case EFAULT:
case EINVAL:
return DDS_RETCODE_BAD_PARAMETER;
case ECONNABORTED:
return DDS_RETCODE_NO_CONNECTION;
case EINTR:
return DDS_RETCODE_INTERRUPTED;
case EMFILE:
case ENFILE:
case ENOBUFS:
case ENOMEM:
return DDS_RETCODE_OUT_OF_RESOURCES;
case ENOTSOCK:
case EOPNOTSUPP:
return DDS_RETCODE_ILLEGAL_OPERATION;
case EPROTO:
return DDS_RETCODE_ERROR;
case EPERM:
return DDS_RETCODE_NOT_ALLOWED;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_getsockname(
ddsrt_socket_t sock,
struct sockaddr *addr,
socklen_t *addrlen)
{
if (getsockname(sock, addr, addrlen) == 0)
return DDS_RETCODE_OK;
switch (errno) {
case EBADF:
case EFAULT:
case EINVAL:
case ENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
case ENOBUFS:
return DDS_RETCODE_OUT_OF_RESOURCES;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_getsockopt(
ddsrt_socket_t sock,
int32_t level,
int32_t optname,
void *optval,
socklen_t *optlen)
{
if (getsockopt(sock, level, optname, optval, optlen) == 0)
return DDS_RETCODE_OK;
switch (errno) {
case EBADF:
case EFAULT:
case EINVAL:
case ENOPROTOOPT:
case ENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_setsockopt(
ddsrt_socket_t sock,
int32_t level,
int32_t optname,
const void *optval,
socklen_t optlen)
{
switch (optname) {
case SO_SNDBUF:
case SO_RCVBUF:
/* optlen == 4 && optval == 0 does not work. */
if (!(optlen == 4 && *((unsigned *)optval) == 0)) {
break;
}
/* falls through */
case SO_DONTROUTE:
/* SO_DONTROUTE causes problems on macOS (e.g. no multicasting). */
return DDS_RETCODE_OK;
}
if (setsockopt(sock, level, optname, optval, optlen) == -1) {
goto err_setsockopt;
}
#if defined(__APPLE__)
if (level == SOL_SOCKET && optname == SO_REUSEADDR &&
setsockopt(sock, level, SO_REUSEPORT, optval, optlen) == -1)
{
goto err_setsockopt;
}
#endif /* __APPLE__ */
return DDS_RETCODE_OK;
err_setsockopt:
switch (errno) {
case EBADF:
case EINVAL:
case ENOPROTOOPT:
case ENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_setsocknonblocking(
ddsrt_socket_t sock,
bool nonblock)
{
int flags;
flags = fcntl(sock, F_GETFL, 0);
if (flags == -1) {
goto err_fcntl;
} else {
if (nonblock) {
flags |= O_NONBLOCK;
} else {
flags &= ~O_NONBLOCK;
}
if (fcntl(sock, F_SETFL, flags) == -1) {
goto err_fcntl;
}
}
return DDS_RETCODE_OK;
err_fcntl:
switch (errno) {
case EACCES:
case EAGAIN:
case EPERM:
return DDS_RETCODE_ERROR;
case EBADF:
case EINVAL:
return DDS_RETCODE_BAD_PARAMETER;
default:
break;
}
return DDS_RETCODE_ERROR;
}
static inline dds_retcode_t
recv_error_to_retcode(int errnum)
{
switch (errnum) {
case EAGAIN:
#if EAGAIN != EWOULDBLOCK
case EWOULDBLOCK:
#endif
return DDS_RETCODE_TRY_AGAIN;
case EBADF:
case EFAULT:
case EINVAL:
case ENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
case ECONNREFUSED:
return DDS_RETCODE_NO_CONNECTION;
case EINTR:
return DDS_RETCODE_INTERRUPTED;
case ENOMEM:
return DDS_RETCODE_OUT_OF_RESOURCES;
case ENOTCONN:
return DDS_RETCODE_ILLEGAL_OPERATION;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_recv(
ddsrt_socket_t sock,
void *buf,
size_t len,
int flags,
ssize_t *rcvd)
{
ssize_t n;
if ((n = recv(sock, buf, len, flags)) != -1) {
assert(n >= 0);
*rcvd = n;
return DDS_RETCODE_OK;
}
return recv_error_to_retcode(errno);
}
dds_retcode_t
ddsrt_recvmsg(
ddsrt_socket_t sock,
ddsrt_msghdr_t *msg,
int flags,
ssize_t *rcvd)
{
ssize_t n;
if ((n = recvmsg(sock, msg, flags)) != -1) {
assert(n >= 0);
*rcvd = n;
return DDS_RETCODE_OK;
}
return recv_error_to_retcode(errno);
}
static inline dds_retcode_t
send_error_to_retcode(int errnum)
{
switch (errnum) {
case EACCES:
return DDS_RETCODE_NOT_ALLOWED;
case EAGAIN:
#if EAGAIN != EWOULDBLOCK
case EWOULDBLOCK:
#endif
case EALREADY:
return DDS_RETCODE_TRY_AGAIN;
case EBADF:
case EFAULT:
case EINVAL:
case ENOTSOCK:
case EOPNOTSUPP:
return DDS_RETCODE_BAD_PARAMETER;
case ECONNRESET:
return DDS_RETCODE_NO_CONNECTION;
case EDESTADDRREQ:
case EISCONN:
case ENOTCONN:
case EPIPE:
return DDS_RETCODE_ILLEGAL_OPERATION;
case EINTR:
return DDS_RETCODE_INTERRUPTED;
case EMSGSIZE:
return DDS_RETCODE_NOT_ENOUGH_SPACE;
case ENOBUFS:
case ENOMEM:
return DDS_RETCODE_OUT_OF_RESOURCES;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_send(
ddsrt_socket_t sock,
const void *buf,
size_t len,
int flags,
ssize_t *sent)
{
ssize_t n;
if ((n = send(sock, buf, len, flags)) != -1) {
assert(n >= 0);
*sent = n;
return DDS_RETCODE_OK;
}
return send_error_to_retcode(errno);
}
dds_retcode_t
ddsrt_sendmsg(
ddsrt_socket_t sock,
const ddsrt_msghdr_t *msg,
int flags,
ssize_t *sent)
{
ssize_t n;
if ((n = sendmsg(sock, msg, flags)) != -1) {
assert(n >= 0);
*sent = n;
return DDS_RETCODE_OK;
}
return send_error_to_retcode(errno);
}
dds_retcode_t
ddsrt_select(
int32_t nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *errorfds,
dds_duration_t reltime,
int32_t *ready)
{
int n;
struct timeval tv, *tvp = NULL;
tvp = ddsrt_duration_to_timeval_ceil(reltime, &tv);
if ((n = select(nfds, readfds, writefds, errorfds, tvp)) != -1) {
*ready = n;
return (n == 0 ? DDS_RETCODE_TIMEOUT : DDS_RETCODE_OK);
}
switch (errno) {
case EINTR:
return DDS_RETCODE_INTERRUPTED;
case EBADF:
case EINVAL:
return DDS_RETCODE_BAD_PARAMETER;
case ENOMEM:
return DDS_RETCODE_OUT_OF_RESOURCES;
default:
break;
}
return DDS_RETCODE_ERROR;
}

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 <assert.h>
#include <limits.h>
#include "dds/ddsrt/sockets.h"
ddsrt_gethostname(
char *name,
size_t len)
{
assert(name != NULL);
assert(len <= INT_MAX);
if (len == 0) {
return DDS_RETCODE_BAD_PARAMETER;
} else if (gethostname(name, (int)len) == 0) {
return DDS_RETCODE_OK;
}
switch(WSAGetLastError()) {
case WSAEFAULT:
return DDS_RETCODE_NOT_ENOUGH_SPACE;
case WSAENETDOWN:
return DDS_RETCODE_NO_NETWORK;
case WSAEINPROGRESS:
return DDS_RETCODE_IN_PROGRESS;
default:
break;
}
return DDS_RETCODE_ERROR;
}

View file

@ -0,0 +1,680 @@
/*
* 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 <stdbool.h>
#include <stddef.h>
#include <winerror.h>
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/retcode.h"
#include "dds/ddsrt/sockets_priv.h"
#include "dds/ddsrt/time.h"
#ifdef ddsrt_select
#undef ddsrt_select /* See sockets.h for details. */
#endif
void
ddsrt_winsock_init(void)
{
int err;
WSADATA wsa_data;
err = WSAStartup(MAKEWORD(2,0), &wsa_data);
if (err != 0) {
DDS_FATAL("WSAStartup(2.0, ...) failed with %d\n", err);
}
/* Confirm Windows Socket version 2.0 is supported. If versions greater
than 2.0 in addition to 2.0 are supported, 2.0 will still be returned as
that is the requested version. */
if (LOBYTE(wsa_data.wVersion) != 2 ||
HIBYTE(wsa_data.wVersion) != 0)
{
WSACleanup();
DDS_FATAL("WSAStartup(2.0, ...) failed\n");
}
}
void
ddsrt_winsock_fini(void)
{
WSACleanup();
}
dds_retcode_t
ddsrt_socket(ddsrt_socket_t *sockptr, int domain, int type, int protocol)
{
int err;
dds_retcode_t ret = DDS_RETCODE_OK;
ddsrt_socket_t sock = DDSRT_INVALID_SOCKET;
assert(sockptr != NULL);
sock = socket(domain, type, protocol);
if (sock != INVALID_SOCKET) {
*sockptr = sock;
return DDS_RETCODE_OK;
}
err = WSAGetLastError();
assert(err != WSANOTINITIALISED);
assert(err != WSAEINVALIDPROCTABLE);
assert(err != WSAEINVALIDPROVIDER);
assert(err != WSAEPROVIDERFAILEDINIT);
switch (err) {
case WSAENETDOWN:
return DDS_RETCODE_NO_NETWORK;
case WSAEINVAL:
case WSAEAFNOSUPPORT:
case WSAEPROTONOSUPPORT:
case WSAEPROTOTYPE:
case WSAESOCKTNOSUPPORT:
return DDS_RETCODE_BAD_PARAMETER;
case WSAEINPROGRESS:
return DDS_RETCODE_TRY_AGAIN;
case WSAEMFILE:
case WSAENOBUFS:
return DDS_RETCODE_OUT_OF_RESOURCES;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_close(ddsrt_socket_t sock)
{
int err;
if (closesocket(sock) != SOCKET_ERROR)
return DDS_RETCODE_OK;
err = WSAGetLastError();
assert(err != WSANOTINITIALISED);
switch (err) {
case WSAENETDOWN:
return DDS_RETCODE_NO_NETWORK;
case WSAENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
case WSAEINPROGRESS:
case WSAEWOULDBLOCK:
return DDS_RETCODE_TRY_AGAIN;
case WSAEINTR:
return DDS_RETCODE_INTERRUPTED;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_accept(
ddsrt_socket_t sock,
struct sockaddr *addr,
socklen_t *addrlen,
ddsrt_socket_t *connptr)
{
int err;
ddsrt_socket_t conn;
if ((conn = accept(sock, addr, addrlen)) != INVALID_SOCKET) {
*connptr = conn;
return DDS_RETCODE_OK;
}
err = WSAGetLastError();
assert(err != WSANOTINITIALISED);
switch (err) {
case WSAECONNRESET:
return DDS_RETCODE_NO_CONNECTION;
case WSAEFAULT:
return DDS_RETCODE_BAD_PARAMETER;
case WSAEINTR:
return DDS_RETCODE_INTERRUPTED;
case WSAEINVAL:
case WSAENOTSOCK:
case WSAEOPNOTSUPP:
return DDS_RETCODE_ILLEGAL_OPERATION;
case WSAEINPROGRESS:
return DDS_RETCODE_IN_PROGRESS;
case WSAEMFILE:
case WSAENOBUFS:
return DDS_RETCODE_OUT_OF_RESOURCES;
case WSAEWOULDBLOCK:
return DDS_RETCODE_TRY_AGAIN;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_bind(ddsrt_socket_t sock, const struct sockaddr *addr, socklen_t addrlen)
{
int err;
if (bind(sock, addr, addrlen) != SOCKET_ERROR)
return DDS_RETCODE_OK;
err = WSAGetLastError();
assert(err != WSANOTINITIALISED);
switch (err) {
case WSAENETDOWN:
return DDS_RETCODE_NO_NETWORK;
case WSAEACCES:
return DDS_RETCODE_NOT_ALLOWED;
case WSAEADDRINUSE:
case WSAEADDRNOTAVAIL:
return DDS_RETCODE_PRECONDITION_NOT_MET;
case WSAEFAULT:
case WSAEINVAL:
case WSAENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
case WSAEINPROGRESS:
return DDS_RETCODE_TRY_AGAIN;
case WSAENOBUFS:
return DDS_RETCODE_OUT_OF_RESOURCES;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_listen(
ddsrt_socket_t sock,
int backlog)
{
int err;
if (listen(sock, backlog) != SOCKET_ERROR)
return DDS_RETCODE_OK;
err = WSAGetLastError();
assert(err != WSANOTINITIALISED);
switch (err) {
case WSAENETDOWN:
return DDS_RETCODE_NO_NETWORK;
case WSAEADDRINUSE:
case WSAEINVAL:
return DDS_RETCODE_PRECONDITION_NOT_MET;
case WSAEINPROGRESS:
return DDS_RETCODE_TRY_AGAIN;
case WSAEMFILE:
return DDS_RETCODE_OUT_OF_RESOURCES;
case WSAENOTSOCK:
case WSAEOPNOTSUPP:
return DDS_RETCODE_ILLEGAL_OPERATION;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_connect(
ddsrt_socket_t sock,
const struct sockaddr *addr,
socklen_t addrlen)
{
int err;
if (connect(sock, addr, addrlen) != SOCKET_ERROR)
return DDS_RETCODE_OK;
err = WSAGetLastError();
assert(err != WSANOTINITIALISED);
switch (err) {
case WSAENETDOWN:
return DDS_RETCODE_NO_NETWORK;
case WSAEADDRINUSE:
case WSAEADDRNOTAVAIL:
return DDS_RETCODE_PRECONDITION_NOT_MET;
case WSAEINTR:
return DDS_RETCODE_INTERRUPTED;
case WSAEINPROGRESS:
case WSAEALREADY:
case WSAEWOULDBLOCK:
return DDS_RETCODE_TRY_AGAIN;
case WSAEAFNOSUPPORT:
case WSAEFAULT:
case WSAEINVAL:
case WSAENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
case WSAECONNREFUSED:
case WSAENETUNREACH:
case WSAEHOSTUNREACH:
return DDS_RETCODE_NO_CONNECTION;
case WSAEISCONN:
case WSAEACCES:
return DDS_RETCODE_NOT_ALLOWED;
case WSAENOBUFS:
return DDS_RETCODE_OUT_OF_RESOURCES;
case WSAETIMEDOUT:
return DDS_RETCODE_TIMEOUT;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_getsockname(
ddsrt_socket_t sock,
struct sockaddr *addr,
socklen_t *addrlen)
{
int err;
assert(sock != INVALID_SOCKET);
assert(addr != NULL);
if (getsockname(sock, addr, addrlen) != SOCKET_ERROR)
return DDS_RETCODE_OK;
err = WSAGetLastError();
assert(err != WSANOTINITIALISED);
switch (err) {
case WSAENETDOWN:
return DDS_RETCODE_NO_NETWORK;
case WSAEFAULT: /* addrlen parameter is too small. */
return DDS_RETCODE_OUT_OF_RESOURCES;
case WSAEINPROGRESS:
return DDS_RETCODE_TRY_AGAIN;
case WSAENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
case WSAEINVAL:
return DDS_RETCODE_PRECONDITION_NOT_MET;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_getsockopt(
ddsrt_socket_t sock,
int32_t level,
int32_t optname,
void *optval,
socklen_t *optlen)
{
int err, ret;
if (level == IPPROTO_IP && (optname == IP_MULTICAST_TTL ||
optname == IP_MULTICAST_LOOP))
{
/* IP_MULTICAST_TTL and IP_MULTICAST_LOOP take a DWORD* rather than a
char* on Windows. */
int dwoptlen = sizeof(DWORD);
DWORD dwoptval = *((unsigned char *)optval);
ret = getsockopt(sock, level, optname, (char *)&dwoptval, &dwoptlen);
if (ret != SOCKET_ERROR) {
assert(dwoptlen == sizeof(DWORD));
*((unsigned char *)optval) = (unsigned char)dwoptval;
*optlen = sizeof( unsigned char );
}
} else {
ret = getsockopt(sock, level, optname, optval, (int *)optlen);
}
if (ret != SOCKET_ERROR)
return DDS_RETCODE_OK;
err = WSAGetLastError();
assert(err != WSANOTINITIALISED);
switch (err) {
case WSAENETDOWN:
return DDS_RETCODE_NO_NETWORK;
case WSAEFAULT:
case WSAEINVAL:
case WSAENOPROTOOPT:
case WSAENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
case WSAEINPROGRESS:
return DDS_RETCODE_TRY_AGAIN;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_setsockopt(
ddsrt_socket_t sock,
int32_t level,
int32_t optname,
const void *optval,
socklen_t optlen)
{
int err, ret;
DWORD dwoptval;
if (level == IPPROTO_IP && (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);
ret = setsockopt(sock, level, optname, optval, (int)optlen);
} else {
ret = setsockopt(sock, level, optname, optval, (int)optlen);
}
if (ret != SOCKET_ERROR)
return DDS_RETCODE_OK;
err = WSAGetLastError();
assert(err != WSANOTINITIALISED);
switch (err) {
case WSAENETDOWN:
return DDS_RETCODE_NO_NETWORK;
case WSAEFAULT:
case WSAEINVAL:
case WSAENOPROTOOPT:
case WSAENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
case WSAEINPROGRESS:
return DDS_RETCODE_IN_PROGRESS;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_setsocknonblocking(
ddsrt_socket_t sock,
bool nonblock)
{
int err;
u_long mode;
/* If mode = 0, blocking is enabled,
* if mode != 0, non-blocking is enabled. */
mode = nonblock ? 1 : 0;
if (ioctlsocket(sock, FIONBIO, &mode) != SOCKET_ERROR)
return DDS_RETCODE_OK;
err = WSAGetLastError();
assert(err != WSANOTINITIALISED);
switch (err) {
case WSAENETDOWN:
return DDS_RETCODE_NO_NETWORK;
case WSAEINPROGRESS:
return DDS_RETCODE_TRY_AGAIN;
case WSAENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
default:
break;
}
return DDS_RETCODE_ERROR;
}
static dds_retcode_t recv_error_to_retcode(int errnum)
{
assert(errnum != WSANOTINITIALISED);
switch (errnum) {
case WSAENETDOWN:
return DDS_RETCODE_NO_NETWORK;
case WSAEFAULT:
return DDS_RETCODE_BAD_PARAMETER;
case WSAENOTCONN:
case WSAEINVAL:
return DDS_RETCODE_PRECONDITION_NOT_MET;
case WSAEINTR:
return DDS_RETCODE_INTERRUPTED;
case WSAEINPROGRESS:
case WSAEWOULDBLOCK:
return DDS_RETCODE_TRY_AGAIN;
case WSAENETRESET:
case WSAECONNABORTED:
case WSAECONNRESET:
case WSAETIMEDOUT:
return DDS_RETCODE_NO_CONNECTION;
case WSAEISCONN:
case WSAENOTSOCK:
case WSAEOPNOTSUPP:
case WSAESHUTDOWN:
return DDS_RETCODE_ILLEGAL_OPERATION;
case WSAEMSGSIZE:
return DDS_RETCODE_NOT_ENOUGH_SPACE;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_recv(
ddsrt_socket_t sock,
void *buf,
size_t len,
int flags,
ssize_t *rcvd)
{
ssize_t n;
assert(len < INT_MAX);
if ((n = recv(sock, (char *)buf, (int)len, flags)) != SOCKET_ERROR) {
*rcvd = n;
return DDS_RETCODE_OK;
}
return recv_error_to_retcode(WSAGetLastError());
}
dds_retcode_t
ddsrt_recvmsg(
ddsrt_socket_t sock,
ddsrt_msghdr_t *msg,
int flags,
ssize_t *rcvd)
{
int err, n;
assert(msg != NULL);
assert(msg->msg_iovlen == 1);
assert(msg->msg_controllen == 0);
msg->msg_flags = 0;
n = recvfrom(
sock,
msg->msg_iov[0].iov_base,
msg->msg_iov[0].iov_len,
flags,
msg->msg_name,
&msg->msg_namelen);
if (n != -1) {
*rcvd = n;
return DDS_RETCODE_OK;
}
err = WSAGetLastError();
if (err == WSAEMSGSIZE) {
/* Windows returns an error for too-large messages, UNIX expects the
original size and the MSG_TRUNC flag. MSDN states it is truncated, which
presumably means it returned as much of the message as it could. Return
that the message was one byte larger than the available space and set
MSG_TRUNC. */
*rcvd = msg->msg_iov[0].iov_len + 1;
msg->msg_flags |= MSG_TRUNC;
}
return recv_error_to_retcode(err);
}
static dds_retcode_t
send_error_to_retcode(int errnum)
{
assert(errnum != WSANOTINITIALISED);
switch (errnum) {
case WSAENETDOWN: /* Network subsystem failed. */
return DDS_RETCODE_NO_NETWORK;
case WSAEACCES: /* Remote address is a broadcast address. */
return DDS_RETCODE_NOT_ALLOWED;
case WSAEINTR: /* Blocking sockets call was cancelled. */
return DDS_RETCODE_INTERRUPTED;
case WSAEINPROGRESS: /* Blocking sockets call in progress. */
case WSA_IO_PENDING: /* Operation pending (WSASentTo). */
return DDS_RETCODE_IN_PROGRESS;
case WSAEFAULT: /* A parameter was not part of the user address space or
destination address was to small (WSASendTo). */
case WSAEADDRNOTAVAIL: /* Remote address is not valid (WSASentTo). */
case WSAEAFNOSUPPORT: /* Remote address is in wrong family (WSASentTo). */
return DDS_RETCODE_BAD_PARAMETER;
case WSAENETRESET: /* Time to live expired. */
case WSAEHOSTUNREACH: /* Host is unreachable. */
case WSAECONNABORTED: /* Time-out or other failure (send). */
case WSAETIMEDOUT: /* Network or remote host failure (send). */
case WSAENETUNREACH: /* Network is unreachable. (WSASentTo). */
case WSA_OPERATION_ABORTED: /* Socket was closed (WSASentTo). */
return DDS_RETCODE_NO_CONNECTION;
case WSAENOBUFS:
return DDS_RETCODE_OUT_OF_RESOURCES;
case WSAENOTCONN: /* Socket is not connected. */
case WSAEINVAL: /* Socket has not been bound. */
return DDS_RETCODE_PRECONDITION_NOT_MET;
case WSAENOTSOCK: /* Descriptor is not a socket. */
case WSAEOPNOTSUPP: /* Operation not supported (send). */
case WSAESHUTDOWN: /* Socket shut down. */
return DDS_RETCODE_ILLEGAL_OPERATION;
case WSAEWOULDBLOCK: /* Socket is nonblocking and call would block. */
return DDS_RETCODE_TRY_AGAIN;
case WSAEMSGSIZE: /* Message is larger than transport maximum. */
return DDS_RETCODE_NOT_ENOUGH_SPACE;
default:
break;
}
return DDS_RETCODE_ERROR;
}
dds_retcode_t
ddsrt_send(
ddsrt_socket_t sock,
const void *buf,
size_t len,
int flags,
ssize_t *sent)
{
int n;
assert(buf != NULL);
assert(len <= INT_MAX);
assert(sent != NULL);
if ((n = send(sock, buf, (int)len, flags)) != SOCKET_ERROR) {
*sent = n;
return DDS_RETCODE_OK;
}
return send_error_to_retcode(WSAGetLastError());
}
/* Compile time check to ensure iovec matches WSABUF. */
struct iovec_matches_WSABUF {
char sizeof_matches[sizeof(ddsrt_iovec_t) == sizeof(WSABUF) ? 1 : -1];
char base_off_matches[offsetof(ddsrt_iovec_t, iov_base) == offsetof(WSABUF, buf) ? 1 : -1];
char base_size_matches[sizeof(((ddsrt_iovec_t *)8)->iov_base) == sizeof(((WSABUF *)8)->buf) ? 1 : -1];
char len_off_matches[offsetof(ddsrt_iovec_t, iov_len) == offsetof(WSABUF, len) ? 1 : -1];
char len_size_matches[sizeof(((ddsrt_iovec_t *)8)->iov_len) == sizeof(((WSABUF *)8)->len) ? 1 : -1];
};
dds_retcode_t
ddsrt_sendmsg(
ddsrt_socket_t sock,
const ddsrt_msghdr_t *msg,
int flags,
ssize_t *sent)
{
int ret;
DWORD n;
assert(msg != NULL);
assert(msg->msg_controllen == 0);
ret = WSASendTo(
sock,
(WSABUF *)msg->msg_iov,
(DWORD)msg->msg_iovlen,
&n,
flags,
(SOCKADDR *)msg->msg_name,
msg->msg_namelen,
NULL,
NULL);
if (ret != SOCKET_ERROR) {
*sent = (ssize_t)n;
return DDS_RETCODE_OK;
}
return send_error_to_retcode(WSAGetLastError());
}
dds_retcode_t
ddsrt_select(
int32_t nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *errorfds,
dds_duration_t reltime,
int32_t *ready)
{
int err;
int32_t n;
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }, *tvp = NULL;
(void)nfds;
tvp = ddsrt_duration_to_timeval_ceil(reltime, &tv);
if ((n = select(-1, readfds, writefds, errorfds, tvp)) != SOCKET_ERROR) {
*ready = n;
return (n == 0 ? DDS_RETCODE_TIMEOUT : DDS_RETCODE_OK);
}
err = WSAGetLastError();
assert(err != WSANOTINITIALISED);
switch (err) {
case WSAEFAULT:
return DDS_RETCODE_OUT_OF_RESOURCES;
case WSAENETDOWN:
return DDS_RETCODE_NO_NETWORK;
case WSAEINVAL:
case WSAENOTSOCK:
return DDS_RETCODE_BAD_PARAMETER;
case WSAEINPROGRESS:
return DDS_RETCODE_TRY_AGAIN;
default:
break;
}
return DDS_RETCODE_ERROR;
}

180
src/ddsrt/src/string.c Normal file
View file

@ -0,0 +1,180 @@
/*
* 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 <ctype.h>
#include <stdint.h>
#if defined(__IAR_SYSTEMS_ICC__)
#define _DLIB_ADD_EXTRA_SYMBOLS /* Export strtok_r. */
#endif
#include <string.h>
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/string.h"
int
ddsrt_strcasecmp(
const char *s1,
const char *s2)
{
int cr;
while (*s1 && *s2) {
cr = tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
if (cr) {
return cr;
}
s1++;
s2++;
}
cr = tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
return cr;
}
int
ddsrt_strncasecmp(
const char *s1,
const char *s2,
size_t n)
{
int cr = 0;
assert(s1 != NULL);
assert(s2 != NULL);
while (*s1 && *s2 && n) {
cr = tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
if (cr) {
return cr;
}
s1++;
s2++;
n--;
}
if (n) {
cr = tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
}
return cr;
}
char *
ddsrt_strtok_r(
char *str,
const char *delim,
char **saveptr)
{
#if _WIN32
return strtok_s(str, delim, saveptr);
#else
return strtok_r(str, delim, saveptr);
#endif
}
char *
ddsrt_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;
}
size_t
ddsrt_strlcpy(
char * __restrict dest,
const char * __restrict src,
size_t size)
{
size_t srclen = 0;
assert(dest != NULL);
assert(src != NULL);
/* strlcpy must return the number of bytes that (would) have been written,
i.e. the length of src. */
srclen = strlen(src);
if (size > 0) {
size_t len = srclen;
if (size <= srclen) {
len = size - 1;
}
memcpy(dest, src, len);
dest[len] = '\0';
}
return srclen;
}
/* NOTE: ddsrt_strlcat does not forward to strlcat too avoid a bug in the macOS
implementation where it does not return the right result if dest
contains more characters than the size specified if size is either
0 or 1. */
size_t
ddsrt_strlcat(
char * __restrict dest,
const char * __restrict src,
size_t size)
{
size_t destlen, srclen;
assert(dest != NULL);
assert(src != NULL);
/* strlcat must return the number of bytes that (would) have been written,
i.e. the length of dest plus the length of src. */
destlen = strlen(dest);
srclen = strlen(src);
if (SIZE_MAX == destlen) {
srclen = 0;
} else if ((SIZE_MAX - destlen) <= srclen) {
srclen = (SIZE_MAX - destlen) - 1;
}
if (size > 0 && --size > destlen) {
size_t len = srclen;
size -= destlen;
if (size <= srclen) {
len = size;
}
memcpy(dest + destlen, src, len);
dest[destlen + len] = '\0';
}
return destlen + srclen;
}
void *
ddsrt_memdup(const void *src, size_t n)
{
void *dest = NULL;
if (n != 0 && (dest = ddsrt_malloc_s(n)) != NULL) {
memcpy(dest, src, n);
}
return dest;
}
char *
ddsrt_strdup(
const char *str)
{
assert(str != NULL);
return ddsrt_memdup(str, strlen(str) + 1);
}

View file

@ -0,0 +1,43 @@
/*
* 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 <assert.h>
#include <errno.h>
#include <string.h>
#include "dds/ddsrt/string.h"
dds_retcode_t
ddsrt_strerror_r(int errnum, char *buf, size_t buflen)
{
assert(buf != NULL);
assert(buflen > 0);
switch (strerror_r(errnum, buf, buflen)) {
case 0: /* Success */
buf[buflen - 1] = '\0'; /* Always null-terminate, just to be safe. */
return DDS_RETCODE_OK;
case EINVAL:
return DDS_RETCODE_BAD_PARAMETER;
case ERANGE:
return DDS_RETCODE_NOT_ENOUGH_SPACE;
default:
break;
}
return DDS_RETCODE_ERROR;
}

View file

@ -0,0 +1,69 @@
/*
* 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 "dds/ddsrt/retcode.h"
#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
ddsrt_strerror_r(int errnum, char *buf, size_t buflen)
{
const char *str;
assert(buf != NULL);
assert(buflen > 0);
if (buflen < (NAME_MAX + 1))
return DDS_RETCODE_NOT_ENOUGH_SPACE;
if (strerrorIf(errnum) == NULL)
return DDS_RETCODE_BAD_PARAMETER;
(void)strerror_r(errnum, buf);
return DDS_RETCODE_OK;
}
#else
int
ddsrt_strerror_r(int errnum, char *buf, size_t buflen)
{
int err;
const char *str;
assert(buf != NULL);
assert(buflen > 0);
/* 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. */
err = 0;
buf[buflen - 1] = 'x';
(void)strerror_r(errnum, buf, buflen);
if (buf[buflen - 1] != 'x')
return DDS_RETCODE_NOT_ENOUGH_SPACE;
buf[buflen - 1] = '\0'; /* Always null terminate, just to be safe. */
return DDS_RETCODE_OK;
}
#endif /* _WRS_KERNEL */

View file

@ -0,0 +1,71 @@
/*
* 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 "dds/ddsrt/types.h"
#include "dds/ddsrt/string.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
ddsrt_strerror_r(
int errnum,
char *buf,
size_t buflen)
{
int orig_err;
DWORD cnt;
assert(buf != NULL);
assert(buflen > 0);
orig_err = GetLastError();
cnt = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL,
errnum,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)buf,
(DWORD)buflen,
NULL);
if (cnt == 0) {
if (GetLastError() == ERROR_MORE_DATA) {
return DDS_RETCODE_NOT_ENOUGH_SPACE;
} else {
return DDS_RETCODE_BAD_PARAMETER;
}
}
/* ddsrt_strerror_r should not modify errno itself. */
SetLastError(orig_err);
buf[buflen - 1] = '\0'; /* Always null-terminate, just to be safe. */
return DDS_RETCODE_OK;
}

208
src/ddsrt/src/strtod.c Normal file
View file

@ -0,0 +1,208 @@
/*
* 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 <ctype.h>
#include <errno.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "dds/ddsrt/io.h"
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/strtod.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, "%3.1f", 2.2);
lcNumeric = num [1];
if (lcNumeric != '.') {
DDS_WARNING("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 = strchr(str, lcNumeric);
if (str != NULL) {
*str = '.';
}
}
}
dds_retcode_t
ddsrt_strtod(const char *nptr, char **endptr, double *dblptr)
{
double dbl;
int orig_errno;
dds_retcode_t ret = DDS_RETCODE_OK;
assert(nptr != NULL);
assert(dblptr != NULL);
orig_errno = errno;
errno = 0;
if (os_lcNumericGet() == '.') {
/* The current locale uses '.', so strtod can be used as is. */
dbl = 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. */
dbl = strtod(nptrCopy, &nptrCopyEnd);
/* Calculate the proper end char when needed. */
if (endptr != NULL) {
*endptr = (char*)nptr + (nptrCopyEnd - nptrCopy);
}
}
if ((dbl == HUGE_VALF || dbl == HUGE_VALL || dbl == 0) && errno == ERANGE) {
ret = DDS_RETCODE_OUT_OF_RANGE;
} else {
errno = orig_errno;
}
*dblptr = dbl;
return ret;
}
dds_retcode_t
ddsrt_strtof(const char *nptr, char **endptr, float *fltptr)
{
/* Just use os_strtod(). */
/* FIXME: This will have to do for now, but a single-precision floating
point number is definitely not a double-precision floating point
number. */
double dbl = 0.0;
dds_retcode_t ret;
assert(nptr != NULL);
assert(fltptr != NULL);
ret = ddsrt_strtod(nptr, endptr, &dbl);
*fltptr = (float)dbl;
return ret;
}
int
ddsrt_dtostr(double src, char *str, size_t size)
{
int i;
assert(str != NULL);
/* 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;
}
int
ddsrt_ftostr(float src, char *str, size_t size)
{
int i;
assert(str != NULL);
/* 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;
}

276
src/ddsrt/src/strtol.c 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
*/
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include "dds/ddsrt/strtol.h"
int ddsrt_todigit(const int chr)
{
if (chr >= '0' && chr <= '9') {
return chr - '0';
} else if (chr >= 'a' && chr <= 'z') {
return 10 + (chr - 'a');
} else if (chr >= 'A' && chr <= 'Z') {
return 10 + (chr - 'A');
}
return -1;
}
static dds_retcode_t
ullfstr(
const char *str,
char **endptr,
int32_t base,
unsigned long long *ullng,
unsigned long long max)
{
dds_retcode_t rc = DDS_RETCODE_OK;
int num;
size_t cnt = 0;
unsigned long long tot = 0;
assert(str != NULL);
assert(ullng != NULL);
if (base == 0) {
if (str[0] == '0') {
if ((str[1] == 'x' || str[1] == 'X') && ddsrt_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) {
return DDS_RETCODE_BAD_PARAMETER;
}
while ((rc == DDS_RETCODE_OK) &&
(num = ddsrt_todigit(str[cnt])) >= 0 && num < base)
{
if (tot <= (max / (unsigned) base)) {
tot *= (unsigned) base;
tot += (unsigned) num;
cnt++;
} else {
rc = DDS_RETCODE_OUT_OF_RANGE;
tot = max;
}
}
if (endptr != NULL) {
*endptr = (char *)str + cnt;
}
*ullng = tot;
return rc;
}
dds_retcode_t
ddsrt_strtoll(
const char *str,
char **endptr,
int32_t base,
long long *llng)
{
dds_retcode_t rc = DDS_RETCODE_OK;
size_t cnt = 0;
long long tot = 1;
unsigned long long ullng = 0, max = INT64_MAX;
assert(str != NULL);
assert(llng != NULL);
for (; isspace((unsigned char)str[cnt]); cnt++) {
/* Ignore leading whitespace. */
}
if (str[cnt] == '-') {
tot = -1;
max++;
cnt++;
} else if (str[cnt] == '+') {
cnt++;
}
rc = ullfstr(str + cnt, endptr, base, &ullng, max);
if (endptr && *endptr == (str + cnt))
*endptr = (char *)str;
if (rc != DDS_RETCODE_BAD_PARAMETER)
*llng = tot * (long long)ullng;
return rc;
}
dds_retcode_t
ddsrt_strtoull(
const char *str,
char **endptr,
int32_t base,
unsigned long long *ullng)
{
dds_retcode_t rc = DDS_RETCODE_OK;
size_t cnt = 0;
unsigned long long tot = 1;
unsigned long long max = UINT64_MAX;
assert(str != NULL);
assert(ullng != 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++;
}
rc = ullfstr(str + cnt, endptr, base, ullng, max);
if (endptr && *endptr == (str + cnt))
*endptr = (char *)str;
if (rc != DDS_RETCODE_BAD_PARAMETER)
*ullng *= tot;
return rc;
}
dds_retcode_t
ddsrt_atoll(
const char *str,
long long *llng)
{
return ddsrt_strtoll(str, NULL, 10, llng);
}
dds_retcode_t
ddsrt_atoull(
const char *str,
unsigned long long *ullng)
{
return ddsrt_strtoull(str, NULL, 10, ullng);
}
char *
ddsrt_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 *
ddsrt_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)ddsrt_ulltostr(pos, str + cnt, len - cnt, &ptr);
}
if (endptr != NULL) {
*endptr = ptr;
}
return str;
}

View file

@ -0,0 +1,236 @@
/*
* 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 "dds/ddsrt/sync.h"
#include "dds/ddsrt/timeconv.h"
void ddsrt_mutex_init (ddsrt_mutex_t *mutex)
{
int shared;
assert (mutex != NULL);
pthread_mutex_init (&mutex->mutex, NULL);
(void)shared;
}
void ddsrt_mutex_destroy (ddsrt_mutex_t *mutex)
{
assert (mutex != NULL);
if (pthread_mutex_destroy (&mutex->mutex) != 0)
abort();
}
void ddsrt_mutex_lock (ddsrt_mutex_t *mutex)
{
assert (mutex != NULL);
if (pthread_mutex_lock (&mutex->mutex) != 0)
abort();
}
bool
ddsrt_mutex_trylock (ddsrt_mutex_t *mutex)
{
int err;
assert (mutex != NULL);
err = pthread_mutex_trylock (&mutex->mutex);
if (err != 0 && err != EBUSY)
abort();
return (err == 0);
}
void
ddsrt_mutex_unlock (ddsrt_mutex_t *mutex)
{
assert (mutex != NULL);
if (pthread_mutex_unlock (&mutex->mutex) != 0)
abort();
}
void
ddsrt_cond_init (ddsrt_cond_t *cond)
{
assert (cond != NULL);
pthread_cond_init (&cond->cond, NULL);
}
void
ddsrt_cond_destroy (ddsrt_cond_t *cond)
{
assert (cond != NULL);
if (pthread_cond_destroy (&cond->cond) != 0)
abort();
}
void
ddsrt_cond_wait (ddsrt_cond_t *cond, ddsrt_mutex_t *mutex)
{
assert (cond != NULL);
assert (mutex != NULL);
if (pthread_cond_wait (&cond->cond, &mutex->mutex) != 0)
abort();
}
bool
ddsrt_cond_waituntil(
ddsrt_cond_t *cond,
ddsrt_mutex_t *mutex,
dds_time_t abstime)
{
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
assert(cond != NULL);
assert(mutex != NULL);
if (abstime == DDS_NEVER) {
ddsrt_cond_wait(cond, mutex);
return true;
}
if (abstime > 0) {
ts.tv_sec = abstime / DDS_NSECS_IN_SEC;
ts.tv_nsec = abstime % DDS_NSECS_IN_SEC;
}
switch (pthread_cond_timedwait(&cond->cond, &mutex->mutex, &ts)) {
case 0:
return true;
case ETIMEDOUT:
return false;
default:
break;
}
abort();
}
bool
ddsrt_cond_waitfor(
ddsrt_cond_t *cond,
ddsrt_mutex_t *mutex,
dds_duration_t reltime)
{
assert(cond != NULL);
assert(mutex != NULL);
return ddsrt_cond_waituntil(
cond, mutex, ddsrt_time_add_duration(dds_time(), reltime));
}
void
ddsrt_cond_signal (ddsrt_cond_t *cond)
{
assert (cond != NULL);
if (pthread_cond_signal (&cond->cond) != 0)
abort();
}
void
ddsrt_cond_broadcast (ddsrt_cond_t *cond)
{
assert (cond != NULL);
if (pthread_cond_broadcast (&cond->cond) != 0)
abort();
}
void
ddsrt_rwlock_init (ddsrt_rwlock_t *rwlock)
{
int err = 0;
assert(rwlock != NULL);
/* process-shared attribute is set to PTHREAD_PROCESS_PRIVATE by default */
if ((err = pthread_rwlock_init(&rwlock->rwlock, NULL)) != 0)
abort();
}
void
ddsrt_rwlock_destroy (ddsrt_rwlock_t *rwlock)
{
int err;
assert(rwlock != NULL);
if ((err = pthread_rwlock_destroy (&rwlock->rwlock)) != 0)
abort();
}
void ddsrt_rwlock_read (ddsrt_rwlock_t *rwlock)
{
int err;
assert(rwlock != NULL);
err = pthread_rwlock_rdlock(&rwlock->rwlock);
assert(err == 0);
(void)err;
}
void ddsrt_rwlock_write (ddsrt_rwlock_t *rwlock)
{
int err;
assert(rwlock != NULL);
err = pthread_rwlock_wrlock(&rwlock->rwlock);
assert(err == 0);
(void)err;
}
bool ddsrt_rwlock_tryread (ddsrt_rwlock_t *rwlock)
{
int err;
assert(rwlock != NULL);
err = pthread_rwlock_tryrdlock(&rwlock->rwlock);
assert(err == 0 || err == EBUSY);
return err == 0;
}
bool ddsrt_rwlock_trywrite (ddsrt_rwlock_t *rwlock)
{
int err;
assert(rwlock != NULL);
err = pthread_rwlock_trywrlock(&rwlock->rwlock);
assert(err == 0 || err == EBUSY);
return err == 0;
}
void ddsrt_rwlock_unlock (ddsrt_rwlock_t *rwlock)
{
int err;
assert(rwlock != NULL);
err = pthread_rwlock_unlock(&rwlock->rwlock);
assert(err == 0);
(void)err;
}
void ddsrt_once (ddsrt_once_t *control, ddsrt_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,214 @@
/*
* 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 <stdlib.h>
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/timeconv.h"
void ddsrt_mutex_init(ddsrt_mutex_t *mutex)
{
assert(mutex != NULL);
InitializeSRWLock(&mutex->lock);
}
void ddsrt_mutex_destroy(ddsrt_mutex_t *mutex)
{
assert(mutex != NULL);
}
void ddsrt_mutex_lock(ddsrt_mutex_t *mutex)
{
assert(mutex != NULL);
AcquireSRWLockExclusive(&mutex->lock);
}
bool ddsrt_mutex_trylock(ddsrt_mutex_t *mutex)
{
assert(mutex != NULL);
return TryAcquireSRWLockExclusive(&mutex->lock);
}
void ddsrt_mutex_unlock(ddsrt_mutex_t *mutex)
{
assert(mutex != NULL);
ReleaseSRWLockExclusive(&mutex->lock);
}
void ddsrt_cond_init (ddsrt_cond_t *cond)
{
assert(cond != NULL);
InitializeConditionVariable(&cond->cond);
}
void ddsrt_cond_destroy(ddsrt_cond_t *cond)
{
assert(cond != NULL);
}
void
ddsrt_cond_wait(ddsrt_cond_t *cond, ddsrt_mutex_t *mutex)
{
assert(cond != NULL);
assert(mutex != NULL);
if (!SleepConditionVariableSRW(&cond->cond, &mutex->lock, INFINITE, 0)) {
abort();
}
}
bool
ddsrt_cond_waituntil(
ddsrt_cond_t *cond,
ddsrt_mutex_t *mutex,
dds_time_t abstime)
{
dds_duration_t reltime;
assert(cond != NULL);
assert(mutex != NULL);
if (abstime == DDS_NEVER) {
reltime = DDS_INFINITY;
} else {
dds_time_t time = dds_time();
reltime = (abstime > time ? abstime - time : 0);
}
return ddsrt_cond_waitfor(cond, mutex, reltime);
}
bool
ddsrt_cond_waitfor(
ddsrt_cond_t *cond,
ddsrt_mutex_t *mutex,
dds_duration_t reltime)
{
dds_time_t abstime;
DWORD msecs;
assert(cond != NULL);
assert(mutex != NULL);
if (reltime == DDS_INFINITY) {
ddsrt_cond_wait(cond, mutex);
return true;
}
abstime = ddsrt_time_add_duration(dds_time(), reltime);
msecs = ddsrt_duration_to_msecs_ceil(reltime);
if (SleepConditionVariableSRW(&cond->cond, &mutex->lock, msecs, 0)) {
return true;
} else if (GetLastError() != ERROR_TIMEOUT) {
abort();
}
return (dds_time() >= abstime) ? false : true;
}
void ddsrt_cond_signal (ddsrt_cond_t *cond)
{
assert(cond != NULL);
WakeConditionVariable(&cond->cond);
}
void ddsrt_cond_broadcast (ddsrt_cond_t *cond)
{
assert(cond != NULL);
WakeAllConditionVariable(&cond->cond);
}
void ddsrt_rwlock_init (ddsrt_rwlock_t *rwlock)
{
assert(rwlock);
InitializeSRWLock(&rwlock->lock);
rwlock->state = 0;
}
void ddsrt_rwlock_destroy (ddsrt_rwlock_t *rwlock)
{
assert(rwlock);
}
void ddsrt_rwlock_read (ddsrt_rwlock_t *rwlock)
{
assert(rwlock);
AcquireSRWLockShared(&rwlock->lock);
rwlock->state = 1;
}
void ddsrt_rwlock_write(ddsrt_rwlock_t *rwlock)
{
assert(rwlock);
AcquireSRWLockExclusive(&rwlock->lock);
rwlock->state = -1;
}
bool ddsrt_rwlock_tryread (ddsrt_rwlock_t *rwlock)
{
assert(rwlock);
if (TryAcquireSRWLockShared(&rwlock->lock)) {
rwlock->state = 1;
return true;
}
return false;
}
bool ddsrt_rwlock_trywrite (ddsrt_rwlock_t *rwlock)
{
assert(rwlock);
if (TryAcquireSRWLockExclusive(&rwlock->lock)) {
rwlock->state = -1;
return true;
}
return false;
}
void ddsrt_rwlock_unlock (ddsrt_rwlock_t *rwlock)
{
assert(rwlock);
assert(rwlock->state != 0);
if (rwlock->state > 0) {
ReleaseSRWLockShared(&rwlock->lock);
} else {
ReleaseSRWLockExclusive(&rwlock->lock);
}
}
typedef struct {
ddsrt_once_fn init_fn;
} once_arg_t;
static BOOL WINAPI
once_wrapper(
PINIT_ONCE InitOnce,
PVOID Parameter,
PVOID *Context)
{
once_arg_t *wrap = (once_arg_t *)Parameter;
assert(Parameter != NULL);
assert(Context == NULL);
wrap->init_fn();
return TRUE;
}
void
ddsrt_once(
ddsrt_once_t *control,
ddsrt_once_fn init_fn)
{
once_arg_t wrap = { .init_fn = init_fn };
(void) InitOnceExecuteOnce(control, &once_wrapper, &wrap, NULL);
}

24
src/ddsrt/src/threads.c Normal file
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
*/
#include <assert.h>
#include "dds/ddsrt/threads.h"
void
ddsrt_threadattr_init (
ddsrt_threadattr_t *tattr)
{
assert(tattr != NULL);
tattr->schedClass = DDSRT_SCHED_DEFAULT;
tattr->schedPriority = 0;
tattr->stackSize = 0;
}

View file

@ -0,0 +1,30 @@
/*
* 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 DDSRT_THREAD_TYPES_H
#define DDSRT_THREAD_TYPES_H
#include "dds/ddsrt/threads.h"
typedef struct {
char *name;
ddsrt_thread_routine_t routine;
void *arg;
} thread_context_t;
/** \brief Internal structure used to store cleanup handlers (private) */
typedef struct {
void *prev;
void (*routine)(void *);
void *arg;
} thread_cleanup_t;
#endif /* DDSRT_THREAD_TYPES_H */

View file

@ -0,0 +1,447 @@
/*
* 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
*/
/* _GNU_SOURCE is required for pthread_getname_np and pthread_setname_np. */
#define _GNU_SOURCE
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <limits.h>
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/string.h"
#include "dds/ddsrt/threads_priv.h"
#include "dds/ddsrt/types.h"
#if defined(__linux)
#include <sys/syscall.h>
#define MAXTHREADNAMESIZE (15) /* 16 bytes including null-terminating byte. */
#elif defined(__APPLE__)
#include <mach/thread_info.h> /* MAXTHREADNAMESIZE */
#elif defined(__sun)
#define MAXTHREADNAMESIZE (31)
#elif defined(__FreeBSD__)
/* Required for pthread_get_name_np and pthread_set_name_np. */
#include <pthread_np.h>
#include <sys/thr.h>
#define MAXTHREADNAMESIZE (MAXCOMLEN)
#elif defined(__VXWORKS__)
#include <taskLib.h>
/* VX_TASK_NAME_LENGTH is the maximum number of bytes, excluding
null-terminating byte, for a thread name. */
#define MAXTHREADNAMESIZE (VX_TASK_NAME_LENGTH)
#endif /* __APPLE__ */
size_t
ddsrt_thread_getname(char *str, size_t size)
{
char buf[MAXTHREADNAMESIZE + 1] = "";
size_t cnt = 0;
assert(str != NULL);
assert(size > 0);
#if defined(__linux)
/* Thread names are limited to 16 bytes on Linux. ERANGE is returned if the
buffer is smaller than 16 bytes. Use an intermediate buffer. */
(void)pthread_getname_np(pthread_self(), buf, sizeof(buf));
cnt = ddsrt_strlcpy(str, buf, size);
#elif defined(__APPLE__)
/* pthread_getname_np on APPLE uses strlcpy to copy the thread name, but
does not return the number of bytes (that would have been) written. Use
an intermediate buffer. */
(void)pthread_getname_np(pthread_self(), buf, sizeof(buf));
cnt = ddsrt_strlcpy(str, buf, size);
#elif defined(__FreeBSD__)
(void)pthread_get_name_np(pthread_self(), buf, sizeof(buf));
cnt = ddsrt_strlcpy(str, buf, size);
#elif defined(__sun)
(void)pthread_getname_np(pthread_self(), buf, sizeof(buf));
cnt = ddsrt_strlcpy(str, buf, size);
#elif defined(__VXWORKS__)
{
char *ptr;
/* VxWorks does not support retrieving the name of a task through the
POSIX thread API, but the task API offers it through taskName. */
/* Do not free the pointer returned by taskName. See
src/wind/taskInfo.c for details. */
ptr = taskName(taskIdSelf());
if (ptr == NULL) {
ptr = buf;
}
cnt = ddsrt_strlcpy(str, ptr, size);
}
#endif
/* Thread identifier is used as fall back if thread name lookup is not
supported or the thread name is empty. */
if (cnt == 0) {
ddsrt_tid_t tid = ddsrt_gettid();
cnt = (size_t)snprintf(str, size, "%"PRIdTID, tid);
}
return cnt;
}
void
ddsrt_thread_setname(const char *__restrict name)
{
assert(name != NULL);
#if defined(__linux)
/* Thread names are limited to 16 bytes on Linux. ERANGE is returned if the
name exceeds the limit, so silently truncate. */
char buf[MAXTHREADNAMESIZE + 1] = "";
ddsrt_strlcpy(buf, name, sizeof(buf));
(void)pthread_setname_np(pthread_self(), name);
#elif defined(__APPLE__)
(void)pthread_setname_np(name);
#elif defined(__FreeBSD__)
(void)pthread_set_name_np(pthread_self(), name);
#elif defined(__sun)
/* Thread names are limited to 31 bytes on Solaris. Excess bytes are
silently truncated. */
(void)pthread_setname_np(pthread_self(), name);
#else
/* VxWorks does not support the task name to be set after a task is created.
Setting the name of a task can be done through pthread_attr_setname. */
#warning "ddsrt_thread_setname is not supported"
#endif
}
/** \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)
{
thread_context_t *context = threadContext;
uintptr_t resultValue;
ddsrt_thread_setname(context->name);
/* Call the user routine */
resultValue = context->routine (context->arg);
/* Free the thread context resources, arguments is responsibility */
/* for the caller of os_procCreate */
ddsrt_free(context->name);
ddsrt_free(context);
#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(thread.v, &policy, &sched_param) == 0) {
max = sched_get_priority_max(policy);
if (max != -1) {
(void)pthread_setschedprio(thread.v, max);
}
}
#endif
/* return the result of the user routine */
return (void *)resultValue;
}
dds_retcode_t
ddsrt_thread_create (
ddsrt_thread_t *threadptr,
const char *name,
const ddsrt_threadattr_t *threadAttr,
uint32_t (*start_routine) (void *),
void *arg)
{
pthread_attr_t attr;
thread_context_t *ctx;
ddsrt_threadattr_t tattr;
int result, create_ret;
assert (threadptr != NULL);
assert (name != NULL);
assert (threadAttr != NULL);
assert (start_routine != NULL);
tattr = *threadAttr;
if (pthread_attr_init (&attr) != 0)
return DDS_RETCODE_ERROR;
#if defined(__VXWORKS__)
/* pthread_setname_np is not available on VxWorks. Use pthread_attr_setname
instead (proprietary VxWorks extension). */
(void)pthread_attr_setname (&attr, name);
#endif
if (pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM) != 0 ||
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE) != 0)
goto err;
if (tattr.stackSize != 0)
{
#ifdef PTHREAD_STACK_MIN
if (tattr.stackSize < PTHREAD_STACK_MIN)
tattr.stackSize = PTHREAD_STACK_MIN;
#endif
if ((result = pthread_attr_setstacksize (&attr, tattr.stackSize)) != 0)
{
DDS_ERROR ("ddsrt_thread_create(%s): pthread_attr_setstacksize(%"PRIu32") failed with error %d\n", name, tattr.stackSize, result);
goto err;
}
}
if (tattr.schedClass == DDSRT_SCHED_DEFAULT)
{
if (tattr.schedPriority != 0)
{
/* If caller doesn't set the class, he must not try to set the priority, which we
approximate by expecting a 0. FIXME: should do this as part of config validation */
DDS_ERROR("ddsrt_thread_create(%s): schedClass DEFAULT but priority != 0 is unsupported\n", name);
goto err;
}
}
else
{
int policy;
struct sched_param sched_param;
if ((result = pthread_getschedparam (pthread_self (), &policy, &sched_param) != 0) != 0)
{
DDS_ERROR("ddsrt_thread_create(%s): pthread_attr_getschedparam(self) failed with error %d\n", name, result);
goto err;
}
switch (tattr.schedClass)
{
case DDSRT_SCHED_DEFAULT:
assert (0);
break;
case DDSRT_SCHED_REALTIME:
policy = SCHED_FIFO;
break;
case DDSRT_SCHED_TIMESHARE:
policy = SCHED_OTHER;
break;
}
if ((result = pthread_attr_setschedpolicy (&attr, policy)) != 0)
{
DDS_ERROR("ddsrt_thread_create(%s): pthread_attr_setschedpolicy(%d) failed with error %d\n", name, policy, result);
goto err;
}
sched_param.sched_priority = tattr.schedPriority;
if ((result = pthread_attr_setschedparam (&attr, &sched_param)) != 0)
{
DDS_ERROR("ddsrt_thread_create(%s): pthread_attr_setschedparam(priority = %d) failed with error %d\n", name, tattr.schedPriority, result);
goto err;
}
if ((result = pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED)) != 0)
{
DDS_ERROR("ddsrt_thread_create(%s): pthread_attr_setinheritsched(EXPLICIT) failed with error %d\n", name, result);
goto err;
}
}
/* Construct context structure & start thread */
ctx = ddsrt_malloc (sizeof (thread_context_t));
ctx->name = ddsrt_malloc (strlen (name) + 1);
strcpy (ctx->name, name);
ctx->routine = start_routine;
ctx->arg = arg;
if ((create_ret = pthread_create (&threadptr->v, &attr, os_startRoutineWrapper, ctx)) != 0)
{
DDS_ERROR ("os_threadCreate(%s): pthread_create failed with error %d\n", name, create_ret);
goto err_create;
}
pthread_attr_destroy (&attr);
return DDS_RETCODE_OK;
err_create:
ddsrt_free (ctx->name);
ddsrt_free (ctx);
err:
pthread_attr_destroy (&attr);
return DDS_RETCODE_ERROR;
}
ddsrt_tid_t
ddsrt_gettid(void)
{
ddsrt_tid_t tid;
#if defined(__linux)
tid = syscall(SYS_gettid);
#elif defined(__FreeBSD__) && (__FreeBSD_version >= 900031)
/* FreeBSD >= 9.0 */
tid = pthread_getthreadid_np();
#elif defined(__APPLE__) && !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \
__MAC_OS_X_VERSION_MIN_REQUIRED < 1060)
/* macOS >= 10.6 */
pthread_threadid_np(NULL, &tid);
#elif defined(__VXWORKS__)
tid = taskIdSelf();
#else
tid = (uintmax_t)((uintptr_t)pthread_self());
#endif
return tid;
}
ddsrt_thread_t
ddsrt_thread_self(void)
{
ddsrt_thread_t id = {.v = pthread_self ()};
return id;
}
bool ddsrt_thread_equal(ddsrt_thread_t a, ddsrt_thread_t b)
{
return (pthread_equal(a.v, b.v) != 0);
}
dds_retcode_t
ddsrt_thread_join(ddsrt_thread_t thread, uint32_t *thread_result)
{
int err;
void *vthread_result;
assert (thread.v);
if ((err = pthread_join (thread.v, &vthread_result)) != 0)
{
DDS_TRACE ("pthread_join(0x%"PRIxMAX") failed with error %d\n", (uintmax_t)((uintptr_t)thread.v), err);
return DDS_RETCODE_ERROR;
}
if (thread_result)
*thread_result = (uint32_t) ((uintptr_t) vthread_result);
return DDS_RETCODE_OK;
}
static pthread_key_t thread_cleanup_key;
static pthread_once_t thread_once = PTHREAD_ONCE_INIT;
static void thread_cleanup_fini(void *arg);
static void thread_init_once(void)
{
int err;
err = pthread_key_create(&thread_cleanup_key, &thread_cleanup_fini);
assert(err == 0);
(void)err;
}
static void thread_init(void)
{
(void)pthread_once(&thread_once, &thread_init_once);
}
dds_retcode_t ddsrt_thread_cleanup_push (void (*routine) (void *), void *arg)
{
int err;
thread_cleanup_t *prev, *tail;
assert(routine != NULL);
thread_init();
if ((tail = ddsrt_calloc(1, sizeof(*tail))) != NULL) {
prev = pthread_getspecific(thread_cleanup_key);
tail->prev = prev;
tail->routine = routine;
tail->arg = arg;
if ((err = pthread_setspecific(thread_cleanup_key, tail)) != 0) {
assert(err != EINVAL);
return DDS_RETCODE_OUT_OF_RESOURCES;
}
return DDS_RETCODE_OK;
}
return DDS_RETCODE_OUT_OF_RESOURCES;
}
dds_retcode_t ddsrt_thread_cleanup_pop (int execute)
{
int err;
thread_cleanup_t *tail;
thread_init();
if ((tail = pthread_getspecific(thread_cleanup_key)) != NULL) {
if ((err = pthread_setspecific(thread_cleanup_key, tail->prev)) != 0) {
assert(err != EINVAL);
return DDS_RETCODE_OUT_OF_RESOURCES;
}
if (execute) {
tail->routine(tail->arg);
}
ddsrt_free(tail);
}
return DDS_RETCODE_OK;
}
static void thread_cleanup_fini(void *arg)
{
thread_cleanup_t *tail, *prev;
tail = (thread_cleanup_t *)arg;
while (tail != NULL) {
prev = tail->prev;
assert(tail->routine != NULL);
tail->routine(tail->arg);
ddsrt_free(tail);
tail = prev;
}
/* Thread-specific value associated with thread_cleanup_key will already be
nullified if invoked as destructor, i.e. not from ddsrt_thread_fini. */
}
void ddsrt_thread_init(void)
{
thread_init();
}
void ddsrt_thread_fini(void)
{
thread_cleanup_t *tail;
thread_init();
if ((tail = pthread_getspecific(thread_cleanup_key)) != NULL) {
thread_cleanup_fini(tail);
(void)pthread_setspecific(thread_cleanup_key, NULL);
}
}

View file

@ -0,0 +1,303 @@
/*
* 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 "dds/ddsrt/heap.h"
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/string.h"
#include "dds/ddsrt/threads_priv.h"
static uint32_t
os_startRoutineWrapper(
void *threadContext)
{
thread_context_t *context = threadContext;
uint32_t resultValue = 0;
ddsrt_thread_setname(context->name);
/* Call the user routine */
resultValue = context->routine(context->arg);
/* Free the thread context resources, arguments is responsibility */
/* for the caller of os_threadCreate */
ddsrt_free(context->name);
ddsrt_free(context);
/* return the result of the user routine */
return resultValue;
}
dds_retcode_t
ddsrt_thread_create(
ddsrt_thread_t *thrptr,
const char *name,
const ddsrt_threadattr_t *attr,
ddsrt_thread_routine_t start_routine,
void *arg)
{
ddsrt_thread_t thr;
thread_context_t *ctx;
int32_t prio;
assert(thrptr != NULL);
assert(name != NULL);
assert(attr != NULL);
assert(start_routine != NULL);
if ((ctx = ddsrt_malloc(sizeof(*ctx))) == NULL ||
(ctx->name = ddsrt_strdup(name)) == NULL)
return DDS_RETCODE_OUT_OF_RESOURCES;
ctx->routine = start_routine;
ctx->arg = arg;
thr.handle = CreateThread(NULL,
(SIZE_T)attr->stackSize,
(LPTHREAD_START_ROUTINE)os_startRoutineWrapper,
(LPVOID)ctx,
(DWORD)0,
&thr.tid);
if (thr.handle == NULL)
return DDS_RETCODE_ERROR;
*thrptr = thr;
/* 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. */
/* FIXME: The logic here might be incorrect.
https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority */
prio = attr->schedPriority;
if (GetPriorityClass(GetCurrentProcess()) == REALTIME_PRIORITY_CLASS) {
if (attr->schedPriority < -7)
prio = THREAD_PRIORITY_IDLE;
else if (attr->schedPriority > 6)
prio = THREAD_PRIORITY_TIME_CRITICAL;
} else {
if (attr->schedPriority < THREAD_PRIORITY_LOWEST)
prio = THREAD_PRIORITY_IDLE;
else if (attr->schedPriority > THREAD_PRIORITY_HIGHEST)
prio = THREAD_PRIORITY_TIME_CRITICAL;
}
if (SetThreadPriority(thr.handle, prio) == 0) {
DDS_WARNING("SetThreadPriority failed with %i\n", GetLastError());
}
return DDS_RETCODE_OK;
}
ddsrt_tid_t
ddsrt_gettid(void)
{
return GetCurrentThreadId();
}
ddsrt_thread_t
ddsrt_thread_self(
void)
{
ddsrt_thread_t thr;
thr.tid = GetCurrentThreadId();
thr.handle = GetCurrentThread(); /* pseudo HANDLE, no need to close it */
return thr;
}
bool ddsrt_thread_equal(ddsrt_thread_t a, ddsrt_thread_t b)
{
return a.tid == b.tid;
}
/* 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);
*/
dds_retcode_t
ddsrt_thread_join(
ddsrt_thread_t thread,
uint32_t *thread_result)
{
DWORD tr;
DWORD waitres;
BOOL status;
if (thread.handle == NULL) {
return DDS_RETCODE_BAD_PARAMETER;
}
waitres = WaitForSingleObject(thread.handle, INFINITE);
if (waitres != WAIT_OBJECT_0) {
//err = GetLastError();
//OS_DEBUG_1("os_threadWaitExit", "WaitForSingleObject Failed %d", err);
return DDS_RETCODE_ERROR;
}
status = GetExitCodeThread(thread.handle, &tr);
if (!status) {
//err = GetLastError();
//OS_DEBUG_1("os_threadWaitExit", "GetExitCodeThread Failed %d", err);
return DDS_RETCODE_ERROR;
}
assert(tr != STILL_ACTIVE);
if (thread_result) {
*thread_result = tr;
}
CloseHandle(thread.handle);
return DDS_RETCODE_OK;
}
/* Thread names on Linux are limited to 16 bytes, no reason to provide
more storage than that as internal threads must adhere to that limit. */
static ddsrt_thread_local char thread_name[16] = "";
size_t
ddsrt_thread_getname(
char *__restrict str,
size_t size)
{
size_t cnt;
assert(str != NULL);
if ((cnt = ddsrt_strlcpy(str, thread_name, size)) == 0) {
ddsrt_tid_t tid = ddsrt_gettid();
cnt = (size_t)snprintf(str, size, "%"PRIdTID, tid);
assert(cnt >= 0);
}
return cnt;
}
static const DWORD MS_VC_EXCEPTION=0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; /** Must be 0x1000. */
LPCSTR szName; /** Pointer to name (in user addr space). */
DWORD dwThreadID; /** Thread ID (-1=caller thread). */
DWORD dwFlags; /** Reserved for future use, must be zero. */
} THREADNAME_INFO;
#pragma pack(pop)
/** \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.
*/
void
ddsrt_thread_setname(
const char *__restrict name)
{
assert(name != NULL);
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = -1;
info.dwFlags = 0;
/* Empty try/except that catches everything on purpose to set the thread
name. See: http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx. */
#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)
{
/* Suppress warnings. */
}
#pragma warning(pop)
ddsrt_strlcpy(thread_name, name, sizeof(thread_name));
}
static ddsrt_thread_local thread_cleanup_t *thread_cleanup = NULL;
dds_retcode_t ddsrt_thread_cleanup_push(void (*routine)(void *), void *arg)
{
thread_cleanup_t *tail;
assert(routine != NULL);
if ((tail = ddsrt_malloc(sizeof(thread_cleanup_t))) != NULL) {
tail->prev = thread_cleanup;
thread_cleanup = tail;
assert(tail != NULL);
tail->routine = routine;
tail->arg = arg;
return DDS_RETCODE_OK;
}
return DDS_RETCODE_OUT_OF_RESOURCES;
}
dds_retcode_t ddsrt_thread_cleanup_pop(int execute)
{
thread_cleanup_t *tail;
if ((tail = thread_cleanup) != NULL) {
thread_cleanup = tail->prev;
if (execute) {
tail->routine(tail->arg);
}
ddsrt_free(tail);
}
return DDS_RETCODE_OK;
}
static void
thread_cleanup_fini(void)
{
thread_cleanup_t *tail, *prev;
tail = thread_cleanup;
while (tail != NULL) {
prev = tail->prev;
assert(tail->routine != NULL);
tail->routine(tail->arg);
ddsrt_free(tail);
tail = prev;
}
thread_cleanup = NULL;
}
void
ddsrt_thread_init(void)
{
return;
}
void
ddsrt_thread_fini(void)
{
thread_cleanup_fini();
}

74
src/ddsrt/src/time.c Normal file
View file

@ -0,0 +1,74 @@
/*
* 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 <time.h>
#include "dds/ddsrt/timeconv.h"
#include "dds/ddsrt/string.h"
extern inline dds_time_t
ddsrt_time_add_duration(dds_time_t abstime, dds_duration_t reltime);
#if !defined(_WIN32)
#include <errno.h>
void dds_sleepfor(dds_duration_t n)
{
struct timespec t, r;
if (n >= 0) {
t.tv_sec = n / DDS_NSECS_IN_SEC;
t.tv_nsec = n % DDS_NSECS_IN_SEC;
while (nanosleep(&t, &r) == -1 && errno == EINTR) {
t = r;
}
}
}
#endif
void dds_sleepuntil(dds_time_t abstime)
{
dds_time_t now = dds_time();
if (abstime > now)
dds_sleepfor (abstime - now);
}
size_t
ddsrt_ctime(dds_time_t n, char *str, size_t size)
{
struct tm tm;
static const char fmt[] = "%Y-%m-%d %H:%M:%S%z";
char buf[] = "YYYY-mm-dd HH:MM:SS.hh:mm"; /* RFC 3339 */
size_t cnt;
time_t sec = (time_t)(n / DDS_NSECS_IN_SEC);
assert(str != NULL);
#if _WIN32
(void)localtime_s(&tm, &sec);
#else
(void)localtime_r(&sec, &tm);
#endif /* _WIN32 */
cnt = strftime(buf, sizeof(buf), fmt, &tm);
assert(cnt == (sizeof(buf) - 2 /* ':' + '\0' */));
buf[sizeof(buf) - 1] = '\0';
buf[sizeof(buf) - 2] = buf[sizeof(buf) - 3];
buf[sizeof(buf) - 3] = buf[sizeof(buf) - 4];
buf[sizeof(buf) - 4] = ':';
(void)cnt;
return ddsrt_strlcpy(str, buf, size);
}

View file

@ -0,0 +1,58 @@
/*
* 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 <errno.h>
#include <time.h>
#include <sys/time.h>
#include <mach/mach_time.h>
#include "dds/ddsrt/time.h"
dds_time_t dds_time(void)
{
struct timeval tv;
(void)gettimeofday(&tv, NULL);
return ((tv.tv_sec * DDS_NSECS_IN_SEC) + (tv.tv_usec * DDS_NSECS_IN_USEC));
}
dds_time_t ddsrt_time_monotonic(void)
{
static mach_timebase_info_data_t timeInfo;
uint64_t mt;
/* 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);
}
return (dds_time_t)(mt * timeInfo.numer / timeInfo.denom);
}
dds_time_t ddsrt_time_elapsed(void)
{
/* Elapsed time clock not (yet) supported on this platform. */
return ddsrt_time_monotonic();
}

View file

@ -0,0 +1,68 @@
/*
* 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 <time.h>
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/time.h"
/**
* @brief Calculate a time given an offset time and a duration.
*
* Negative time can become positive by adding a large enough duration, of
* course a positive time can become negative given a large enough negative
* duration.
*
* @param[in] abstime Timestamp in nanoseconds since UNIX Epoch.
* @param[in] reltime Relative time in nanoseconds.
*
* @returns A timestamp in nanoseconds since UNIX Epoch.
*/
inline dds_time_t
ddsrt_time_add_duration(dds_time_t abstime, dds_duration_t reltime)
{
assert(abstime >= 0);
assert(reltime >= 0);
return (reltime >= DDS_NEVER - abstime ? DDS_NEVER : abstime + reltime);
}
#if _WIN32
/**
* @brief Convert a relative time to microseconds rounding up.
*
* @param[in] reltime Relative time to convert.
*
* @returns INFINITE if @reltime was @DDS_INIFINITY, relative time converted to
* microseconds otherwise.
*/
inline DWORD
ddsrt_duration_to_msecs_ceil(dds_duration_t reltime)
{
if (reltime == DDS_INFINITY) {
return INFINITE;
} else if (reltime > 0) {
assert(INFINITE < (DDS_INFINITY / DDS_NSECS_IN_MSEC));
dds_duration_t max_nsecs = (INFINITE - 1) * DDS_NSECS_IN_MSEC;
if (reltime < (max_nsecs - (DDS_NSECS_IN_MSEC - 1))) {
reltime += (DDS_NSECS_IN_MSEC - 1);
} else {
reltime = max_nsecs;
}
return (DWORD)(reltime / DDS_NSECS_IN_MSEC);
}
return 0;
}
#endif

View file

@ -0,0 +1,41 @@
/*
* 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 <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include "dds/ddsrt/time.h"
dds_time_t dds_time(void)
{
struct timespec ts;
(void)clock_gettime(CLOCK_REALTIME, &ts);
return (ts.tv_sec * DDS_NSECS_IN_SEC) + ts.tv_nsec;
}
dds_time_t ddsrt_time_monotonic(void)
{
struct timespec ts;
(void)clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * DDS_NSECS_IN_SEC) + ts.tv_nsec;
}
dds_time_t ddsrt_time_elapsed(void)
{
/* Elapsed time clock not worth the bother for now. */
return ddsrt_time_monotonic();
}

View file

@ -0,0 +1,161 @@
/*
* 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 <sys/timeb.h>
#include <time.h>
#include "dds/ddsrt/timeconv.h"
extern inline DWORD
ddsrt_duration_to_msecs_ceil(dds_duration_t reltime);
/* GetSystemTimePreciseAsFileTime was introduced with Windows 8, so
starting from _WIN32_WINNET = 0x0602. When building for an older
version we can still check dynamically. */
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0602
#define UseGetSystemTimePreciseAsFileTime
#else
static VOID (WINAPI *GetSystemTimeAsFileTimeFunc)(LPFILTETIME) = GetSystemTimeAsFileTime;
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
* dds_time.
*/
#define FILETIME_EPOCH_OFFSET_SECS (11644473600)
#define SECS_IN_100_NSECS (1000 * 1000 * 10)
dds_time_t dds_time(void)
{
FILETIME ft;
ULARGE_INTEGER ns100;
/* 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.
*/
#ifdef UseGetSystemTimePreciseAsFileTime
GetSystemTimePreciseAsFileTime(&ft);
#else
GetSystemTimeAsFileTimeFunc(&ft);
#endif
ns100.LowPart = ft.dwLowDateTime;
ns100.HighPart = ft.dwHighDateTime;
ns100.QuadPart -= (FILETIME_EPOCH_OFFSET_SECS * SECS_IN_100_NSECS);
return (dds_time_t)(ns100.QuadPart * 100);
}
void ddsrt_time_init(void)
{
#ifndef UseGetSystemTimePreciseAsFileTime
/* Resolve the time-functions from the Kernel32-library. */
VOID (WINAPI *f) (LPFILTETIME);
/* 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);
f = GetProcAddress(Kernel32ModuleHandle, "GetSystemTimePreciseAsFileTime");
if (f != 0) {
GetSystemTimeAsFileTimeFunc = f;
}
#endif
}
void ddsrt_time_fini(void)
{
#ifndef UseGetSystemTimePreciseAsFileTime
if (Kernel32ModuleHandle) {
GetSystemTimeAsFileTimeFunc = GetSystemTimeAsFileTime;
FreeLibrary(Kernel32ModuleHandle);
Kernel32ModuleHandle = NULL;
}
#endif
}
dds_time_t ddsrt_time_monotonic(void)
{
ULONGLONG ubit;
(void)QueryUnbiasedInterruptTime(&ubit); /* 100ns ticks */
return (dds_time_t)(ubit * 100);
}
dds_time_t ddsrt_time_elapsed(void)
{
LARGE_INTEGER qpc;
static LONGLONG qpc_freq; /* Counts per nanosecond. */
/* 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. */
if (qpc_freq == 0){
/* This block is idempotent, so don't bother with synchronisation. */
LARGE_INTEGER frequency;
if (QueryPerformanceFrequency(&frequency)) {
/* Performance-counter frequency is in counts per second. */
qpc_freq = DDS_NSECS_IN_SEC / 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. */
QueryPerformanceCounter(&qpc);
return (dds_time_t)(qpc.QuadPart * qpc_freq);
}
void dds_sleepfor(dds_duration_t reltime)
{
Sleep(ddsrt_duration_to_msecs_ceil(reltime));
}

View file

@ -0,0 +1,43 @@
#
# 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)
set(sources
"atomics.c"
"environ.c"
"heap.c"
"ifaddrs.c"
"sync.c"
"strtoll.c"
"thread.c"
"thread_cleanup.c"
"string.c"
"log.c"
"strlcpy.c"
"socket.c"
"select.c")
add_cunit_executable(cunit_ddsrt ${sources})
target_link_libraries(cunit_ddsrt PRIVATE ddsrt)
# Create a dummy export header. generate_export_header can only be used with
# library targets, but since the targets are linked statically,
# __declspec(dllimport) is not required anyway.
set(export_dir "${CMAKE_CURRENT_BINARY_DIR}/include/dds")
set(export_header "${export_dir}/export.h")
if(NOT EXISTS "${export_header}")
file(MAKE_DIRECTORY "${export_dir}")
file(WRITE "${export_header}" "#define DDS_EXPORT\n")
endif()
target_include_directories(
cunit_ddsrt PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>")

393
src/ddsrt/tests/atomics.c Normal file
View file

@ -0,0 +1,393 @@
/*
* 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/Test.h"
#include "dds/ddsrt/atomics.h"
uint32_t _osuint32 = 0;
uint64_t _osuint64 = 0;
uintptr_t _osaddress = 0;
ptrdiff_t _ptrdiff = 0;
void * _osvoidp = (uintptr_t *)0;
CU_Test(ddsrt_atomics, load_store)
{
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(5);
#if DDSRT_HAVE_ATOMIC64
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(5);
#endif
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(5);
volatile ddsrt_atomic_voidp_t voidp = DDSRT_ATOMIC_VOIDP_INIT((uintptr_t)5);
/* Test uint32 LD-ST */
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 5); /* Returns contents of uint32 */
ddsrt_atomic_st32 (&uint32, _osuint32); /* Writes os_uint32 into uint32 */
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == _osuint32);
/* Test uint64 LD-ST */
#if DDSRT_HAVE_ATOMIC64
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 5);
ddsrt_atomic_st64 (&uint64, _osuint64);
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == _osuint64);
#endif
/* Test uintptr LD-ST */
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 5);
ddsrt_atomic_stptr (&uintptr, _osaddress);
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == _osaddress);
/* Test uintvoidp LD-ST */
CU_ASSERT (ddsrt_atomic_ldvoidp (&voidp) == (uintptr_t*)5);
ddsrt_atomic_stvoidp (&voidp, _osvoidp);
CU_ASSERT (ddsrt_atomic_ldvoidp (&voidp) == (uintptr_t*)_osvoidp);
}
CU_Test(ddsrt_atomics, compare_and_swap)
{
/* Compare and Swap if (ptr == expected) { ptr = newval; } */
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(0);
#if DDSRT_HAVE_ATOMIC64
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(0);
#endif
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(0);
volatile ddsrt_atomic_voidp_t uintvoidp = DDSRT_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 ddsrt_atomic_cas32 */
ret = ddsrt_atomic_cas32 (&uint32, expected, newval);
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == newval && ret == 1);
ddsrt_atomic_st32 (&uint32, _osuint32);
ret = ddsrt_atomic_cas32 (&uint32, expected, newval);
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) != newval && ret == 0);
/* Test ddsrt_atomic_cas64 */
#if DDSRT_HAVE_ATOMIC64
ret = ddsrt_atomic_cas64 (&uint64, expected, newval);
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == newval && ret == 1);
ddsrt_atomic_st64 (&uint64, _osuint64);
ret = ddsrt_atomic_cas64 (&uint64, expected, newval);
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) != newval && ret == 0);
#endif
/* Test ddsrt_atomic_casptr */
ret = ddsrt_atomic_casptr (&uintptr, addr_expected, addr_newval);
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == addr_newval && ret == 1);
ddsrt_atomic_stptr (&uintptr, _osaddress);
ret = ddsrt_atomic_casptr (&uintptr, addr_expected, addr_newval);
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) != addr_newval && ret == 0);
/* Test ddsrt_atomic_casvoidp */
ret = ddsrt_atomic_casvoidp (&uintvoidp, void_expected, void_newval);
CU_ASSERT (ddsrt_atomic_ldvoidp (&uintvoidp) == (uintptr_t*)void_newval && ret == 1);
ddsrt_atomic_stvoidp (&uintvoidp, _osvoidp);
ret = ddsrt_atomic_casvoidp (&uintvoidp, void_expected, void_newval);
CU_ASSERT (ddsrt_atomic_ldvoidp (&uintvoidp) == (uintptr_t*)1 && ret == 0);
}
CU_Test(ddsrt_atomics, increment)
{
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(0);
#if DDSRT_HAVE_ATOMIC64
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(0);
#endif
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(0);
_osuint32 = 0;
_osuint64 = 0;
_osaddress = 0;
_osvoidp = (uintptr_t *)0;
/* Test os_inc32 */
ddsrt_atomic_inc32 (&uint32);
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 1);
/* Test os_inc64 */
#if DDSRT_HAVE_ATOMIC64
ddsrt_atomic_inc64 (&uint64);
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 1);
#endif
/* Test os_incptr */
ddsrt_atomic_incptr (&uintptr);
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 1);
/* Test ddsrt_atomic_inc32_nv */
ddsrt_atomic_st32 (&uint32, _osuint32);
CU_ASSERT (ddsrt_atomic_inc32_nv (&uint32) == 1);
/* Test ddsrt_atomic_inc64_nv */
#if DDSRT_HAVE_ATOMIC64
ddsrt_atomic_st64 (&uint64, _osuint64);
CU_ASSERT (ddsrt_atomic_inc64_nv (&uint64) == 1);
#endif
/* Test ddsrt_atomic_incptr_nv */
ddsrt_atomic_stptr (&uintptr, _osaddress);
CU_ASSERT (ddsrt_atomic_incptr_nv(&uintptr) == 1);
}
CU_Test(ddsrt_atomics, decrement)
{
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(1);
#if DDSRT_HAVE_ATOMIC64
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(1);
#endif
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(1);
_osuint32 = 1;
_osuint64 = 1;
_osaddress = 1;
_osvoidp = (uintptr_t *)1;
/* Test ddsrt_atomic_dec32 */
ddsrt_atomic_dec32 (&uint32);
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 0);
/* Test ddsrt_atomic_dec64 */
#if DDSRT_HAVE_ATOMIC64
ddsrt_atomic_dec64 (&uint64);
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 0);
#endif
/* Test ddsrt_atomic_decptr */
ddsrt_atomic_decptr (&uintptr);
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 0);
/* Test ddsrt_atomic_dec32_nv */
ddsrt_atomic_st32 (&uint32, _osuint32);
CU_ASSERT (ddsrt_atomic_dec32_nv (&uint32) == 0);
/* Test ddsrt_atomic_dec64_nv */
#if DDSRT_HAVE_ATOMIC64
ddsrt_atomic_st64 (&uint64, _osuint64);
CU_ASSERT (ddsrt_atomic_dec64_nv (&uint64) == 0);
#endif
/* Test ddsrt_atomic_decptr_nv */
ddsrt_atomic_stptr (&uintptr, _osaddress);
CU_ASSERT (ddsrt_atomic_decptr_nv(&uintptr) == 0);
}
CU_Test(ddsrt_atomics, add)
{
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(1);
#if DDSRT_HAVE_ATOMIC64
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(1);
#endif
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(1);
volatile ddsrt_atomic_voidp_t uintvoidp = DDSRT_ATOMIC_VOIDP_INIT((uintptr_t)1);
_osuint32 = 2;
_osuint64 = 2;
_osaddress = 2;
_ptrdiff = 2;
/* Test ddsrt_atomic_add32 */
ddsrt_atomic_add32 (&uint32, _osuint32);
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 3);
/* Test ddsrt_atomic_add64 */
#if DDSRT_HAVE_ATOMIC64
ddsrt_atomic_add64 (&uint64, _osuint64);
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 3);
#endif
/* Test ddsrt_atomic_addptr */
ddsrt_atomic_addptr (&uintptr, _osaddress);
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 3);
/* Test ddsrt_atomic_addvoidp */
ddsrt_atomic_addvoidp (&uintvoidp, _ptrdiff);
CU_ASSERT (ddsrt_atomic_ldvoidp (&uintvoidp) == (uintptr_t*)3);
/* Test ddsrt_atomic_add32_nv */
ddsrt_atomic_st32 (&uint32, 1);
CU_ASSERT (ddsrt_atomic_add32_nv (&uint32, _osuint32) == 3);
/* Test ddsrt_atomic_add64_nv */
#if DDSRT_HAVE_ATOMIC64
ddsrt_atomic_st64 (&uint64, 1);
CU_ASSERT (ddsrt_atomic_add64_nv (&uint64, _osuint64) == 3);
#endif
/* Test ddsrt_atomic_addptr_nv */
ddsrt_atomic_stptr (&uintptr, 1);
CU_ASSERT (ddsrt_atomic_addptr_nv (&uintptr, _osaddress) == 3);
/* Test ddsrt_atomic_addvoidp_nv */
ddsrt_atomic_stvoidp (&uintvoidp, (uintptr_t*)1);
CU_ASSERT (ddsrt_atomic_addvoidp_nv (&uintvoidp, _ptrdiff) == (uintptr_t*)3);
}
CU_Test(ddsrt_atomics, subtract)
{
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(5);
#if DDSRT_HAVE_ATOMIC64
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(5);
#endif
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(5);
volatile ddsrt_atomic_voidp_t uintvoidp = DDSRT_ATOMIC_VOIDP_INIT((uintptr_t)5);
_osuint32 = 2;
_osuint64 = 2;
_osaddress = 2;
_ptrdiff = 2;
/* Test ddsrt_atomic_sub32 */
ddsrt_atomic_sub32 (&uint32, _osuint32);
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 3);
/* Test ddsrt_atomic_sub64 */
#if DDSRT_HAVE_ATOMIC64
ddsrt_atomic_sub64 (&uint64, _osuint64);
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 3);
#endif
/* Test ddsrt_atomic_subptr */
ddsrt_atomic_subptr (&uintptr, _osaddress);
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 3);
/* Test ddsrt_atomic_subvoidp */
ddsrt_atomic_subvoidp (&uintvoidp, _ptrdiff);
CU_ASSERT (ddsrt_atomic_ldvoidp (&uintvoidp) == (uintptr_t*)3);
/* Test ddsrt_atomic_sub32_nv */
ddsrt_atomic_st32 (&uint32, 5);
CU_ASSERT (ddsrt_atomic_sub32_nv (&uint32, _osuint32) == 3);
/* Test ddsrt_atomic_sub64_nv */
#if DDSRT_HAVE_ATOMIC64
ddsrt_atomic_st64 (&uint64, 5);
CU_ASSERT (ddsrt_atomic_sub64_nv (&uint64, _osuint64) == 3);
#endif
/* Test ddsrt_atomic_subptr_nv */
ddsrt_atomic_stptr (&uintptr, 5);
CU_ASSERT (ddsrt_atomic_subptr_nv (&uintptr, _osaddress) == 3);
/* Test ddsrt_atomic_subvoidp_nv */
ddsrt_atomic_stvoidp (&uintvoidp, (uintptr_t*)5);
CU_ASSERT (ddsrt_atomic_subvoidp_nv (&uintvoidp, _ptrdiff) == (void *)3);
}
CU_Test(ddsrt_atomics, and)
{
/* AND Operation:
150 010010110
500 111110100
148 010010100 */
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(150);
#if DDSRT_HAVE_ATOMIC64
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(150);
#endif
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(150);
_osuint32 = 500;
_osuint64 = 500;
_osaddress = 500;
/* Test ddsrt_atomic_and32 */
ddsrt_atomic_and32 (&uint32, _osuint32);
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 148);
/* Test ddsrt_atomic_and64 */
#if DDSRT_HAVE_ATOMIC64
ddsrt_atomic_and64 (&uint64, _osuint64);
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 148);
#endif
/* Test ddsrt_atomic_andptr */
ddsrt_atomic_andptr (&uintptr, _osaddress);
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 148);
/* Test ddsrt_atomic_and32_ov */
CU_ASSERT (ddsrt_atomic_and32_ov (&uint32, _osuint32) == 148);
/* Test ddsrt_atomic_and64_ov */
#if DDSRT_HAVE_ATOMIC64
CU_ASSERT (ddsrt_atomic_and64_ov (&uint64, _osuint64) == 148);
#endif
/* Test ddsrt_atomic_andptr_ov */
CU_ASSERT (ddsrt_atomic_andptr_ov (&uintptr, _osaddress) == 148);
/* Test ddsrt_atomic_and32_nv */
CU_ASSERT (ddsrt_atomic_and32_nv (&uint32, _osuint32) == 148);
/* Test ddsrt_atomic_and64_nv */
#if DDSRT_HAVE_ATOMIC64
CU_ASSERT (ddsrt_atomic_and64_nv (&uint64, _osuint64) == 148);
#endif
/* Test ddsrt_atomic_andptr_nv */
CU_ASSERT (ddsrt_atomic_andptr_nv (&uintptr, _osaddress) == 148);
}
CU_Test(ddsrt_atomics, or)
{
/* OR Operation:
150 010010110
500 111110100
502 111110110 */
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(150);
#if DDSRT_HAVE_ATOMIC64
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(150);
#endif
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(150);
_osuint32 = 500;
_osuint64 = 500;
_osaddress = 500;
/* Test ddsrt_atomic_or32 */
ddsrt_atomic_or32 (&uint32, _osuint32);
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 502);
/* Test ddsrt_atomic_or64 */
#if DDSRT_HAVE_ATOMIC64
ddsrt_atomic_or64 (&uint64, _osuint64);
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 502);
#endif
/* Test ddsrt_atomic_orptr */
ddsrt_atomic_orptr (&uintptr, _osaddress);
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 502);
/* Test ddsrt_atomic_or32_ov */
CU_ASSERT (ddsrt_atomic_or32_ov (&uint32, _osuint32) == 502);
/* Test ddsrt_atomic_or64_ov */
#if DDSRT_HAVE_ATOMIC64
CU_ASSERT (ddsrt_atomic_or64_ov (&uint64, _osuint64) == 502);
#endif
/* Test ddsrt_atomic_orptr_ov */
CU_ASSERT (ddsrt_atomic_orptr_ov (&uintptr, _osaddress) == 502);
/* Test ddsrt_atomic_or32_nv */
CU_ASSERT (ddsrt_atomic_or32_nv (&uint32, _osuint32) == 502);
/* Test ddsrt_atomic_or64_nv */
#if DDSRT_HAVE_ATOMIC64
CU_ASSERT (ddsrt_atomic_or64_nv (&uint64, _osuint64) == 502);
#endif
/* Test ddsrt_atomic_orptr_nv */
CU_ASSERT (ddsrt_atomic_orptr_nv (&uintptr, _osaddress) == 502);
}

98
src/ddsrt/tests/environ.c Normal file
View file

@ -0,0 +1,98 @@
/*
* 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 <stdlib.h>
#include "CUnit/Theory.h"
#include "dds/ddsrt/environ.h"
#include "dds/ddsrt/misc.h"
CU_TheoryDataPoints(ddsrt_environ, bad_name) = {
CU_DataPoints(const char *, "", "foo=")
};
CU_Theory((const char *name), ddsrt_environ, bad_name)
{
dds_retcode_t rc;
static const char value[] = "bar";
static char dummy[] = "foobar";
char *ptr;
rc = ddsrt_setenv(name, value);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_BAD_PARAMETER);
rc = ddsrt_unsetenv(name);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_BAD_PARAMETER);
ptr = dummy;
rc = ddsrt_getenv(name, &ptr);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_BAD_PARAMETER);
CU_ASSERT_PTR_EQUAL(ptr, dummy);
}
DDSRT_WARNING_MSVC_OFF(4996)
CU_Test(ddsrt_environ, setenv)
{
dds_retcode_t rc;
static const char name[] = "foo";
static char value[] = "bar";
char *ptr;
rc = ddsrt_setenv(name, value);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
ptr = getenv(name);
CU_ASSERT_PTR_NOT_NULL(ptr);
CU_ASSERT_STRING_EQUAL(ptr, "bar");
/* Ensure value is copied into the environment. */
value[2] = 'z';
ptr = getenv(name);
CU_ASSERT_PTR_NOT_NULL(ptr);
CU_ASSERT_STRING_EQUAL(ptr, "bar");
rc = ddsrt_setenv(name, "");
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
ptr = getenv(name);
CU_ASSERT_PTR_NULL(ptr);
}
DDSRT_WARNING_MSVC_ON(4996)
CU_Test(ddsrt_environ, getenv)
{
dds_retcode_t rc;
static const char name[] = "foo";
static const char value[] = "bar";
static char dummy[] = "foobar";
char *ptr;
/* Ensure "not found" is returned. */
rc = ddsrt_unsetenv(name);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
ptr = dummy;
rc = ddsrt_getenv(name, &ptr);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_NOT_FOUND);
CU_ASSERT_PTR_EQUAL(ptr, dummy);
/* Ensure "ok" is returned and value is what it should be. */
rc = ddsrt_setenv(name, value);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
ptr = dummy;
rc = ddsrt_getenv(name, &ptr);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
CU_ASSERT_PTR_NOT_EQUAL(ptr, dummy);
CU_ASSERT_PTR_NOT_EQUAL(ptr, NULL);
if (ptr != NULL) {
CU_ASSERT_STRING_EQUAL(ptr, "bar");
}
/* Ensure environement is as it was. */
rc = ddsrt_unsetenv(name);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
}

156
src/ddsrt/tests/heap.c Normal file
View file

@ -0,0 +1,156 @@
/*
* 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 <stdio.h>
#include "CUnit/Test.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/heap.h"
CU_Init(ddsrt_heap)
{
ddsrt_init();
return 0;
}
CU_Clean(ddsrt_heap)
{
ddsrt_fini();
return 0;
}
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;
CU_Test(ddsrt_heap, malloc)
{
for(size_t i = 0; i < nof_allocsizes; i++) {
for(size_t j = 0; j < nof_allocsizes; j++) {
size_t s = allocsizes[i] * allocsizes[j]; /* Allocates up to 1MB */
void *ptr = ddsrt_malloc(s);
CU_ASSERT_PTR_NOT_EQUAL(ptr, NULL); /* ddsrt_malloc is supposed to abort on failure */
memset(ptr, 0, s); /* This potentially segfaults if the actual allocated block is too small */
ddsrt_free(ptr);
}
}
CU_PASS("ddsrt_malloc");
}
CU_Test(ddsrt_heap, calloc)
{
for(size_t i = 0; i < nof_allocsizes; i++) {
for(size_t j = 0; j < nof_allocsizes; j++) {
char *ptr = ddsrt_calloc(allocsizes[i], allocsizes[j]);
CU_ASSERT_PTR_NOT_EQUAL(ptr, NULL); /* ddsrt_calloc is supposed to abort on failure */
if(allocsizes[i] * allocsizes[j] > 0) {
CU_ASSERT (ptr[0] == 0 && !memcmp(ptr, ptr + 1, (allocsizes[i] * allocsizes[j]) - 1)); /* ddsrt_calloc should memset properly */
}
ddsrt_free(ptr);
}
}
CU_PASS("ddsrt_calloc");
}
CU_Test(ddsrt_heap, realloc)
{
char *ptr = NULL;
size_t unchanged, s, prevs = 0;
for(size_t i = 0; i < nof_allocsizes; i++) {
for(size_t j = 0; j < nof_allocsizes; j++) {
s = allocsizes[i] * allocsizes[j]; /* Allocates up to 1MB */
printf("ddsrt_realloc(%p) %zu -> %zu\n", ptr, prevs, s);
ptr = ddsrt_realloc(ptr, s);
CU_ASSERT_PTR_NOT_EQUAL(ptr, NULL); /* ddsrt_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)); /* ddsrt_realloc shouldn't change memory */
}
memset(ptr, 1, s); /* This potentially segfaults if the actual allocated block is too small */
prevs = s;
}
}
ddsrt_free(ptr);
CU_PASS("ddsrt_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;
CU_Test(ddsrt_heap, malloc_s)
{
for(size_t i = 0; i < nof_allocsizes_s; i++) {
for(size_t j = 0; j < nof_allocsizes_s; j++) {
size_t s = allocsizes_s[i] * allocsizes_s[j]; /* Allocates up to 8MB */
void *ptr = ddsrt_malloc_s(s); /* If s == 0, ddsrt_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("ddsrt_malloc_s(<=16) returned NULL");
}
ddsrt_free(ptr);
}
}
CU_PASS("ddsrt_malloc_s");
}
CU_Test(ddsrt_heap, calloc_s)
{
for(size_t i = 0; i < nof_allocsizes_s; i++) {
for(size_t j = 0; j < nof_allocsizes_s; j++) {
size_t s = allocsizes_s[i] * allocsizes_s[j];
char *ptr = ddsrt_calloc_s(allocsizes_s[i], allocsizes_s[j]); /* If either one is 0, ddsrt_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("ddsrt_calloc_s(<=16) returned NULL");
}
ddsrt_free(ptr);
}
}
CU_PASS("ddsrt_calloc_s");
}
CU_Test(ddsrt_heap, ddsrt_realloc_s)
{
char *newptr, *ptr = NULL;
size_t unchanged, s, prevs = 0;
for(size_t i = 0; i < nof_allocsizes_s; i++) {
for(size_t j = 0; j < nof_allocsizes_s; j++) {
s = allocsizes_s[i] * allocsizes_s[j]; /* Allocates up to 8MB */
newptr = ddsrt_realloc_s(ptr, s);
printf("%p = ddsrt_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 ddsrt_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)); /* ddsrt_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;
}
}
ddsrt_free(ptr);
CU_PASS("ddsrt_realloc_s");
}

187
src/ddsrt/tests/ifaddrs.c Normal file
View file

@ -0,0 +1,187 @@
/*
* 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/Test.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/ifaddrs.h"
#include "dds/ddsrt/retcode.h"
/* FIXME: It's not possible to predict what network interfaces are available
on a given host. To properly test all combinations the abstracted
operating system functions must be mocked. */
/* FIXME: It's possible that IPv6 is available in the network stack, but
disabled in the kernel. Travis CI for example has build environments
that do not have IPv6 enabled. */
#ifdef DDSRT_HAVE_IPV6
static int ipv6_enabled = 1;
#endif
CU_Init(ddsrt_getifaddrs)
{
ddsrt_init();
#ifdef DDSRT_HAVE_IPV6
#ifdef __linux
FILE *fh;
const char *const *path;
static const char *const paths[] = {
"/proc/sys/net/ipv6/conf/all/disable_ipv6",
"/proc/sys/net/ipv6/conf/default/disable_ipv6",
NULL
};
for (path = paths; ipv6_enabled == 1 && *path != NULL; path++) {
if ((fh = fopen(*path, "r")) != NULL) {
ipv6_enabled = (fgetc(fh) == '0');
fclose(fh);
fh = NULL;
}
}
#endif /* __linux */
#endif /* DDSRT_HAVE_IPV6 */
return 0;
}
CU_Clean(ddsrt_getifaddrs)
{
ddsrt_fini();
return 0;
}
/* Assume every test machine has at least one IPv4 enabled interface. This
simple test verifies an interface can at least be found and that the
IFF_LOOPBACK flags are properly set. */
CU_Test(ddsrt_getifaddrs, ipv4)
{
dds_retcode_t ret;
int seen = 0;
ddsrt_ifaddrs_t *ifa_root, *ifa;
const int afs[] = { AF_INET, DDSRT_AF_TERM };
ret = ddsrt_getifaddrs(&ifa_root, afs);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
for (ifa = ifa_root; ifa; ifa = ifa->next) {
CU_ASSERT_PTR_NOT_EQUAL_FATAL(ifa->addr, NULL);
CU_ASSERT_EQUAL(ifa->addr->sa_family, AF_INET);
if (ifa->addr->sa_family == AF_INET) {
if (ifa->flags & IFF_LOOPBACK) {
CU_ASSERT(ddsrt_sockaddr_isloopback(ifa->addr));
} else {
CU_ASSERT(!ddsrt_sockaddr_isloopback(ifa->addr));
}
seen = 1;
}
}
CU_ASSERT_EQUAL(seen, 1);
ddsrt_freeifaddrs(ifa_root);
}
CU_Test(ddsrt_getifaddrs, null_filter)
{
dds_retcode_t ret;
int cnt = 0;
ddsrt_ifaddrs_t *ifa_root, *ifa;
ret = ddsrt_getifaddrs(&ifa_root, NULL);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
for (ifa = ifa_root; ifa; ifa = ifa->next) {
CU_ASSERT_PTR_NOT_EQUAL_FATAL(ifa->addr, NULL);
cnt++;
}
CU_ASSERT(cnt > 0);
ddsrt_freeifaddrs(ifa_root);
}
CU_Test(ddsrt_getifaddrs, empty_filter)
{
dds_retcode_t ret;
ddsrt_ifaddrs_t *ifa_root;
const int afs[] = { DDSRT_AF_TERM };
ret = ddsrt_getifaddrs(&ifa_root, afs);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
CU_ASSERT_PTR_EQUAL(ifa_root, NULL);
ddsrt_freeifaddrs(ifa_root);
}
#ifdef DDSRT_HAVE_IPV6
CU_Test(ddsrt_getifaddrs, ipv6)
{
if (ipv6_enabled == 1) {
dds_retcode_t ret;
int have_ipv6 = 0;
ddsrt_ifaddrs_t *ifa_root, *ifa;
const int afs[] = { AF_INET6, DDSRT_AF_TERM };
ret = ddsrt_getifaddrs(&ifa_root, afs);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
for (ifa = ifa_root; ifa; ifa = ifa->next) {
CU_ASSERT_PTR_NOT_EQUAL_FATAL(ifa->addr, NULL);
CU_ASSERT_EQUAL(ifa->addr->sa_family, AF_INET6);
if (ifa->addr->sa_family == AF_INET6) {
have_ipv6 = 1;
/* macOS assigns a link-local address to the loopback interface, so
the loopback address must be assigned to the loopback interface,
but the loopback interface can have addresses other than the
loopback address assigned. */
if (ddsrt_sockaddr_isloopback(ifa->addr)) {
CU_ASSERT(ifa->flags & IFF_LOOPBACK);
}
}
}
CU_ASSERT_EQUAL(have_ipv6, 1);
ddsrt_freeifaddrs(ifa_root);
CU_PASS("IPv6 enabled in test environment");
} else {
CU_PASS("IPv6 disabled in test environment");
}
}
/* Assume at least one IPv4 and one IPv6 interface are available when IPv6 is
available on the platform. */
CU_Test(ddsrt_getifaddrs, ipv4_n_ipv6)
{
if (ipv6_enabled == 1) {
dds_retcode_t ret;
int have_ipv4 = 0;
int have_ipv6 = 0;
ddsrt_ifaddrs_t *ifa_root, *ifa;
const int afs[] = { AF_INET, AF_INET6, DDSRT_AF_TERM };
ret = ddsrt_getifaddrs(&ifa_root, afs);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
for (ifa = ifa_root; ifa; ifa = ifa->next) {
CU_ASSERT_PTR_NOT_EQUAL_FATAL(ifa->addr, NULL);
CU_ASSERT(ifa->addr->sa_family == AF_INET ||
ifa->addr->sa_family == AF_INET6);
if (ifa->addr->sa_family == AF_INET) {
have_ipv4 = 1;
} else if (ifa->addr->sa_family == AF_INET6) {
have_ipv6 = 1;
}
}
CU_ASSERT_EQUAL(have_ipv4, 1);
CU_ASSERT_EQUAL(have_ipv6, 1);
ddsrt_freeifaddrs(ifa_root);
CU_PASS("IPv6 enabled in test environment");
} else {
CU_PASS("IPv6 disabled in test environment");
}
}
#endif /* DDSRT_HAVE_IPV6 */

366
src/ddsrt/tests/log.c Normal file
View file

@ -0,0 +1,366 @@
/*
* 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 <errno.h>
#include <stdio.h>
#include <string.h>
#ifdef __APPLE__
#include <pthread.h>
#endif /* __APPLE__ */
#include "CUnit/Test.h"
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/string.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/threads.h"
#include "dds/ddsrt/time.h"
static FILE *fh = NULL;
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
/* Windows does not support opening a stream to a buffer like fmemopen on
* Linux does. A temporary file that will never be flushed to disk is created
* instead. See the link below for more detail.
*
* https://blogs.msdn.microsoft.com/larryosterman/2004/04/19/its-only-temporary/
*/
FILE *fmemopen(void *buf, size_t size, const char *mode)
{
int err = 0;
int fd = -1;
DWORD ret;
FILE *fh = NULL;
HANDLE hdl = INVALID_HANDLE_VALUE;
/* GetTempFileName will fail if the directory is be longer than MAX_PATH-14
characters */
char tmpdir[(MAX_PATH + 1) - 14];
char tmpfile[MAX_PATH + 1];
static const int max = 1000;
static const char pfx[] = "cyclone"; /* Up to first three are used. */
(void)buf;
(void)size;
ret = GetTempPath(sizeof(tmpdir), tmpdir);
if (ret == 0) {
err = GetLastError();
} else if (ret > sizeof(tmpdir)) {
err = ENOMEM;
}
if (GetTempFileName(tmpdir, pfx, 0, tmpfile) == 0) {
err = GetLastError();
assert(err != ERROR_BUFFER_OVERFLOW);
} else {
/* The combination of FILE_ATTRIBUTE_TEMPORARY and
FILE_FLAG_DELETE_ON_CLOSE hints to the filesystem that the file should
never be flushed to disk. */
hdl = CreateFile(
tmpfile,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY,
NULL);
if (hdl == INVALID_HANDLE_VALUE) {
err = GetLastError();
}
}
if (err) {
errno = err;
} else {
DDSRT_WARNING_MSVC_OFF(4996);
if ((fd = _open_osfhandle((intptr_t)hdl, _O_APPEND)) == -1) {
/* errno set by _open_osfhandle. */
CloseHandle(hdl);
} else if ((fh = fdopen(fd, mode)) == NULL) {
/* errno set by fdopen. */
_close(fd); /* Automatically closes underlying handle. */
} else {
return fh;
}
DDSRT_WARNING_MSVC_ON(4996);
}
return NULL;
}
#endif /* _WIN32 */
static void count(void *ptr, const dds_log_data_t *data)
{
(void)data;
*(int *)ptr += 1;
}
static void copy(void *ptr, const dds_log_data_t *data)
{
*(char **)ptr = ddsrt_strdup(data->message);
}
static void setup(void)
{
fh = fmemopen(NULL, 1024, "wb+");
CU_ASSERT_PTR_NOT_NULL_FATAL(fh);
}
static void teardown(void)
{
(void)fclose(fh);
}
/* By default only DDS_LC_FATAL and DDS_LC_ERROR are set. This means setting a
trace sink should not have any effect, because no trace categories are
enabled. The message should end up in the log file. */
CU_Test(dds_log, only_log_file, .init=setup, .fini=teardown)
{
char buf[1024], *ptr;
int cnt = 0;
size_t nbytes;
dds_set_log_file(fh);
dds_set_trace_sink(&count, &cnt);
DDS_ERROR("foo%s\n", "bar");
(void)fseek(fh, 0L, SEEK_SET);
nbytes = fread(buf, 1, sizeof(buf) - 1, fh);
/* At least foobar should have been printed to the log file. */
CU_ASSERT_FATAL(nbytes > 6);
buf[nbytes] = '\0';
ptr = strstr(buf, "foobar\n");
CU_ASSERT_PTR_NOT_NULL(ptr);
/* No trace categories are enabled by default, verify trace callback was
not invoked. */
CU_ASSERT_EQUAL(cnt, 0);
}
/* Messages must be printed to the trace file if at least one trace category
is enabled. Messages must not be written twice if the trace file is the
same as the log file. */
CU_Test(dds_log, same_file, .init=setup, .fini=teardown)
{
char buf[1024], *ptr;
size_t nbytes;
dds_set_log_mask(DDS_LC_ALL);
dds_set_log_file(fh);
dds_set_trace_file(fh);
DDS_ERROR("foo%s\n", "bar");
(void)fseek(fh, 0L, SEEK_SET);
nbytes = fread(buf, 1, sizeof(buf) - 1, fh);
/* At least foobar should have been written to the trace file. */
CU_ASSERT_FATAL(nbytes > 6);
buf[nbytes] = '\0';
ptr = strstr(buf, "foobar\n");
CU_ASSERT_PTR_NOT_NULL_FATAL(ptr);
/* The message should only have been printed once, verify foobar does not
occur again. */
ptr = strstr(ptr + 1, "foobar\n");
CU_ASSERT_PTR_NULL(ptr);
}
/* The sinks are considered to be the same only if the callback and userdata
both are an exact match. If the userdata is different, the function should
be called twice for log messages. */
CU_Test(dds_log, same_sink_function)
{
int log_cnt = 0, trace_cnt = 0;
dds_set_log_mask(DDS_LC_ALL);
dds_set_log_sink(&count, &log_cnt);
dds_set_trace_sink(&count, &trace_cnt);
DDS_ERROR("foo%s\n", "bar");
CU_ASSERT_EQUAL(log_cnt, 1);
CU_ASSERT_EQUAL(trace_cnt, 1);
}
CU_Test(dds_log, exact_same_sink)
{
int cnt = 0;
dds_set_log_mask(DDS_LC_ALL);
dds_set_log_sink(&count, &cnt);
dds_set_trace_sink(&count, &cnt);
DDS_ERROR("foo%s\n", "bar");
CU_ASSERT_EQUAL(cnt, 1);
}
/* The log file must be restored if the sink is unregistered, verify the log
file is not used while the sink is registered. Verify use of the log file is
restored again when the sink is unregistered. */
CU_Test(dds_log, no_sink, .init=setup, .fini=teardown)
{
int ret;
char buf[1024], *ptr = NULL;
size_t cnt[2] = {0, 0};
/* Set the destination log file and verify the message is written. */
dds_set_log_file(fh);
DDS_ERROR("foobar\n");
ret = fseek(fh, 0L, SEEK_SET);
CU_ASSERT_EQUAL_FATAL(ret, 0);
buf[0] = '\0';
cnt[0] = fread(buf, 1, sizeof(buf) - 1, fh);
buf[cnt[0]] = '\0';
ptr = strstr(buf, "foobar\n");
CU_ASSERT_PTR_NOT_NULL_FATAL(ptr);
/* Register a custom sink and verify it receives the message. */
ptr = NULL;
dds_set_log_sink(&copy, &ptr);
DDS_ERROR("foobaz\n");
CU_ASSERT_PTR_NOT_NULL_FATAL(ptr);
CU_ASSERT(strcmp(ptr, "foobaz\n") == 0);
ddsrt_free(ptr);
ptr = NULL;
/* Verify it has not been written to the stream. */
ret = fseek(fh, 0L, SEEK_SET);
CU_ASSERT_EQUAL_FATAL(ret, 0);
buf[0] = '\0';
cnt[1] = fread(buf, 1, sizeof(buf) - 1, fh);
buf[cnt[1]] = '\0';
ptr = strstr(buf, "foobaz\n");
CU_ASSERT_PTR_NULL_FATAL(ptr);
/* Unregister the custom sink and verify the default is restored. */
dds_set_log_sink(0, NULL);
ret = fseek(fh, 0, SEEK_SET);
CU_ASSERT_EQUAL_FATAL(ret, 0);
ptr = NULL;
DDS_ERROR("foobaz\n");
ret = fseek(fh, 0, SEEK_SET);
CU_ASSERT_PTR_NULL(ptr);
if (ptr != NULL) {
ddsrt_free(ptr);
ptr = NULL;
}
buf[0]= '\0';
cnt[1] = fread(buf, 1, sizeof(buf) - 1, fh);
#ifdef _WIN32
/* Write on Windows appends. */
CU_ASSERT_EQUAL(cnt[1], cnt[0] * 2);
#else
CU_ASSERT_EQUAL(cnt[1], cnt[0]);
#endif
buf[cnt[1]] = '\0';
ptr = strstr(buf, "foobaz\n");
CU_ASSERT_PTR_NOT_NULL_FATAL(ptr);
}
/* A newline terminates the message. Until that a newline is encountered, the
messages must be concatenated in the buffer. The newline is replaced by a
NULL byte if it is flushed to a sink. */
CU_Test(dds_log, newline_terminates)
{
char *msg = NULL;
dds_set_log_sink(&copy, &msg);
DDS_ERROR("foo");
CU_ASSERT_PTR_NULL_FATAL(msg);
DDS_ERROR("bar");
CU_ASSERT_PTR_NULL_FATAL(msg);
DDS_ERROR("baz\n");
CU_ASSERT_PTR_NOT_NULL_FATAL(msg);
CU_ASSERT(strcmp(msg, "foobarbaz\n") == 0);
ddsrt_free(msg);
}
/* Nothing must be written unless a category is enabled. */
CU_Test(dds_log, disabled_categories_discarded)
{
char *msg = NULL;
dds_set_log_sink(&copy, &msg);
DDS_INFO("foobar\n");
CU_ASSERT_PTR_NULL_FATAL(msg);
dds_set_log_mask(DDS_LC_FATAL | DDS_LC_ERROR | DDS_LC_INFO);
DDS_INFO("foobar\n");
CU_ASSERT_PTR_NOT_NULL_FATAL(msg);
CU_ASSERT(strcmp(msg, "foobar\n") == 0);
ddsrt_free(msg);
}
static ddsrt_cond_t cond;
static ddsrt_mutex_t mutex;
struct arg {
ddsrt_cond_t *cond;
ddsrt_mutex_t *mutex;
dds_time_t stamp;
dds_duration_t pause;
};
static void dummy(void *ptr, const dds_log_data_t *data)
{
(void)ptr;
(void)data;
}
static void block(void *ptr, const dds_log_data_t *data)
{
(void)data;
struct arg *arg = (struct arg *)ptr;
ddsrt_mutex_lock(arg->mutex);
arg->stamp = dds_time();
ddsrt_cond_broadcast(arg->cond);
ddsrt_mutex_unlock(arg->mutex);
dds_sleepfor(arg->pause);
}
static uint32_t run(void *ptr)
{
(void)ptr;
DDS_ERROR("foobar\n");
return 0;
}
/* Log and trace sinks can be changed at runtime. However, the operation must
be synchronous! Verify the dds_set_log_sink blocks while other threads
reside in the log or trace sinks. */
CU_Test(dds_log, synchronous_sink_changes)
{
struct arg arg;
dds_time_t diff, stamp;
ddsrt_thread_t tid;
ddsrt_threadattr_t tattr;
dds_retcode_t ret;
ddsrt_mutex_init(&mutex);
ddsrt_cond_init(&cond);
(void)memset(&arg, 0, sizeof(arg));
arg.mutex = &mutex;
arg.cond = &cond;
arg.pause = 1000000;
ddsrt_mutex_lock(&mutex);
dds_set_log_sink(&block, &arg);
ddsrt_threadattr_init(&tattr);
ret = ddsrt_thread_create(&tid, "foobar", &tattr, &run, &arg);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
ddsrt_cond_wait(&cond, &mutex);
dds_set_log_sink(dummy, NULL);
stamp = dds_time();
CU_ASSERT(arg.stamp < stamp);
diff = stamp - arg.stamp;
CU_ASSERT(arg.pause < diff);
}

325
src/ddsrt/tests/select.c Normal file
View file

@ -0,0 +1,325 @@
/*
* 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/Theory.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/sockets_priv.h"
#include "dds/ddsrt/threads.h"
CU_Init(ddsrt_select)
{
ddsrt_init();
return 0;
}
CU_Clean(ddsrt_select)
{
ddsrt_fini();
return 0;
}
static struct timeval tv_init = { .tv_sec = -2, .tv_usec = -2 };
#define CU_ASSERT_TIMEVAL_EQUAL(tv, secs, usecs) \
CU_ASSERT((tv.tv_sec == secs) && (tv.tv_usec == usecs))
/* Simple test to validate that duration to timeval conversion is correct. */
CU_Test(ddsrt_select, duration_to_timeval)
{
struct timeval tv, *tvptr;
dds_duration_t nsecs_max;
dds_duration_t secs_max = DDSRT_MAX_INTEGER(ddsrt_tv_sec_t);
dds_duration_t usecs_max = 999999;
if (DDS_INFINITY > secs_max) {
CU_ASSERT_EQUAL_FATAL(secs_max, INT32_MAX);
nsecs_max = DDS_INFINITY * secs_max;
} else {
CU_ASSERT_EQUAL_FATAL(secs_max, DDS_INFINITY);
nsecs_max = DDS_INFINITY / DDS_NSECS_IN_SEC;
}
tv = tv_init;
tvptr = ddsrt_duration_to_timeval_ceil(INT64_MIN, &tv);
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
CU_ASSERT_TIMEVAL_EQUAL(tv, 0, 0);
tv = tv_init;
tvptr = ddsrt_duration_to_timeval_ceil(INT64_MIN + 1, &tv);
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
CU_ASSERT_TIMEVAL_EQUAL(tv, 0, 0);
tv = tv_init;
tvptr = ddsrt_duration_to_timeval_ceil(-2, &tv);
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
CU_ASSERT_TIMEVAL_EQUAL(tv, 0, 0);
tv = tv_init;
tvptr = ddsrt_duration_to_timeval_ceil(-1, &tv);
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
CU_ASSERT_TIMEVAL_EQUAL(tv, 0, 0);
tv = tv_init;
tvptr = ddsrt_duration_to_timeval_ceil(0, &tv);
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
CU_ASSERT_TIMEVAL_EQUAL(tv, 0, 0);
tv = tv_init;
tvptr = ddsrt_duration_to_timeval_ceil(nsecs_max - 1, &tv);
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
CU_ASSERT_TIMEVAL_EQUAL(tv, secs_max, usecs_max);
tv = tv_init;
tvptr = ddsrt_duration_to_timeval_ceil(nsecs_max, &tv);
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
CU_ASSERT_TIMEVAL_EQUAL(tv, secs_max, usecs_max);
tv = tv_init;
tvptr = ddsrt_duration_to_timeval_ceil(nsecs_max + 1, &tv);
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
CU_ASSERT_TIMEVAL_EQUAL(tv, secs_max, usecs_max);
tv = tv_init;
tvptr = ddsrt_duration_to_timeval_ceil(DDS_INFINITY - 1, &tv);
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
CU_ASSERT_TIMEVAL_EQUAL(tv, secs_max, usecs_max);
tv = tv_init;
tvptr = ddsrt_duration_to_timeval_ceil(DDS_INFINITY, &tv);
CU_ASSERT_PTR_EQUAL(tvptr, NULL);
CU_ASSERT_TIMEVAL_EQUAL(tv, 0, 0);
}
typedef struct {
dds_duration_t delay;
dds_duration_t skew;
ddsrt_socket_t sock;
} thread_arg_t;
static void
sockets_pipe(ddsrt_socket_t socks[2])
{
dds_retcode_t rc;
ddsrt_socket_t sock;
int reuseaddr = 1;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = htons(54321);
CU_ASSERT_PTR_NOT_NULL_FATAL(socks);
rc = ddsrt_socket(&sock, AF_INET, SOCK_STREAM, 0);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
rc = ddsrt_setsockopt(
sock, SOL_SOCKET, SO_REUSEADDR, (void*)&reuseaddr, sizeof(reuseaddr));
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
rc = ddsrt_socket(&socks[1], AF_INET, SOCK_STREAM, 0);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
rc = ddsrt_bind(sock, (struct sockaddr *)&addr, sizeof(addr));
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
rc = ddsrt_listen(sock, 1);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
rc = ddsrt_connect(socks[1], (struct sockaddr *)&addr, sizeof(addr));
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
rc = ddsrt_accept(sock, NULL, NULL, &socks[0]);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
ddsrt_close(sock);
}
static const char mesg[] = "foobar";
static uint32_t select_timeout_routine(void *ptr)
{
int cnt = -1;
dds_retcode_t rc;
dds_time_t before, after;
dds_duration_t delay;
fd_set rdset;
thread_arg_t *arg = (thread_arg_t *)ptr;
uint32_t res = 0;
FD_ZERO(&rdset);
FD_SET(arg->sock, &rdset);
before = dds_time();
rc = ddsrt_select(arg->sock + 1, &rdset, NULL, NULL, arg->delay, &cnt);
after = dds_time();
delay = after - before;
fprintf(stderr, "Waited for %"PRId64" (nanoseconds)\n", delay);
fprintf(stderr, "Expected to wait %"PRId64" (nanoseconds)\n", arg->delay);
fprintf(stderr, "ddsrt_select returned %d\n", rc);
fprintf(stderr, "ddsrt_select reported %d ready\n", cnt);
if (rc == DDS_RETCODE_TIMEOUT) {
res = (((after - delay) >= (arg->delay - arg->skew)) && (cnt == 0));
}
return res;
}
CU_Test(ddsrt_select, timeout)
{
dds_retcode_t rc;
ddsrt_socket_t socks[2];
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
thread_arg_t arg;
uint32_t res = 0;
sockets_pipe(socks);
arg.delay = DDS_MSECS(100);
/* Allow the delay to be off by x microseconds (arbitrarily chosen) for
systems with a really poor clock. This test is just to get some
confidence that time calculation is not completely broken, it is by
no means proof that time calculation is entirely correct! */
arg.skew = DDS_MSECS(20);
arg.sock = socks[0];
ddsrt_threadattr_init(&attr);
rc = ddsrt_thread_create(&thr, "select_timeout", &attr, &select_timeout_routine, &arg);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
/* Allow the thread some time to get ready. */
dds_sleepfor(arg.delay * 2);
/* Send data to the read socket to avoid blocking indefinitely. */
ssize_t sent = 0;
rc = ddsrt_send(socks[1], mesg, sizeof(mesg), 0, &sent);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
rc = ddsrt_thread_join(thr, &res);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(res, 1);
(void)ddsrt_close(socks[0]);
(void)ddsrt_close(socks[1]);
}
static uint32_t recv_routine(void *ptr)
{
thread_arg_t *arg = (thread_arg_t*)ptr;
int nfds = 0;
fd_set rdset;
ssize_t rcvd = -1;
char buf[sizeof(mesg)];
FD_ZERO(&rdset);
FD_SET(arg->sock, &rdset);
(void)ddsrt_select(arg->sock + 1, &rdset, NULL, NULL, arg->delay, &nfds);
if (ddsrt_recv(arg->sock, buf, sizeof(buf), 0, &rcvd) == DDS_RETCODE_OK) {
return (rcvd == sizeof(mesg) && strcmp(buf, mesg) == 0);
}
return 0;
}
CU_Test(ddsrt_select, send_recv)
{
dds_retcode_t rc;
ddsrt_socket_t socks[2];
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
thread_arg_t arg;
uint32_t res = 0;
sockets_pipe(socks);
arg.delay = DDS_SECS(1);
arg.skew = 0;
arg.sock = socks[0];
ddsrt_threadattr_init(&attr);
rc = ddsrt_thread_create(&thr, "recv", &attr, &recv_routine, &arg);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
ssize_t sent = 0;
rc = ddsrt_send(socks[1], mesg, sizeof(mesg), 0, &sent);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(sent, sizeof(mesg));
rc = ddsrt_thread_join(thr, &res);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(res, 1);
(void)ddsrt_close(socks[0]);
(void)ddsrt_close(socks[1]);
}
static uint32_t recvmsg_routine(void *ptr)
{
thread_arg_t *arg = (thread_arg_t*)ptr;
int nfds = 0;
fd_set rdset;
ssize_t rcvd = -1;
char buf[sizeof(mesg)];
ddsrt_msghdr_t msg;
ddsrt_iovec_t iov;
memset(&msg, 0, sizeof(msg));
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
FD_ZERO(&rdset);
FD_SET(arg->sock, &rdset);
(void)ddsrt_select(arg->sock + 1, &rdset, NULL, NULL, arg->delay, &nfds);
if (ddsrt_recvmsg(arg->sock, &msg, 0, &rcvd) == DDS_RETCODE_OK) {
return (rcvd == sizeof(mesg) && strcmp(buf, mesg) == 0);
}
return 0;
}
CU_Test(ddsrt_select, sendmsg_recvmsg)
{
dds_retcode_t rc;
ddsrt_socket_t socks[2];
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
thread_arg_t arg;
uint32_t res = 0;
sockets_pipe(socks);
memset(&arg, 0, sizeof(arg));
arg.sock = socks[0];
ddsrt_threadattr_init(&attr);
rc = ddsrt_thread_create(&thr, "recvmsg", &attr, &recvmsg_routine, &arg);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
ssize_t sent = 0;
ddsrt_msghdr_t msg;
ddsrt_iovec_t iov;
memset(&msg, 0, sizeof(msg));
iov.iov_base = (void*)mesg;
iov.iov_len = (ddsrt_iov_len_t)sizeof(mesg);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
rc = ddsrt_sendmsg(socks[1], &msg, 0, &sent);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(sent, sizeof(mesg));
rc = ddsrt_thread_join(thr, &res);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(res, 1);
(void)ddsrt_close(socks[0]);
(void)ddsrt_close(socks[1]);
}

198
src/ddsrt/tests/socket.c Normal file
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
*/
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "CUnit/Theory.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/endian.h"
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/sockets.h"
DDSRT_WARNING_MSVC_OFF(4305)
#if DDSRT_ENDIAN == DDSRT_BIG_ENDIAN
static const struct sockaddr_in ipv4_loopback =
{ .sin_family = AF_INET, .sin_addr = { .s_addr = 0x7f000001 } };
#else
static const struct sockaddr_in ipv4_loopback =
{ .sin_family = AF_INET, .sin_addr = { .s_addr = 0x0100007f } };
#endif /* DDSRT_ENDIAN */
DDSRT_WARNING_MSVC_ON(4305)
#if DDSRT_HAVE_IPV6
static const struct sockaddr_in6 ipv6_loopback =
{ .sin6_family = AF_INET6, .sin6_addr = IN6ADDR_LOOPBACK_INIT };
#endif
static void setup(void)
{
ddsrt_init();
}
static void teardown(void)
{
ddsrt_fini();
}
CU_Test(ddsrt_sockaddrfromstr, bad_family)
{
dds_retcode_t rc;
struct sockaddr_storage sa;
rc = ddsrt_sockaddrfromstr(AF_UNSPEC, "127.0.0.1", &sa);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_BAD_PARAMETER);
}
static void sockaddrfromstr_test(char *str, int af, dds_retcode_t exp)
{
dds_retcode_t rc;
struct sockaddr_storage ss;
rc = ddsrt_sockaddrfromstr(af, str, &ss);
CU_ASSERT_EQUAL(rc, exp);
if (rc == DDS_RETCODE_OK) {
CU_ASSERT_EQUAL(ss.ss_family, af);
}
}
CU_TheoryDataPoints(ddsrt_sockaddrfromstr, ipv4) = {
CU_DataPoints(char *, "127.0.0.1", "0.0.0.0",
"nip"),
CU_DataPoints(int, AF_INET, AF_INET,
AF_INET),
CU_DataPoints(dds_retcode_t, DDS_RETCODE_OK, DDS_RETCODE_OK,
DDS_RETCODE_BAD_PARAMETER)
};
CU_Theory((char *str, int af, dds_retcode_t exp), ddsrt_sockaddrfromstr, ipv4, .init=setup, .fini=teardown)
{
sockaddrfromstr_test(str, af, exp);
}
#if DDSRT_HAVE_IPV6
CU_TheoryDataPoints(ddsrt_sockaddrfromstr, ipv6) = {
CU_DataPoints(char *, "127.0.0.1", "::1",
"::1", "::",
"nip"),
CU_DataPoints(int, AF_INET6, AF_INET6,
AF_INET, AF_INET6,
AF_INET6),
CU_DataPoints(dds_retcode_t, DDS_RETCODE_BAD_PARAMETER, DDS_RETCODE_OK,
DDS_RETCODE_BAD_PARAMETER, DDS_RETCODE_OK,
DDS_RETCODE_BAD_PARAMETER)
};
CU_Theory((char *str, int af, dds_retcode_t exp), ddsrt_sockaddrfromstr, ipv6, .init=setup, .fini=teardown)
{
sockaddrfromstr_test(str, af, exp);
}
#endif /* DDSRT_HAVE_IPV6 */
CU_Test(ddsrt_sockaddrtostr, bad_sockaddr, .init=setup, .fini=teardown)
{
dds_retcode_t rc;
char buf[128] = { 0 };
struct sockaddr_in sa;
memcpy(&sa, &ipv4_loopback, sizeof(ipv4_loopback));
sa.sin_family = AF_UNSPEC;
rc = ddsrt_sockaddrtostr(&sa, buf, sizeof(buf));
CU_ASSERT_EQUAL(rc, DDS_RETCODE_BAD_PARAMETER);
}
CU_Test(ddsrt_sockaddrtostr, no_space, .init=setup, .fini=teardown)
{
dds_retcode_t rc;
char buf[1] = { 0 };
rc = ddsrt_sockaddrtostr(&ipv4_loopback, buf, sizeof(buf));
CU_ASSERT_EQUAL(rc, DDS_RETCODE_NOT_ENOUGH_SPACE);
}
CU_Test(ddsrt_sockaddrtostr, ipv4)
{
dds_retcode_t rc;
char buf[128] = { 0 };
rc = ddsrt_sockaddrtostr(&ipv4_loopback, buf, sizeof(buf));
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
CU_ASSERT_STRING_EQUAL(buf, "127.0.0.1");
}
CU_Test(ddsrt_sockaddrtostr, ipv6)
{
dds_retcode_t rc;
char buf[128] = { 0 };
rc = ddsrt_sockaddrtostr(&ipv6_loopback, buf, sizeof(buf));
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
CU_ASSERT_STRING_EQUAL(buf, "::1");
}
CU_Test(ddsrt_sockets, gethostname)
{
int ret;
dds_retcode_t rc;
char sysbuf[200], buf[200];
buf[0] = '\0';
rc = ddsrt_gethostname(buf, sizeof(buf));
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
sysbuf[0] = '\0';
ret = gethostname(sysbuf, sizeof(sysbuf));
CU_ASSERT_EQUAL(ret, 0);
CU_ASSERT(strcmp(buf, sysbuf) == 0);
rc = ddsrt_gethostname(buf, strlen(buf) - 1);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_NOT_ENOUGH_SPACE);
}
#if DDSRT_HAVE_DNS
static void gethostbyname_test(char *name, int af, dds_retcode_t exp)
{
dds_retcode_t rc;
ddsrt_hostent_t *hent = NULL;
rc = ddsrt_gethostbyname(name, af, &hent);
CU_ASSERT_EQUAL(rc, exp);
if (rc == DDS_RETCODE_OK) {
CU_ASSERT_FATAL(hent->naddrs > 0);
if (af != AF_UNSPEC) {
CU_ASSERT_EQUAL(hent->addrs[0].ss_family, af);
}
}
ddsrt_free(hent);
}
CU_TheoryDataPoints(ddsrt_gethostbyname, ipv4) = {
CU_DataPoints(char *, "", "127.0.0.1", "127.0.0.1"),
CU_DataPoints(int, AF_UNSPEC, AF_INET, AF_UNSPEC),
CU_DataPoints(dds_retcode_t, DDS_RETCODE_HOST_NOT_FOUND, DDS_RETCODE_OK, DDS_RETCODE_OK)
};
CU_Theory((char *name, int af, dds_retcode_t exp), ddsrt_gethostbyname, ipv4, .init=setup, .fini=teardown)
{
gethostbyname_test(name, af, exp);
}
#if DDSRT_HAVE_IPV6
/* Lookup of IPv4 address and specifying AF_INET6 is not invalid as it may
return an IPV4-mapped IPv6 address. */
CU_TheoryDataPoints(ddsrt_gethostbyname, ipv6) = {
CU_DataPoints(char *, "::1", "::1", "::1"),
CU_DataPoints(int, AF_INET, AF_INET6, AF_UNSPEC),
CU_DataPoints(dds_retcode_t, DDS_RETCODE_HOST_NOT_FOUND, DDS_RETCODE_OK, DDS_RETCODE_OK)
};
CU_Theory((char *name, int af, dds_retcode_t exp), ddsrt_gethostbyname, ipv6, .init=setup, .fini=teardown)
{
gethostbyname_test(name, af, exp);
}
#endif /* DDSRT_HAVE_IPV6 */
#endif /* DDSRT_HAVE_DNS */

101
src/ddsrt/tests/string.c Normal file
View file

@ -0,0 +1,101 @@
/*
* 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 "CUnit/Theory.h"
#include "dds/ddsrt/string.h"
typedef enum { eq, lt, gt } eq_t;
CU_TheoryDataPoints(ddsrt_strcasecmp, basic) = {
CU_DataPoints(const char *, "a", "aa", "a", "a", "A", "a", "b", "a", "B", "A", "", "a"),
CU_DataPoints(const char *, "a", "a", "aa", "A", "a", "b", "a", "b", "A", "B", "a", ""),
CU_DataPoints(eq_t, eq, gt, lt, eq, eq, lt, gt, lt, gt, lt, lt, gt)
};
CU_Theory((const char *s1, const char *s2, eq_t e), ddsrt_strcasecmp, basic)
{
int r = ddsrt_strcasecmp(s1, s2);
CU_ASSERT((e == eq && r == 0) || (e == lt && r < 0) || (e == gt && r > 0));
}
CU_TheoryDataPoints(ddsrt_strncasecmp, basic) = {
CU_DataPoints(const char *, "a", "aa", "a", "A", "a", "b", "a", "B", "A", "", "a"),
CU_DataPoints(const char *, "a", "a", "aa", "a", "A", "a", "b", "A", "B", "a", ""),
CU_DataPoints(size_t, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1),
CU_DataPoints(eq_t, eq, gt, lt, eq, eq, gt, lt, gt, lt, lt, gt)
};
CU_Theory((const char *s1, const char *s2, size_t n, eq_t e), ddsrt_strncasecmp, basic)
{
int r = ddsrt_strncasecmp(s1, s2, n);
CU_ASSERT((e == eq && r == 0) || (e == lt && r < 0) || (e == gt && r > 0));
}
CU_TheoryDataPoints(ddsrt_strncasecmp, empty) = {
CU_DataPoints(const char *, "a", "", "a", "", "a", ""),
CU_DataPoints(const char *, "", "a", "", "a", "", "a"),
CU_DataPoints(size_t, 1, 1, 0, 0, 2, 2),
CU_DataPoints(eq_t, gt, lt, eq, eq, gt, lt)
};
CU_Theory((const char *s1, const char *s2, size_t n, eq_t e), ddsrt_strncasecmp, empty)
{
int r = ddsrt_strncasecmp(s1, s2, n);
CU_ASSERT((e == eq && r == 0) || (e == lt && r < 0) || (e == gt && r > 0));
}
CU_TheoryDataPoints(ddsrt_strncasecmp, length) = {
CU_DataPoints(const char *, "aBcD", "AbCX", "aBcD", "AbCX", "aBcD"),
CU_DataPoints(const char *, "AbCX", "aBcD", "AbCX", "aBcD", "AbCd"),
CU_DataPoints(size_t, 3, 3, 4, 4, 5, 5),
CU_DataPoints(eq_t, eq, eq, lt, gt, eq, eq)
};
CU_Theory((const char *s1, const char *s2, size_t n, eq_t e), ddsrt_strncasecmp, length)
{
int r = ddsrt_strncasecmp(s1, s2, n);
CU_ASSERT((e == eq && r == 0) || (e == lt && r < 0) || (e == gt && r > 0));
}
CU_Test(ddsrt_string, strtok_r)
{
char *res;
char *saveptr;
char ts1[] = "123,234";
char ts2[] = ",;,123abc,,456,:,";
char ts3[] = ",,,123,,456,789,,,";
res = ddsrt_strtok_r(ts1, ",", &saveptr);
CU_ASSERT(strcmp(res, "123") == 0);
res = ddsrt_strtok_r( NULL, ",", &saveptr);
CU_ASSERT(strcmp(res, "234") == 0);
res = ddsrt_strtok_r( NULL, ",", &saveptr);
CU_ASSERT(res == NULL);
res = ddsrt_strtok_r(ts2, ",;", &saveptr);
CU_ASSERT(strcmp(res, "123abc") == 0);
res = ddsrt_strtok_r( NULL, ",", &saveptr);
CU_ASSERT(strcmp(res, "456") == 0);
res = ddsrt_strtok_r( NULL, ",:", &saveptr);
CU_ASSERT(res == NULL);
res = ddsrt_strtok_r(ts3, ",", &saveptr);
CU_ASSERT(strcmp(res, "123") == 0);
res = ddsrt_strtok_r( NULL, ",", &saveptr);
CU_ASSERT(strcmp(res, "456") == 0);
res = ddsrt_strtok_r( NULL, ",", &saveptr);
CU_ASSERT(strcmp(res, "789") == 0);
res = ddsrt_strtok_r( NULL, ",:", &saveptr);
CU_ASSERT(res == NULL);
}

80
src/ddsrt/tests/strlcpy.c Normal file
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
*/
#include <stdio.h>
#include <string.h>
#include "CUnit/Theory.h"
#include "dds/ddsrt/string.h"
CU_TheoryDataPoints(ddsrt_strlcpy, dest_size) = {
CU_DataPoints(char *, "foo", "foo", "foo", "foo", "foo", "", "", ""),
CU_DataPoints(size_t, 0, 1, 3, 4, 5, 0, 1, 2)
};
CU_Theory((char *src, size_t size), ddsrt_strlcpy, dest_size)
{
char dest[] = "................";
size_t len, srclen;
srclen = strlen(src);
len = ddsrt_strlcpy(dest, src, size);
CU_ASSERT_EQUAL(len, srclen);
if (size > 0) {
if ((size - 1) < len) {
len = size - 1;
}
CU_ASSERT_EQUAL(dest[len], '\0');
CU_ASSERT_EQUAL(dest[len+1], '.');
CU_ASSERT((strncmp(dest, src, len) == 0));
} else {
CU_ASSERT_EQUAL(dest[0], '.');
}
}
CU_TheoryDataPoints(ddsrt_strlcat, dest_size) = {
CU_DataPoints(char *, "", "", "", "", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "", "", "foo", "foo", "foo"),
CU_DataPoints(char *, "bar", "bar", "bar", "bar", "bar", "bar", "bar", "bar", "bar", "bar", "bar", "", "", "", "", ""),
CU_DataPoints(size_t, 0, 1, 3, 4, 0, 1, 3, 4, 5, 6, 7, 0, 1, 3, 4, 5)
};
CU_Theory((char *seed, char *src, size_t size), ddsrt_strlcat, dest_size)
{
char dest[] = "................";
size_t len, seedlen, srclen;
seedlen = strlen(seed);
srclen = strlen(src);
memcpy(dest, seed, seedlen);
dest[seedlen] = '\0';
len = ddsrt_strlcat(dest, src, size);
CU_ASSERT_EQUAL(len, (seedlen + srclen));
if (size > 0) {
char foobar[sizeof(dest)];
if ((size - 1) <= seedlen) {
len = seedlen;
} else if ((size - 1) <= len) {
len = size - 1;
}
CU_ASSERT_EQUAL(dest[len], '\0');
if (seedlen < (size - 1)) {
CU_ASSERT_EQUAL(dest[len+1], '.');
}
(void)snprintf(foobar, len+1, "%s%s", seed, src);
CU_ASSERT((strncmp(dest, foobar, len) == 0));
} else {
CU_ASSERT((strcmp(dest, seed) == 0));
}
}

343
src/ddsrt/tests/strtoll.c Normal file
View file

@ -0,0 +1,343 @@
/*
* 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/Test.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/strtol.h"
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 = DDSRT_MIN_INTEGER(long long);
long long llmax = DDSRT_MAX_INTEGER(long long);
unsigned long long ullmax = DDSRT_MAX_INTEGER(unsigned long long);
CU_Init(ddsrt_strtoll)
{
ddsrt_init();
(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 0;
}
CU_Clean(ddstr_strtoll)
{
ddsrt_fini();
return 0;
}
CU_Test(ddsrt_strtoll, strtoll)
{
dds_retcode_t rc;
long long ll;
static char dummy[] = "dummy";
str = "gibberish";
ll = -1;
rc = ddsrt_strtoll(str, &ptr, 0, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 0 && ptr == str);
str = "+gibberish";
ll = -2;
rc = ddsrt_strtoll(str, &ptr, 0, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 0 && ptr == str);
str = "-gibberish";
ll = -3;
rc = ddsrt_strtoll(str, &ptr, 0, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 0 && ptr == str);
str = "gibberish";
ptr = NULL;
ll = -4;
rc = ddsrt_strtoll(str, &ptr, 36, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 46572948005345 && ptr && *ptr == '\0');
str = "1050505055";
ptr = dummy;
ll = -5;
rc = ddsrt_strtoll(str, &ptr, 37, &ll);
CU_ASSERT (rc == DDS_RETCODE_BAD_PARAMETER);
CU_ASSERT (ll == -5 && ptr == dummy);
str = " \t \n 1050505055";
ll = -6;
rc = ddsrt_strtoll(str, NULL, 10, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 1050505055LL);
str = " \t \n -1050505055";
ptr = NULL;
ll = -7;
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == -1050505055LL);
str = " \t \n - \t \n 1050505055";
ptr = NULL;
ll = -8;
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 0LL && ptr == str);
str = "10x";
ptr = NULL;
ll = -9;
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 10LL && ptr && *ptr == 'x');
str = "+10x";
ll = -10;
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 10LL && ptr && *ptr == 'x');
str = "-10x";
ll = -11;
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == -10LL && ptr && *ptr == 'x');
str = (const char *)str_llmax;
ll = -12;
rc = ddsrt_strtoll(str, NULL, 10, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == llmax);
str = (const char *)str_llmin;
ll = -13;
rc = ddsrt_strtoll(str, NULL, 10, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == llmin);
str = (const char *)str_llrange;
ll = -14;
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
CU_ASSERT (rc == DDS_RETCODE_OUT_OF_RANGE);
CU_ASSERT (ll == llmax && *ptr == '1');
str = "0x100";
ll = -15;
rc = ddsrt_strtoll(str, NULL, 16, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 0x100LL);
str = "0X100";
ll = -16;
rc = ddsrt_strtoll(str, NULL, 16, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 0x100LL);
str = "0x1DEFCAB";
ll = -17;
rc = ddsrt_strtoll(str, NULL, 16, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 0x1DEFCABLL);
str = "0x1defcab";
ll = -18;
rc = ddsrt_strtoll(str, NULL, 16, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 0x1DEFCABLL);
str = (char *)str_xllmin;
ll = -19;
rc = ddsrt_strtoll(str, NULL, 16, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == llmin);
str = (char *)str_xllmax;
ll = -20;
rc = ddsrt_strtoll(str, NULL, 16, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == llmax);
str = "0x100";
ll = -21;
rc = ddsrt_strtoll(str, NULL, 0, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 0x100LL);
str = "100";
ll = -22;
rc = ddsrt_strtoll(str, NULL, 16, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 0x100LL);
/* calling os_strtoll with \"%s\" and base 10, expected result 0 */
str = "0x100";
ll = -23;
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 0 && ptr && *ptr == 'x');
/* calling os_strtoll with \"%s\" and base 0, expected result 256 */
str = "0x100g";
ll = -24;
rc = ddsrt_strtoll(str, &ptr, 0, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 256 && ptr && *ptr == 'g');
str = "0100";
ll = -25;
rc = ddsrt_strtoll(str, NULL, 0, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 64LL);
str = "0100";
ll = -26;
rc = ddsrt_strtoll(str, NULL, 8, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 64LL);
str = "100";
ll = -27;
rc = ddsrt_strtoll(str, NULL, 8, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 64LL);
/* calling os_strtoll with \"%s\" and base 10, expected result 100 */
str = "0100";
ll = -28;
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 100);
/* calling os_strtoll with \"%s\" and base 0, expected result 64 */
str = "01008";
ll = -29;
rc = ddsrt_strtoll(str, &ptr, 8, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 64LL && ptr && *ptr == '8');
str = "00001010";
ll = -30;
rc = ddsrt_strtoll(str, NULL, 2, &ll);
CU_ASSERT (rc == DDS_RETCODE_OK);
CU_ASSERT (ll == 10LL);
}
CU_Test(ddsrt_strtoll, strtoull)
{
dds_retcode_t rc;
unsigned long long ull;
str = "0xffffffffffffffff";
ull = 1;
rc = ddsrt_strtoull(str, NULL, 0, &ull);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
CU_ASSERT(ull == ullmax);
str = "-1";
ull = 2;
rc = ddsrt_strtoull(str, NULL, 0, &ull);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
CU_ASSERT(ull == ullmax);
str = "-2";
ull = 3;
rc = ddsrt_strtoull(str, NULL, 0, &ull);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
CU_ASSERT(ull == (ullmax - 1));
}
CU_Test(ddsrt_strtoll, atoll)
{
dds_retcode_t rc;
long long ll;
str = "10";
ll = -1;
rc = ddsrt_atoll(str, &ll);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
CU_ASSERT(ll == 10);
}
CU_Test(ddsrt_strtoll, atoull)
{
dds_retcode_t rc;
unsigned long long ull;
str = "10";
ull = 1;
rc = ddsrt_atoull(str, &ull);
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
CU_ASSERT(ull == 10);
}
CU_Test(ddsrt_strtoll, lltostr)
{
long long ll;
ll = llmax;
ptr = ddsrt_lltostr(ll, buf, 0, NULL);
CU_ASSERT(ptr == NULL);
/* calling os_lltostr with %lld with buffer size of 5, expected result \"5432\" */
ll = 54321;
ptr = ddsrt_lltostr(ll, buf, 5, NULL);
CU_ASSERT(strcmp(ptr, "5432") == 0);
ll = llmax;
ptr = ddsrt_lltostr(ll, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, str_llmax) == 0);
ll = llmin;
ptr = ddsrt_lltostr(ll, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, str_llmin) == 0);
ll = 1;
ptr = ddsrt_lltostr(ll, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, "1") == 0);
ll = 0;
ptr = ddsrt_lltostr(ll, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, "0") == 0);
ll = -1;
ptr = ddsrt_lltostr(ll, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, "-1") == 0);
}
CU_Test(ddsrt_strtoll, ulltostr)
{
unsigned long long ull;
ull = ullmax;
ptr = ddsrt_ulltostr(ull, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, str_ullmax) == 0);
ull = 0ULL;
ptr = ddsrt_ulltostr(ull, buf, sizeof(buf), NULL);
CU_ASSERT(strcmp(ptr, "0") == 0);
}

357
src/ddsrt/tests/sync.c Normal file
View file

@ -0,0 +1,357 @@
/*
* 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 <stdint.h>
#include "CUnit/Theory.h"
#include "dds/ddsrt/atomics.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/threads.h"
#include "dds/ddsrt/time.h"
CU_Init(ddsrt_sync)
{
ddsrt_init();
return 0;
}
CU_Clean(ddsrt_sync)
{
ddsrt_fini();
return 0;
}
typedef struct {
ddsrt_atomic_uint32_t cnt;
ddsrt_mutex_t lock;
ddsrt_rwlock_t rwlock;
ddsrt_cond_t cond;
dds_time_t abstime;
dds_time_t reltime;
} thread_arg_t;
static uint32_t mutex_lock_routine(void *ptr)
{
int res;
thread_arg_t *arg = (thread_arg_t *)ptr;
ddsrt_atomic_inc32(&arg->cnt);
ddsrt_mutex_lock(&arg->lock);
res = ddsrt_atomic_cas32(&arg->cnt, 2UL, 4UL);
ddsrt_mutex_unlock(&arg->lock);
return (uint32_t)res;
}
/* This test is merely best-effort, the scheduler might schedule the main
main thread before a lock operation is attempted by the second thread. */
CU_Test(ddsrt_sync, mutex_lock_conc)
{
dds_retcode_t ret;
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(0) };
uint32_t res = 0;
ddsrt_mutex_init(&arg.lock);
ddsrt_mutex_lock(&arg.lock);
ddsrt_threadattr_init(&attr);
ret = ddsrt_thread_create(&thr, "mutex_lock_conc", &attr, &mutex_lock_routine, &arg);
CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
while (ddsrt_atomic_ld32(&arg.cnt) == 0)
/* Wait for thread to be scheduled. */ ;
ddsrt_atomic_inc32(&arg.cnt);
ddsrt_mutex_unlock(&arg.lock);
ret = ddsrt_thread_join(thr, &res);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(res, 1);
CU_ASSERT_EQUAL(ddsrt_atomic_ld32(&arg.cnt), 4UL);
ddsrt_mutex_destroy(&arg.lock);
}
static uint32_t mutex_trylock_routine(void *ptr)
{
thread_arg_t *arg = (thread_arg_t *)ptr;
if (ddsrt_mutex_trylock(&arg->lock)) {
ddsrt_atomic_inc32(&arg->cnt);
}
return ddsrt_atomic_ld32(&arg->cnt);
}
CU_Test(ddsrt_sync, mutex_trylock)
{
bool locked;
ddsrt_mutex_t lock;
ddsrt_mutex_init(&lock);
locked = ddsrt_mutex_trylock(&lock);
CU_ASSERT(locked == true);
locked = ddsrt_mutex_trylock (&lock);
/* NOTE: On VxWorks RTP mutexes seemingly can be locked recursively. Still,
behavior should be consistent across targets. If this fails, fix
the implementation instead. */
CU_ASSERT(locked == false);
ddsrt_mutex_unlock(&lock);
ddsrt_mutex_destroy(&lock);
}
static uint32_t rwlock_tryread_routine(void *ptr)
{
thread_arg_t *arg = (thread_arg_t *)ptr;
if (ddsrt_rwlock_tryread(&arg->rwlock)) {
ddsrt_atomic_inc32(&arg->cnt);
ddsrt_rwlock_unlock(&arg->rwlock);
}
return ddsrt_atomic_ld32(&arg->cnt);
}
static uint32_t rwlock_trywrite_routine(void *ptr)
{
thread_arg_t *arg = (thread_arg_t *)ptr;
/* This operation should never succeed in the test, but if it does the
result must reflect it. */
if (ddsrt_rwlock_trywrite(&arg->rwlock)) {
ddsrt_atomic_inc32(&arg->cnt);
ddsrt_rwlock_unlock(&arg->rwlock);
}
return ddsrt_atomic_ld32(&arg->cnt);
}
CU_Test(ddsrt_sync, mutex_trylock_conc)
{
dds_retcode_t ret;
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(1) };
uint32_t res = 0;
ddsrt_mutex_init(&arg.lock);
ddsrt_mutex_lock(&arg.lock);
ddsrt_threadattr_init(&attr);
ret = ddsrt_thread_create(&thr, "mutex_trylock_conc", &attr, &mutex_trylock_routine, &arg);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
ret = ddsrt_thread_join(thr, &res);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(res, 1);
ddsrt_mutex_unlock(&arg.lock);
ddsrt_mutex_destroy(&arg.lock);
}
#define READ (1)
#define TRYREAD (2)
#define WRITE (3)
#define TRYWRITE (4)
CU_TheoryDataPoints(ddsrt_sync, rwlock_trylock_conc) = {
CU_DataPoints(uint32_t, READ, READ, WRITE, WRITE),
CU_DataPoints(uint32_t, TRYREAD, TRYWRITE, TRYREAD, TRYWRITE),
CU_DataPoints(uint32_t, 2, 1, 1, 1)
};
CU_Theory((uint32_t lock, uint32_t trylock, uint32_t exp), ddsrt_sync, rwlock_trylock_conc)
{
dds_retcode_t ret;
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
ddsrt_thread_routine_t func;
thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(1) };
uint32_t res = 0;
ddsrt_rwlock_init(&arg.rwlock);
if (lock == READ) {
ddsrt_rwlock_read(&arg.rwlock);
} else {
ddsrt_rwlock_write(&arg.rwlock);
}
if (trylock == TRYREAD) {
func = &rwlock_tryread_routine;
} else {
func = &rwlock_trywrite_routine;
}
ddsrt_threadattr_init(&attr);
ret = ddsrt_thread_create(&thr, "rwlock_trylock_conc", &attr, func, &arg);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
ret = ddsrt_thread_join(thr, &res);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
ddsrt_rwlock_unlock(&arg.rwlock);
CU_ASSERT_EQUAL(res, exp);
ddsrt_rwlock_destroy(&arg.rwlock);
}
/* An atomic read is used for synchronization because it is important that the
threads try to access the once control concurrently as much as possible. Of
course, this is only best-effort as there is no guarantee that
initialization is actually tried concurrently. */
static ddsrt_atomic_uint32_t once_count = DDSRT_ATOMIC_UINT32_INIT(0);
static ddsrt_once_t once_control = DDSRT_ONCE_INIT;
#define ONCE_THREADS (8)
static void do_once(void)
{
ddsrt_atomic_inc32(&once_count);
}
static uint32_t once_routine(void *ptr)
{
(void)ptr;
while (ddsrt_atomic_ld32(&once_count) == 0)
/* Wait for the go-ahead. */ ;
ddsrt_once(&once_control, &do_once);
return ddsrt_atomic_ld32(&once_count);
}
CU_Test(ddsrt_sync, once_conc)
{
dds_retcode_t ret;
ddsrt_thread_t thrs[ONCE_THREADS];
ddsrt_threadattr_t attr;
uint32_t res;
char buf[32];
ddsrt_threadattr_init(&attr);
for (int i = 0; i < ONCE_THREADS; i++) {
(void)snprintf(buf, sizeof(buf), "once_conc%d", i + 1);
ret = ddsrt_thread_create(&thrs[i], buf, &attr, &once_routine, NULL);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
}
ddsrt_atomic_st32(&once_count, 1);
for (int i = 0; i < ONCE_THREADS; i++) {
res = 0;
ret = ddsrt_thread_join(thrs[i], &res);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(res, 2);
}
ddsrt_once(&once_control, &do_once);
CU_ASSERT_EQUAL(ddsrt_atomic_ld32(&once_count), 2);
}
static uint32_t waitfor_routine(void *ptr)
{
dds_time_t before, after;
dds_duration_t reltime;
thread_arg_t *arg = (thread_arg_t *)ptr;
uint32_t cnt = 0, res = 0;
while (ddsrt_atomic_ld32(&arg->cnt) == 0)
/* Wait for go-ahead. */ ;
ddsrt_mutex_lock(&arg->lock);
before = dds_time();
reltime = arg->reltime;
while (ddsrt_cond_waitfor(&arg->cond, &arg->lock, reltime)) {
after = dds_time();
if ((after - before) < arg->reltime && (after - before) > 0) {
reltime = arg->reltime - (after - before);
} else {
reltime = 0;
}
cnt++;
}
after = dds_time();
reltime = after - before;
fprintf(stderr, "waited for %"PRId64" (nanoseconds)\n", reltime);
fprintf(stderr, "expected to wait %"PRId64" (nanoseconds)\n", arg->reltime);
fprintf(stderr, "woke up %u times\n", cnt);
ddsrt_mutex_unlock(&arg->lock);
if (reltime >= arg->reltime) {
/* Ensure that the condition variable at least waited for the amount of
time so that time calculation is not (too) broken.*/
res = cnt < 3; /* An arbitrary number to ensure the implementation
did not just spin, aka is completely broken. */
}
return res;
}
CU_Test(ddsrt_sync, cond_waitfor)
{
dds_retcode_t rc;
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(0), .reltime = DDS_MSECS(100) };
uint32_t res = 0;
ddsrt_mutex_init(&arg.lock);
ddsrt_cond_init(&arg.cond);
ddsrt_mutex_lock(&arg.lock);
ddsrt_threadattr_init(&attr);
rc = ddsrt_thread_create(&thr, "cond_waitfor", &attr, &waitfor_routine, &arg);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
ddsrt_mutex_unlock(&arg.lock);
/* Give go-ahead. */
ddsrt_atomic_inc32(&arg.cnt);
/* Wait a little longer than the waiting thread. */
dds_sleepfor(arg.reltime * 2);
/* Send a signal too avoid blocking indefinitely. */
ddsrt_cond_signal(&arg.cond);
rc = ddsrt_thread_join(thr, &res);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(res, 1);
}
static uint32_t waituntil_routine(void *ptr)
{
dds_time_t after;
thread_arg_t *arg = (thread_arg_t *)ptr;
uint32_t cnt = 0, res = 0;
ddsrt_mutex_lock(&arg->lock);
while(ddsrt_cond_waituntil(&arg->cond, &arg->lock, arg->abstime)) {
cnt++;
}
after = dds_time();
ddsrt_mutex_unlock(&arg->lock);
fprintf(stderr, "waited until %"PRId64" (nanoseconds)\n", after);
fprintf(stderr, "expected to wait until %"PRId64" (nanoseconds)\n", arg->abstime);
fprintf(stderr, "woke up %u times\n", cnt);
if (after > arg->abstime) {
res = cnt < 3; /* An arbitrary number to ensure the implementation
did not just spin, aka is completely broken. */
}
return res;
}
CU_Test(ddsrt_sync, cond_waituntil)
{
dds_retcode_t rc;
dds_duration_t delay = DDS_MSECS(100);
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(0) };
uint32_t res = 0;
arg.abstime = dds_time() + delay;
ddsrt_mutex_init(&arg.lock);
ddsrt_cond_init(&arg.cond);
ddsrt_mutex_lock(&arg.lock);
ddsrt_threadattr_init(&attr);
rc = ddsrt_thread_create(&thr, "cond_waituntil", &attr, &waituntil_routine, &arg);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
ddsrt_mutex_unlock(&arg.lock);
dds_sleepfor(delay * 2);
/* Send a signal too avoid blocking indefinitely. */
ddsrt_cond_signal(&arg.cond);
rc = ddsrt_thread_join(thr, &res);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(res, 1);
}

233
src/ddsrt/tests/thread.c Normal file
View file

@ -0,0 +1,233 @@
/*
* 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 <stdlib.h>
#if !defined(_WIN32)
#include <sched.h>
#include <unistd.h>
#endif
#include "CUnit/Theory.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/retcode.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/threads.h"
static int32_t min_fifo_prio = 250;
static int32_t max_fifo_prio = 250;
static int32_t max_other_prio = 60;
static int32_t min_other_prio = 250;
CU_Init(ddsrt_thread)
{
ddsrt_init();
#if defined(WIN32)
max_fifo_prio = THREAD_PRIORITY_HIGHEST;
min_fifo_prio = THREAD_PRIORITY_LOWEST;
max_other_prio = THREAD_PRIORITY_HIGHEST;
min_other_prio = THREAD_PRIORITY_LOWEST;
#else
min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
# if !defined(_WRS_KERNEL)
max_other_prio = sched_get_priority_max(SCHED_OTHER);
min_other_prio = sched_get_priority_min(SCHED_OTHER);
# endif
#endif
return 0;
}
CU_Clean(ddsrt_thread)
{
ddsrt_fini();
return 0;
}
typedef struct {
int res;
int ret;
ddsrt_threadattr_t *attr;
} thread_arg_t;
uint32_t thread_main(void *ptr)
{
thread_arg_t *arg = (thread_arg_t *)ptr;
ddsrt_threadattr_t *attr;
assert(arg != NULL);
attr = arg->attr;
#if _WIN32
int prio = GetThreadPriority(GetCurrentThread());
if (prio == THREAD_PRIORITY_ERROR_RETURN)
abort();
if (prio == attr->schedPriority) {
arg->res = 1;
}
#else
int err;
int policy;
struct sched_param sched;
err = pthread_getschedparam(pthread_self(), &policy, &sched);
if (err != 0) {
abort();
}
if (((policy == SCHED_OTHER && attr->schedClass == DDSRT_SCHED_TIMESHARE) ||
(policy == SCHED_FIFO && attr->schedClass == DDSRT_SCHED_REALTIME))
&& (sched.sched_priority == attr->schedPriority))
{
arg->res = 1;
}
#endif
return (uint32_t)arg->ret;
}
CU_TheoryDataPoints(ddsrt_thread, create_and_join) = {
CU_DataPoints(ddsrt_sched_t, DDSRT_SCHED_TIMESHARE, DDSRT_SCHED_TIMESHARE,
DDSRT_SCHED_REALTIME, DDSRT_SCHED_REALTIME),
CU_DataPoints(int32_t *, &min_other_prio, &max_other_prio,
&min_fifo_prio, &max_fifo_prio),
CU_DataPoints(uint32_t, 10101, 20202,
30303, 40404)
};
CU_Theory((ddsrt_sched_t sched, int32_t *prio, uint32_t exp), ddsrt_thread, create_and_join)
{
int skip = 0;
uint32_t res = 50505;
dds_retcode_t ret;
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
thread_arg_t arg;
#if defined(__VXWORKS__)
# if defined(_WRS_KERNEL)
if (sched == DDSRT_SCHED_TIMESHARE) {
skip = 1;
CU_PASS("VxWorks DKM only supports SCHED_FIFO");
}
# endif
#elif !defined(_WIN32)
if (sched == DDSRT_SCHED_REALTIME && (getuid() != 0 && geteuid() != 0)) {
skip = 1;
CU_PASS("SCHED_FIFO requires root privileges");
}
#endif
if (!skip) {
ddsrt_threadattr_init(&attr);
attr.schedClass = sched;
attr.schedPriority = *prio;
memset(&arg, 0, sizeof(arg));
arg.ret = (int32_t)exp;
arg.attr = &attr;
ret = ddsrt_thread_create(&thr, "thread", &attr, &thread_main, &arg);
CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
if (ret == DDS_RETCODE_OK) {
ret = ddsrt_thread_join (thr, &res);
CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(res, exp);
if (ret == DDS_RETCODE_OK) {
CU_ASSERT_EQUAL(arg.res, 1);
}
}
}
}
CU_Test(ddsrt_thread, thread_id)
{
int eq = 0;
ddsrt_thread_t thr;
#if defined(_WIN32)
DWORD _tid;
#else
pthread_t _thr;
#endif
thr = ddsrt_thread_self();
#if defined(_WIN32)
_tid = GetCurrentThreadId();
eq = (thr.tid == _tid);
#else
_thr = pthread_self();
eq = pthread_equal(thr.v, _thr);
#endif
CU_ASSERT_NOT_EQUAL(eq, 0);
}
static ddsrt_mutex_t locks[2];
uint32_t thread_main_waitforme(void *ptr)
{
uint32_t ret = 0;
(void)ptr;
ddsrt_mutex_lock(&locks[0]);
ret = 10101;
ddsrt_mutex_unlock(&locks[0]);
return ret;
}
uint32_t thread_main_waitforit(void *ptr)
{
uint32_t res = 0;
ddsrt_thread_t *thr = (ddsrt_thread_t *)ptr;
ddsrt_mutex_lock(&locks[1]);
(void)ddsrt_thread_join(*thr, &res);
ddsrt_mutex_unlock(&locks[1]);
return res + 20202;
}
CU_Test(ddsrt_thread, stacked_join)
{
dds_retcode_t ret;
ddsrt_thread_t thrs[2];
ddsrt_threadattr_t attr;
uint32_t res = 0;
ddsrt_mutex_init(&locks[0]);
ddsrt_mutex_init(&locks[1]);
ddsrt_mutex_lock(&locks[0]);
ddsrt_mutex_lock(&locks[1]);
ddsrt_threadattr_init(&attr);
ret = ddsrt_thread_create(&thrs[0], "", &attr, &thread_main_waitforme, NULL);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
ret = ddsrt_thread_create(&thrs[1], "", &attr, &thread_main_waitforit, &thrs[0]);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
ddsrt_mutex_unlock(&locks[1]);
dds_sleepfor(DDS_MSECS(100)); /* 100ms */
ddsrt_mutex_unlock(&locks[0]);
ddsrt_thread_join(thrs[1], &res);
CU_ASSERT_EQUAL(res, 30303);
ddsrt_mutex_destroy(&locks[0]);
ddsrt_mutex_destroy(&locks[1]);
}
CU_Test(ddsrt_thread, attribute)
{
ddsrt_threadattr_t attr;
ddsrt_threadattr_init(&attr);
CU_ASSERT_EQUAL(attr.schedClass, DDSRT_SCHED_DEFAULT);
CU_ASSERT_EQUAL(attr.schedPriority, 0);
CU_ASSERT_EQUAL(attr.stackSize, 0);
}

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
*/
#include <assert.h>
#include <stdint.h>
#include "CUnit/Test.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/threads.h"
CU_Init(ddsrt_thread_cleanup)
{
ddsrt_init();
return 0;
}
CU_Clean(ddsrt_thread_cleanup)
{
ddsrt_fini();
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;
ddsrt_mutex_t *mutex;
ddsrt_thread_t thread;
};
static struct thread_argument *
make_thread_argument(
int flags, int pop, int one, int two)
{
struct thread_argument *targ = ddsrt_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) {
ddsrt_thread_cleanup_push(&reset_one, arg);
pushed++;
}
if (targ->flags & THREAD_RESET_2) {
ddsrt_thread_cleanup_push(&reset_two, arg);
pushed++;
}
assert(targ->pop <= pushed);
if (targ->block) {
ddsrt_mutex_lock(targ->mutex);
}
while (popped < targ->pop) {
execute = 1 << (THREAD_RUN_OFFSET + (targ->pop - (popped + 1)));
ddsrt_thread_cleanup_pop(targ->flags & execute);
targ->cancelled++;
popped++;
}
if (targ->block) {
ddsrt_mutex_unlock(targ->mutex);
}
return 0;
}
static void
setup(
struct thread_argument *arg)
{
dds_retcode_t rc;
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
uint32_t tres = 0;
ddsrt_threadattr_init(&attr);
rc = ddsrt_thread_create(&thr, "", &attr, &thread_main, (void *)arg);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
arg->thread = thr;
if (!arg->block) {
rc = ddsrt_thread_join(thr, &tres);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
}
}
/* verify the cleanup routine is called */
CU_Test(ddsrt_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);
ddsrt_free(targ);
}
/* verify all cleanup routines are called if multiple are registered */
CU_Test(ddsrt_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);
ddsrt_free(targ);
}
/* verify the first cleanup routine is still called if second got popped */
CU_Test(ddsrt_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);
ddsrt_free(targ);
}
CU_Test(ddsrt_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);
ddsrt_free(targ);
}
/* verify no cleanup routines are called if all got popped */
CU_Test(ddsrt_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);
ddsrt_free(targ);
}
CU_Test(ddsrt_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);
ddsrt_free(targ);
}
CU_Test(ddsrt_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);
ddsrt_free(targ);
}
CU_Test(ddsrt_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);
ddsrt_mutex_t mutex1, mutex2;
ddsrt_mutex_init(&mutex1);
ddsrt_mutex_init(&mutex2);
ddsrt_mutex_lock(&mutex1);
ddsrt_mutex_lock(&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 */
ddsrt_mutex_unlock(&mutex2);
ddsrt_thread_join(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 */
ddsrt_mutex_unlock(&mutex1);
ddsrt_thread_join(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);
ddsrt_mutex_destroy(&mutex1);
ddsrt_mutex_destroy(&mutex2);
ddsrt_free(targ1);
ddsrt_free(targ2);
}