Merge branch 'master' into merge2

Signed-off-by: Martin Bremmer <martin.bremmer@adlinktech.com>
This commit is contained in:
Martin Bremmer 2019-09-03 11:44:50 +02:00
commit 3fc777e631
477 changed files with 31941 additions and 32175 deletions

View file

@ -11,12 +11,44 @@
#
include(CheckCSourceCompiles)
include(CheckLibraryExists)
include(GenerateDummyExportHeader)
# Lightweight IP stack can be used on non-embedded targets too, but the
# runtime must be instructed to use it instead of the native stack. Of course
# for embedded targets there is no "native" stack and the runtime module must
# always be instructed to use an "alternative" stack.
option(WITH_LWIP "Use lightweight IP stack" OFF)
option(WITH_DNS "Enable domain name lookups" ON)
option(WITH_FREERTOS "Build for FreeRTOS" OFF)
function(check_runtime_feature SOURCE_FILE)
get_target_property(_defs ddsrt INTERFACE_COMPILE_DEFINITIONS)
foreach(_def ${_defs})
set(_strdefs "${_strdefs} -D${_def}")
endforeach()
# Generate dummy export header required by feature tests.
generate_dummy_export_header(
ddsrt
BASE_NAME dds
EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/cmake/include/dds/export.h")
set(_strincs "${CMAKE_CURRENT_BINARY_DIR}/cmake/include")
get_target_property(_incs ddsrt INTERFACE_INCLUDE_DIRECTORIES)
foreach(_inc ${_incs})
set(_strincs "${_strincs};${_inc}")
endforeach()
if(_strincs)
set(_strincs "-DINCLUDE_DIRECTORIES:STRING=${_strincs}")
endif()
set(expr "cmake_([_a-zA-Z0-9]+)=([_a-zA-Z0-9]+)")
try_compile(
foo "${CMAKE_BINARY_DIR}"
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE}"
CMAKE_FLAGS "${_strincs}"
COMPILE_DEFINITIONS "${_strdefs}"
OUTPUT_VARIABLE output)
string(REGEX MATCHALL "${expr}" matches "${output}")
foreach(match ${matches})
@ -26,7 +58,9 @@ function(check_runtime_feature SOURCE_FILE)
endforeach()
endfunction()
if(APPLE)
if(WITH_FREERTOS)
set(system_name freertos)
elseif(APPLE)
set(system_name darwin)
else()
string(TOLOWER ${CMAKE_SYSTEM_NAME} system_name)
@ -38,6 +72,15 @@ endif()
# ship an older version, so an interface library with public sources is used
# as a workaround for now.
add_library(ddsrt INTERFACE)
foreach(opt WITH_LWIP WITH_DNS WITH_FREERTOS)
if(${opt})
target_compile_definitions(ddsrt INTERFACE DDSRT_${opt}=1)
else()
target_compile_definitions(ddsrt INTERFACE DDSRT_${opt}=0)
endif()
endforeach()
target_include_directories(
ddsrt INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
@ -69,7 +112,9 @@ list(APPEND headers
"${include_path}/dds/ddsrt/dynlib.h"
"${include_path}/dds/ddsrt/strtod.h"
"${include_path}/dds/ddsrt/strtol.h"
"${include_path}/dds/ddsrt/types.h")
"${include_path}/dds/ddsrt/types.h"
"${include_path}/dds/ddsrt/countargs.h"
"${include_path}/dds/ddsrt/static_assert.h")
list(APPEND sources
"${source_path}/io.c"
@ -79,10 +124,10 @@ list(APPEND sources
"${source_path}/strtol.c")
list(APPEND headers
"${source_path}/dds/ddsrt/avl.h"
"${source_path}/dds/ddsrt/fibheap.h"
"${source_path}/dds/ddsrt/hopscotch.h"
"${source_path}/dds/ddsrt/thread_pool.h")
"${include_path}/dds/ddsrt/avl.h"
"${include_path}/dds/ddsrt/fibheap.h"
"${include_path}/dds/ddsrt/hopscotch.h"
"${include_path}/dds/ddsrt/thread_pool.h")
list(APPEND sources
"${source_path}/avl.c"
@ -103,13 +148,13 @@ list(APPEND sources
# 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 md5 process dynlib)
sockets string sync threads time md5 process netstat dynlib)
if(EXISTS "${include_path}/dds/ddsrt/${feature}.h")
list(APPEND headers "${include_path}/dds/ddsrt/${feature}.h")
file(GLOB
file(GLOB_RECURSE
files
CONFIGURE_DEPENDS
"${include_path}/dds/ddsrt/${feature}/**.h")
"${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
@ -125,10 +170,9 @@ foreach(feature atomics cdtors environ heap ifaddrs random rusage
# feature does not exist in cmake, the feature is expected to be
# implemented for all targets.
string(TOUPPER "${feature}" feature_uc)
set(HAVE_${feature_uc} TRUE)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${feature}.c")
check_runtime_feature(cmake/${feature}.c)
else()
set(HAVE_${feature_uc} TRUE)
check_runtime_feature("cmake/${feature}.c")
endif()
if(HAVE_${feature_uc})
@ -138,24 +182,32 @@ foreach(feature atomics cdtors environ heap ifaddrs random rusage
list(APPEND sources "${source_path}/${feature}.c")
endif()
set(system_exists FALSE)
foreach(system ${system_name} posix)
# Allow custom implementations for a feature. e.g. lwip as opposed to
# windows or posix.
set(_system_name "${system_name}")
if(NOT HAVE_${feature_uc} MATCHES "[tT][rR][uU][eE]")
set(_system_name "${HAVE_${feature_uc}}")
endif()
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
file(GLOB_RECURSE
files
CONFIGURE_DEPENDS
"${source_path}/${feature}/include/**.h")
list(APPEND sources ${files})
"${source_path}/${feature}/include/*.h")
list(APPEND headers ${files})
target_include_directories(
ddsrt INTERFACE
"$<BUILD_INTERFACE:${source_path}/${feature}/include/>")
endif()
if(IS_DIRECTORY "${source_path}/${feature}/${system}")
file(GLOB
file(GLOB_RECURSE
files
CONFIGURE_DEPENDS
"${source_path}/${feature}/${system}/**.c")
"${source_path}/${feature}/${system}/*.c")
list(APPEND sources ${files})
set(system_exists TRUE)
endif()
@ -172,12 +224,16 @@ foreach(feature atomics cdtors environ heap ifaddrs random rusage
endif()
endforeach()
target_sources(ddsrt INTERFACE ${sources})
target_sources(ddsrt INTERFACE ${sources} ${headers})
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
target_link_libraries(ddsrt INTERFACE Threads::Threads)
target_link_libraries(ddsrt INTERFACE ${CMAKE_DL_LIBS})
set(HAVE_MULTI_PROCESS ${HAVE_MULTI_PROCESS} PARENT_SCOPE)
if(NOT WITH_FREERTOS)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
target_link_libraries(ddsrt INTERFACE Threads::Threads)
target_link_libraries(ddsrt INTERFACE ${CMAKE_DL_LIBS})
endif()
if(WIN32)
target_link_libraries(ddsrt INTERFACE wsock32 ws2_32 iphlpapi bcrypt)

23
src/ddsrt/cmake/ifaddrs.c Normal file
View file

@ -0,0 +1,23 @@
/*
* 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/ifaddrs.h"
#if DDSRT_WITH_LWIP
# if LWIP_SOCKET
# error "cmake_HAVE_IFADDRS=lwip"
# else
# error "cmake_HAVE_IFADDRS=false"
# endif
#else
# error "cmake_HAVE_IFADDRS=true"
#endif

18
src/ddsrt/cmake/netstat.c Normal file
View file

@ -0,0 +1,18 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "dds/ddsrt/netstat.h"
#if DDSRT_HAVE_NETSTAT
# error "cmake_HAVE_NETSTAT=true"
#else
# error "cmake_HAVE_NETSTAT=false"
#endif

18
src/ddsrt/cmake/process.c Normal file
View file

@ -0,0 +1,18 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "dds/ddsrt/process.h"
#if DDSRT_HAVE_MULTI_PROCESS
# error "cmake_HAVE_MULTI_PROCESS=true"
#else
# error "cmake_HAVE_MULTI_PROCESS=false"
#endif

19
src/ddsrt/cmake/rusage.c Normal file
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
*/
#include "dds/ddsrt/rusage.h"
#if DDSRT_HAVE_RUSAGE
# error "cmake_HAVE_RUSAGE=TRUE"
#else
# error "cmake_HAVE_RUSAGE=FALSE"
#endif

View file

@ -59,6 +59,34 @@ typedef ddsrt_atomic_uintptr_t ddsrt_atomic_voidp_t;
#error "Atomic operations are not supported"
#endif
#if ! DDSRT_HAVE_ATOMIC64
/* 64-bit atomics are not supported by all hardware, but it would be a shame not to use them when
they are available. That necessitates an alternative implementation when they are not, either in
the form of a different implementation where it is used, or as an emulation using a mutex in
ddsrt. It seems that the places where they'd be used end up adding a mutex, so an emulation in
ddsrt while being able to check whether it is supported by hardware is a sensible approach. */
DDS_EXPORT uint64_t ddsrt_atomic_ld64 (const volatile ddsrt_atomic_uint64_t *x);
DDS_EXPORT void ddsrt_atomic_st64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
DDS_EXPORT void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x);
DDS_EXPORT uint64_t ddsrt_atomic_inc64_nv (volatile ddsrt_atomic_uint64_t *x);
DDS_EXPORT void ddsrt_atomic_dec64 (volatile ddsrt_atomic_uint64_t *x);
DDS_EXPORT uint64_t ddsrt_atomic_dec64_nv (volatile ddsrt_atomic_uint64_t *x);
DDS_EXPORT void ddsrt_atomic_add64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
DDS_EXPORT uint64_t ddsrt_atomic_add64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
DDS_EXPORT void ddsrt_atomic_sub64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
DDS_EXPORT uint64_t ddsrt_atomic_sub64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
DDS_EXPORT void ddsrt_atomic_and64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
DDS_EXPORT uint64_t ddsrt_atomic_and64_ov (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
DDS_EXPORT uint64_t ddsrt_atomic_and64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
DDS_EXPORT void ddsrt_atomic_or64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
DDS_EXPORT uint64_t ddsrt_atomic_or64_ov (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
DDS_EXPORT uint64_t ddsrt_atomic_or64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v);
DDS_EXPORT int ddsrt_atomic_cas64 (volatile ddsrt_atomic_uint64_t *x, uint64_t exp, uint64_t des);
#endif
void ddsrt_atomics_init (void);
void ddsrt_atomics_fini (void);
#if defined(__cplusplus)
}
#endif

View file

@ -85,6 +85,9 @@ inline void *ddsrt_atomic_addvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff
inline void ddsrt_atomic_add32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
(void) ddsrt_atomic_add32_nv (x, v);
}
inline uint32_t ddsrt_atomic_add32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return ddsrt_atomic_add32_nv (x, v) - v;
}
inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) {
(void) ddsrt_atomic_addptr_nv (x, v);
}
@ -115,6 +118,9 @@ inline void ddsrt_atomic_subvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v
/* INC */
inline uint32_t ddsrt_atomic_inc32_ov (volatile ddsrt_atomic_uint32_t *x) {
return ddsrt_atomic_add32_nv (x, 1) - 1;
}
inline uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x) {
return ddsrt_atomic_add32_nv (x, 1);
}
@ -130,6 +136,9 @@ inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x) {
/* DEC */
inline uint32_t ddsrt_atomic_dec32_ov (volatile ddsrt_atomic_uint32_t *x) {
return ddsrt_atomic_sub32_nv (x, 1) + 1;
}
inline uint32_t ddsrt_atomic_dec32_nv (volatile ddsrt_atomic_uint32_t *x) {
return ddsrt_atomic_sub32_nv (x, 1);
}
@ -206,6 +215,12 @@ inline void ddsrt_atomic_orptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v)
inline void ddsrt_atomic_fence (void) {
__asm volatile ("dmb" : : : "memory");
}
inline void ddsrt_atomic_fence_ldld (void) {
ddsrt_atomic_fence ();
}
inline void ddsrt_atomic_fence_stst (void) {
ddsrt_atomic_fence ();
}
inline void ddsrt_atomic_fence_acq (void) {
ddsrt_atomic_fence ();
}

View file

@ -13,6 +13,7 @@
#define DDSRT_ATOMICS_GCC_H
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/attributes.h"
#if defined (__cplusplus)
extern "C" {
@ -25,19 +26,51 @@ extern "C" {
/* LD, ST */
inline uint32_t ddsrt_atomic_ld32(const volatile ddsrt_atomic_uint32_t *x) { return x->v; }
ddsrt_attribute_no_sanitize (("thread"))
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; }
ddsrt_attribute_no_sanitize (("thread"))
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); }
ddsrt_attribute_no_sanitize (("thread"))
inline uintptr_t ddsrt_atomic_ldptr(const volatile ddsrt_atomic_uintptr_t *x)
{
return x->v;
}
ddsrt_attribute_no_sanitize (("thread"))
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; }
ddsrt_attribute_no_sanitize (("thread"))
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; }
ddsrt_attribute_no_sanitize (("thread"))
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); }
ddsrt_attribute_no_sanitize (("thread"))
inline void ddsrt_atomic_stptr(volatile ddsrt_atomic_uintptr_t *x, uintptr_t v)
{
x->v = v;
}
ddsrt_attribute_no_sanitize (("thread"))
inline void ddsrt_atomic_stvoidp(volatile ddsrt_atomic_voidp_t *x, void *v)
{
ddsrt_atomic_stptr(x, (uintptr_t)v);
}
/* INC */
@ -52,6 +85,9 @@ inline void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x) {
inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x) {
__sync_fetch_and_add (&x->v, 1);
}
inline uint32_t ddsrt_atomic_inc32_ov (volatile ddsrt_atomic_uint32_t *x) {
return __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);
}
@ -116,6 +152,9 @@ inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t 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_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return __sync_fetch_and_add (&x->v, 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);
}
@ -147,6 +186,9 @@ inline void ddsrt_atomic_subptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t 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_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return __sync_fetch_and_sub (&x->v, 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);
}
@ -284,11 +326,24 @@ inline void ddsrt_atomic_fence_ldld (void) {
__sync_synchronize ();
#endif
}
inline void ddsrt_atomic_fence_stst (void) {
#if !(defined __i386__ || defined __x86_64__ || defined _M_IX86 || defined _M_X64)
__sync_synchronize ();
#endif
}
inline void ddsrt_atomic_fence_acq (void) {
#if !(defined __i386__ || defined __x86_64__ || defined _M_IX86 || defined _M_X64)
ddsrt_atomic_fence ();
#else
asm volatile ("" ::: "memory");
#endif
}
inline void ddsrt_atomic_fence_rel (void) {
#if !(defined __i386__ || defined __x86_64__ || defined _M_IX86 || defined _M_X64)
ddsrt_atomic_fence ();
#else
asm volatile ("" ::: "memory");
#endif
}
#if defined (__cplusplus)

View file

@ -74,6 +74,9 @@ inline void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x) {
inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x) {
DDSRT_ATOMIC_PTROP (InterlockedIncrement) (&x->v);
}
inline uint32_t ddsrt_atomic_inc32_ov (volatile ddsrt_atomic_uint32_t *x) {
return InterlockedIncrement (&x->v) - 1;
}
inline uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x) {
return InterlockedIncrement (&x->v);
}
@ -138,6 +141,9 @@ inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t 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_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return InterlockedExchangeAdd (&x->v, v);
}
inline uint32_t ddsrt_atomic_add32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return InterlockedExchangeAdd (&x->v, v) + v;
}
@ -157,46 +163,52 @@ inline void *ddsrt_atomic_addvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff
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)
DDSRT_WARNING_MSVC_OFF(4146)
InterlockedExchangeAdd (&x->v, -v);
DDSRT_WARNING_MSVC_ON(4146)
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)
DDSRT_WARNING_MSVC_OFF(4146)
InterlockedExchangeAdd64 (&x->v, -v);
DDSRT_WARNING_MSVC_ON(4146)
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_WARNING_MSVC_OFF(4146)
DDSRT_ATOMIC_PTROP (InterlockedExchangeAdd) (&x->v, -v);
DDSRT_WARNING_MSVC_ON(4146)
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_ov (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);
DDSRT_WARNING_MSVC_ON(4146)
}
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)
DDSRT_WARNING_MSVC_OFF(4146)
return InterlockedExchangeAdd (&x->v, -v) - v;
DDSRT_WARNING_MSVC_ON(4146)
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)
DDSRT_WARNING_MSVC_OFF(4146)
return InterlockedExchangeAdd64 (&x->v, -v) - v;
DDSRT_WARNING_MSVC_ON(4146)
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)
DDSRT_WARNING_MSVC_OFF(4146)
return DDSRT_ATOMIC_PTROP (InterlockedExchangeAdd) (&x->v, -v) - v;
DDSRT_WARNING_MSVC_ON(4146)
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);
@ -280,16 +292,21 @@ 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)
DDSRT_WARNING_MSVC_OFF(28113)
volatile LONG tmp = 0;
InterlockedExchange (&tmp, 0);
DDSRT_WARNING_MSVC_ON(28113)
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_stst (void) {
#if !(defined _M_IX86 || defined _M_X64)
ddsrt_atomic_fence ();
#endif
}
inline void ddsrt_atomic_fence_acq (void) {
ddsrt_atomic_fence ();
}

View file

@ -40,6 +40,11 @@ inline void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x) {
inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x) {
atomic_inc_ulong (&x->v);
}
inline uint32_t ddsrt_atomic_inc32_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 uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x) {
return atomic_inc_32_nv (&x->v);
}
@ -100,6 +105,9 @@ inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t 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_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return atomic_add_32_nv (&x->v, 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);
}
@ -127,6 +135,9 @@ inline void ddsrt_atomic_subptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t 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_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) {
return atomic_add_32_nv (&x->v, -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);
}
@ -234,7 +245,10 @@ inline void ddsrt_atomic_fence (void) {
membar_enter ();
}
inline void ddsrt_atomic_fence_ldld (void) {
membar_enter ();
membar_consumer ();
}
inline void ddsrt_atomic_fence_stst (void) {
membar_producer ();
}
inline void ddsrt_atomic_fence_acq (void) {
membar_enter ();

View file

@ -105,4 +105,22 @@
# define ddsrt_attribute_assume_aligned(params)
#endif
#if ddsrt_has_attribute(packed)
# define ddsrt_attribute_packed __attribute__ ((__packed__))
#else
# define ddsrt_attribute_packed
#endif
#if ddsrt_has_attribute(no_sanitize)
# define ddsrt_attribute_no_sanitize(params) __attribute__ ((__no_sanitize__ params))
#else
# define ddsrt_attribute_no_sanitize(params)
#endif
#if defined(__has_feature)
# define ddsrt_has_feature_thread_sanitizer __has_feature(thread_sanitizer)
#else
# define ddsrt_has_feature_thread_sanitizer 0
#endif
#endif /* DDSRT_ATTRIBUTES_H */

View file

@ -0,0 +1,20 @@
/*
* Copyright(c) 2019 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_COUNTARGS_H
#define DDSRT_COUNTARGS_H
#define DDSRT_COUNT_ARGS_MSVC_WORKAROUND(x) x
#define DDSRT_COUNT_ARGS(...) DDSRT_COUNT_ARGS1 (__VA_ARGS__, 10,9,8,7,6,5,4,3,2,1,0)
#define DDSRT_COUNT_ARGS1(...) DDSRT_COUNT_ARGS_MSVC_WORKAROUND (DDSRT_COUNT_ARGS_ARGN (__VA_ARGS__))
#define DDSRT_COUNT_ARGS_ARGN(a,b,c,d,e,f,g,h,i,j,n,...) n
#endif

View file

@ -47,7 +47,7 @@ typedef struct ddsrt_dynlib *ddsrt_dynlib_t;
* @param[in] translate Automatic name translation on/off.
* @param[out] handle Library handle that will be assigned after successfull operation. It is assigned to NULL if loading fails.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Library handle was successfully loaded.
@ -57,7 +57,7 @@ typedef struct ddsrt_dynlib *ddsrt_dynlib_t;
* Loading failed.
* Use ddsrt_dlerror() to diagnose the failure.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_dlopen(
const char *name,
bool translate,
@ -73,7 +73,7 @@ ddsrt_dlopen(
*
* @param[in] handle Library handle.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Library handle was successfully closed.
@ -81,7 +81,7 @@ ddsrt_dlopen(
* Library closing failed.
* Use ddsrt_dlerror() to diagnose the failure.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_dlclose(
ddsrt_dynlib_t handle);
@ -95,7 +95,7 @@ ddsrt_dlclose(
* @param[in] symbol Symbol name.
* @param[out] address The memory address of the loaded symbol (void*).
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Symbol was found in the loaded library.
@ -104,7 +104,7 @@ ddsrt_dlclose(
* Symbol was not found.
* Use ddsrt_dlerror() to diagnose the failure.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_dlsym(
ddsrt_dynlib_t handle,
const char *symbol,
@ -124,14 +124,14 @@ ddsrt_dlsym(
* function should be called immediately after calling ddsrt_dlopen or ddsrt_dlsym
* function.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Most recent library related error returned.
* @retval DDS_RETCODE_NOT_FOUND
* No library related error found.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_dlerror(
char *buf,
size_t buflen);

View file

@ -25,7 +25,15 @@ extern "C" {
# else
# define DDSRT_ENDIAN DDSRT_LITTLE_ENDIAN
# endif
#else /* _WIN32 */
/* _WIN32 */
#elif defined(__IAR_SYSTEMS_ICC__)
# if __LITTLE_ENDIAN__ == 1
# define DDSRT_ENDIAN DDSRT_LITTLE_ENDIAN
# else
# define DDSRT_ENDIAN DDSRT_BIG_ENDIAN
# endif
/* __IAR_SYSTEMS_ICC__ */
#else
# if defined(__BYTE_ORDER__)
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define DDSRT_ENDIAN DDSRT_BIG_ENDIAN

View file

@ -24,13 +24,9 @@ extern "C" {
* @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.
* @param[out] value Alias to value of environment variable - must not be modified
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Environment variable written to @buf.
@ -43,7 +39,7 @@ extern "C" {
* @retval DDS_RETCODE_ERROR
* Unspecified error.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_getenv(
const char *name,
char **value)
@ -58,7 +54,7 @@ ddsrt_nonnull_all;
* @param[in] name Environment variable name.
* @param[in] value Value to set environment variable to.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Environment variable successfully set to @value.
@ -69,7 +65,7 @@ ddsrt_nonnull_all;
* @retval DDS_RETCODE_ERROR
* Unspecified system error.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_setenv(
const char *name,
const char *value)
@ -80,7 +76,7 @@ ddsrt_nonnull_all;
*
* @param[in] name Environment variable name.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Environment variable successfully unset.
@ -91,7 +87,7 @@ ddsrt_nonnull_all;
* @retval DDS_RETCODE_ERROR
* Unspecified system error.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_unsetenv(
const char *name)
ddsrt_nonnull_all;
@ -104,6 +100,10 @@ ddsrt_nonnull_all;
* The result string should be freed with ddsrt_free().
*
* @param[in] string String to expand.
* @param[in] domid Domain id that this is relevant to
* UINT32_MAX means none (see logging)
* also made available as
* ${CYCLONEDDS_DOMAIN_ID}
*
* @returns Allocated char*.
*
@ -115,7 +115,8 @@ ddsrt_nonnull_all;
*/
DDS_EXPORT char*
ddsrt_expand_envvars(
const char *string);
const char *string,
uint32_t domid);
/**
* @brief Expand environment variables within string.
@ -137,7 +138,8 @@ ddsrt_expand_envvars(
*/
DDS_EXPORT char*
ddsrt_expand_envvars_sh(
const char *string);
const char *string,
uint32_t domid);
#if defined(__cplusplus)

View file

@ -20,15 +20,6 @@
extern "C" {
#endif
/* Concurrent version */
struct ddsrt_chh;
struct ddsrt_chh_bucket;
struct ddsrt_chh_iter {
struct ddsrt_chh_bucket *bs;
uint32_t size;
uint32_t cursor;
};
/*
* The hopscotch hash table is dependent on a proper functioning hash.
* If the hash function generates a lot of hash collisions, then it will
@ -39,29 +30,20 @@ struct ddsrt_chh_iter {
* When proper distributed hash values are generated, then hopscotch
* works nice and quickly.
*/
typedef uint32_t (*ddsrt_hh_hash_fn) (const void *);
typedef uint32_t (*ddsrt_hh_hash_fn) (const void *a);
/*
* Hopscotch needs to be able to compare two elements.
* Returns 0 when not equal.
*/
typedef int (*ddsrt_hh_equals_fn) (const void *, const void *);
typedef int (*ddsrt_hh_equals_fn) (const void *a, const void *b);
/*
* Hopscotch is will resize its internal buckets list when needed. It will
* call this garbage collection function with the old buckets list. The
* caller has to delete the list when it deems it safe to do so.
*/
typedef void (*ddsrt_hh_buckets_gc_fn) (void *);
DDS_EXPORT struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets);
DDS_EXPORT void ddsrt_chh_free (struct ddsrt_chh * __restrict hh);
DDS_EXPORT void *ddsrt_chh_lookup (struct ddsrt_chh * __restrict rt, const void * __restrict template);
DDS_EXPORT int ddsrt_chh_add (struct ddsrt_chh * __restrict rt, const void * __restrict data);
DDS_EXPORT int ddsrt_chh_remove (struct ddsrt_chh * __restrict rt, const void * __restrict template);
DDS_EXPORT void ddsrt_chh_enum_unsafe (struct ddsrt_chh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg); /* may delete a */
void *ddsrt_chh_iter_first (struct ddsrt_chh * __restrict rt, struct ddsrt_chh_iter *it);
void *ddsrt_chh_iter_next (struct ddsrt_chh_iter *it);
typedef void (*ddsrt_hh_buckets_gc_fn) (void *bs, void *arg);
/* Sequential version */
struct ddsrt_hh;
@ -80,6 +62,31 @@ DDS_EXPORT void ddsrt_hh_enum (struct ddsrt_hh * __restrict rt, void (*f) (void
DDS_EXPORT void *ddsrt_hh_iter_first (struct ddsrt_hh * __restrict rt, struct ddsrt_hh_iter * __restrict iter); /* may delete nodes */
DDS_EXPORT void *ddsrt_hh_iter_next (struct ddsrt_hh_iter * __restrict iter);
/* Concurrent version */
struct ddsrt_chh;
struct ddsrt_chh_bucket;
#if ! ddsrt_has_feature_thread_sanitizer
struct ddsrt_chh_iter {
struct ddsrt_chh_bucket *bs;
uint32_t size;
uint32_t cursor;
};
#else
struct ddsrt_chh_iter {
struct ddsrt_chh *chh;
struct ddsrt_hh_iter it;
};
#endif
DDS_EXPORT struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets, void *gc_buckets_arg);
DDS_EXPORT void ddsrt_chh_free (struct ddsrt_chh * __restrict hh);
DDS_EXPORT void *ddsrt_chh_lookup (struct ddsrt_chh * __restrict rt, const void * __restrict template);
DDS_EXPORT int ddsrt_chh_add (struct ddsrt_chh * __restrict rt, const void * __restrict data);
DDS_EXPORT int ddsrt_chh_remove (struct ddsrt_chh * __restrict rt, const void * __restrict template);
DDS_EXPORT void ddsrt_chh_enum_unsafe (struct ddsrt_chh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg); /* may delete a */
DDS_EXPORT void *ddsrt_chh_iter_first (struct ddsrt_chh * __restrict rt, struct ddsrt_chh_iter *it);
DDS_EXPORT void *ddsrt_chh_iter_next (struct ddsrt_chh_iter *it);
/* Sequential version, embedded data */
struct ddsrt_ehh;

View file

@ -18,11 +18,18 @@
extern "C" {
#endif
enum ddsrt_iftype {
DDSRT_IFTYPE_UNKNOWN,
DDSRT_IFTYPE_WIRED,
DDSRT_IFTYPE_WIFI
};
struct ddsrt_ifaddrs {
struct ddsrt_ifaddrs *next;
char *name;
uint32_t index;
uint32_t flags;
enum ddsrt_iftype type;
struct sockaddr *addr;
struct sockaddr *netmask;
struct sockaddr *broadaddr;
@ -30,7 +37,7 @@ struct ddsrt_ifaddrs {
typedef struct ddsrt_ifaddrs ddsrt_ifaddrs_t;
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_getifaddrs(
ddsrt_ifaddrs_t **ifap,
const int *afs);

View file

@ -92,6 +92,8 @@ extern "C" {
typedef struct {
/** Log category the message falls into. */
uint32_t priority;
/** Log domain id, UINT32_MAX is global. */
uint32_t domid;
/** Filename where message was generated. */
const char *file;
/** Line number in file where message was generated. */
@ -102,10 +104,38 @@ typedef struct {
const char *message;
/** Size of log message. */
size_t size;
/** Default log message header length */
size_t hdrsize;
} 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 *);
typedef void (*dds_log_write_fn_t) (void *, const dds_log_data_t *);
/** Semi-opaque type for log/trace configuration. */
struct ddsrt_log_cfg_common {
/** Mask for testing whether the xLOG macro should forward to the
function (and so incur the cost of constructing the parameters).
Messages in DDS_LOG_MASK are rare, so the overhead of calling
the function and then dropping the message is not an issue, unlike
for messages in DDS_TRACE_MASK. */
uint32_t mask;
/** The actual configured trace mask */
uint32_t tracemask;
/** Domain id for reporting; UINT32_MAX = no domain */
uint32_t domid;
};
typedef struct ddsrt_log_cfg {
struct ddsrt_log_cfg_common c;
union {
dds_log_write_fn_t fnptr;
void *ptr;
uint32_t u32;
unsigned char pad[72];
} u;
} ddsrt_log_cfg_t;
DDS_EXPORT extern uint32_t *const dds_log_mask;
@ -186,14 +216,84 @@ dds_set_trace_sink(
void *userdata);
/**
* @brief Write a log or trace message.
* @brief Initialize a struct ddsrt_log_cfg for use with dds_log_cfg
*
* 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.
*
* 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[out] cfg On return, initialised to make dds_log_cfg invoked
* with this config object behave as specified by the
* other parameters.
* @param[in] domid Numerical identifier in log/trace, UINT32_MAX is
* reserved for global logging.
* @param[in] tracemask Mask determining which traces should be written.
* @param[in] log_fp File for default sink.
* @param[in] trace_fp File for default sink.
*/
DDS_EXPORT void
dds_log_cfg_init(
struct ddsrt_log_cfg *cfg,
uint32_t domid,
uint32_t tracemask,
FILE *log_fp,
FILE *trace_fp);
/**
* @brief Write a log or trace message for a specific logging configuraiton
* (categories, id, sinks).
*
* Direct use of #dds_log is discouraged. Use #DDS_CINFO, #DDS_CWARNING,
* #DDS_CERROR, #DDS_CTRACE or #DDS_CLOG instead.
*/
DDS_EXPORT void
dds_log_cfg(
const struct ddsrt_log_cfg *cfg,
uint32_t prio,
const char *file,
uint32_t line,
const char *func,
const char *fmt,
...)
ddsrt_attribute_format((__printf__, 6, 7));
/**
* @brief Write a log or trace message to the global configuration but with
* specific domain (intended solely for use during domain start-up, while
* the domain-specific logging/tracing hasn't been set yet).
*
* Write a log or trace message to one (or both) of the currently active sinks.
*
* Direct use of #dds_log_id is discouraged. Use #DDS_ILOG instead.
*/
DDS_EXPORT void
dds_log_id(
uint32_t prio,
uint32_t domid,
const char *file,
uint32_t line,
const char *func,
const char *fmt,
...)
ddsrt_attribute_format((__printf__, 6, 7));
/**
* @brief Write a log or trace message to the global log/trace.
*
* 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_EXPORT void
dds_log(
uint32_t prio,
const char *file,
@ -279,23 +379,70 @@ dds_log(
*/
#define DDS_LOG(cat, ...) \
((dds_get_log_mask() & (cat)) ? \
dds_log(cat, __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0)
dds_log((cat), __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0)
/** Write a log message of type #DDS_LC_INFO. */
/**
* @brief Write a log message with a domain id override.
*
* 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_ILOG(cat, domid, ...) \
((dds_get_log_mask() & (cat)) ? \
dds_log_id((cat), (domid), __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0)
/**
* @brief Write a log message using a specific config.
*
* 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_CLOG(cat, cfg, ...) \
(((cfg)->c.mask & (cat)) ? \
dds_log_cfg((cfg), (cat), __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0)
/** Write a log message of type #DDS_LC_INFO into global log. */
#define DDS_INFO(...) \
DDS_LOG(DDS_LC_INFO, __VA_ARGS__)
/** Write a log message of type #DDS_LC_WARNING. */
/** Write a log message of type #DDS_LC_WARNING into global log. */
#define DDS_WARNING(...) \
DDS_LOG(DDS_LC_WARNING, __VA_ARGS__)
/** Write a log message of type #DDS_LC_ERROR. */
/** Write a log message of type #DDS_LC_ERROR into global log. */
#define DDS_ERROR(...) \
DDS_LOG(DDS_LC_ERROR, __VA_ARGS__)
/** Write a log message of type #DDS_LC_ERROR and abort. */
/** Write a log message of type #DDS_LC_ERROR into global log 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__)
/* MSVC mishandles __VA_ARGS__ while claiming to be conforming -- and even
if they have a defensible implement, they still differ from every other
compiler out there. An extra layer of macro expansion works around it. */
#define DDS_CLOG_MSVC_WORKAROUND(x) x
/** Write a log message of type #DDS_LC_INFO using specific logging config. */
#define DDS_CINFO(...) \
DDS_CLOG_MSVC_WORKAROUND(DDS_CLOG(DDS_LC_INFO, __VA_ARGS__))
/** Write a log message of type #DDS_LC_WARNING using specific logging config. */
#define DDS_CWARNING(...) \
DDS_CLOG_MSVC_WORKAROUND(DDS_CLOG(DDS_LC_WARNING, __VA_ARGS__))
/** Write a log message of type #DDS_LC_ERROR using specific logging config. */
#define DDS_CERROR(...) \
DDS_CLOG_MSVC_WORKAROUND(DDS_CLOG(DDS_LC_ERROR, __VA_ARGS__))
/** Write a #DDS_LC_TRACE message using specific logging config. */
#define DDS_CTRACE(...) \
DDS_CLOG_MSVC_WORKAROUND(DDS_CLOG(DDS_LC_TRACE, __VA_ARGS__))
#if defined (__cplusplus)
}

View file

@ -18,29 +18,45 @@
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_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
#if defined(__clang__) || \
defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
# define DDSRT_STR(s) #s
# define DDSRT_JOINSTR(x,y) DDSRT_STR(x ## y)
# define DDSRT_DO_PRAGMA(x) _Pragma(#x)
# define DDSRT_PRAGMA(x) DDSRT_DO_PRAGMA(GCC diagnostic x)
# if defined(__clang__)
# define DDSRT_WARNING_CLANG_OFF(x) \
DDSRT_PRAGMA(push) \
DDSRT_PRAGMA(ignored DDSRT_JOINSTR(-W,x))
# define DDSRT_WARNING_CLANG_ON(x) \
DDSRT_PRAGMA(pop)
# elif ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
# define DDSRT_WARNING_GNUC_OFF(x) \
DDSRT_GNUC_PRAGMA(push) \
DDSRT_GNUC_PRAGMA(ignored DDSRT_GNUC_JOINSTR(-W,x))
DDSRT_PRAGMA(push) \
DDSRT_PRAGMA(ignored DDSRT_JOINSTR(-W,x))
# define DDSRT_WARNING_GNUC_ON(x) \
DDSRT_GNUC_PRAGMA(pop)
DDSRT_PRAGMA(pop)
# else
# define DDSRT_WARNING_GNUC_OFF(x) \
DDSRT_GNUC_PRAGMA(ignored DDSRT_GNUC_JOINSTR(-W,x))
DDSRT_PRAGMA(ignored DDSRT_JOINSTR(-W,x))
# define DDSRT_WARNING_GNUC_ON(x) \
DDSRT_GNUC_PRAGMA(warning DDSRT_GNUC_JOINSTR(-W,x))
DDSRT_PRAGMA(warning DDSRT_JOINSTR(-W,x))
# endif
#else
#endif
#if !defined(DDSRT_WARNING_CLANG_OFF) && \
!defined(DDSRT_WARNING_CLANG_ON)
# define DDSRT_WARNING_CLANG_OFF(x)
# define DDSRT_WARNING_CLANG_ON(x)
#endif
#if !defined(DDSRT_WARNING_GNUC_OFF) && \
!defined(DDSRT_WARNING_GNUC_ON)
# 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)) \
@ -52,23 +68,6 @@ extern "C" {
# 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
*/

View file

@ -0,0 +1,73 @@
/*
* Copyright(c) 2019 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_NETSTAT_H
#define DDSRT_NETSTAT_H
#include <stdint.h>
#include "dds/export.h"
#include "dds/ddsrt/retcode.h"
#if defined (__linux) || defined (__APPLE__) || defined (_WIN32)
#define DDSRT_HAVE_NETSTAT (1)
#else
#define DDSRT_HAVE_NETSTAT (0)
#endif
#if DDSRT_HAVE_NETSTAT
#if defined(__cplusplus)
extern "C" {
#endif
struct ddsrt_netstat {
uint64_t ipkt;
uint64_t opkt;
uint64_t ibytes;
uint64_t obytes;
};
/**
* @brief Platform dependent control structure for network statistics
*/
struct ddsrt_netstat_control;
/**
* @brief Prepare for gathering network statistics for specified interface.
*/
DDS_EXPORT dds_return_t
ddsrt_netstat_new (
struct ddsrt_netstat_control **control,
const char *device);
/**
* @brief Release resources for gathering network statistics.
*/
DDS_EXPORT dds_return_t
ddsrt_netstat_free (
struct ddsrt_netstat_control *control);
/**
* @brief Get network statistics.
*/
DDS_EXPORT dds_return_t
ddsrt_netstat_get (
struct ddsrt_netstat_control *control,
struct ddsrt_netstat *stats);
#if defined(__cplusplus)
}
#endif
#endif /* DDSRT_HAVE_NETSTAT */
#endif /* DDSRT_NETSTAT_H */

View file

@ -17,19 +17,30 @@
#include "dds/ddsrt/types.h"
#include "dds/ddsrt/retcode.h"
#if defined(_WIN32)
#if DDSRT_WITH_FREERTOS
#include <FreeRTOS.h>
#include <task.h>
typedef TaskHandle_t ddsrt_pid_t; /* typedef void *TaskHandle_t */
#define PRIdPID "p"
#define DDSRT_HAVE_MULTI_PROCESS 0
/* DDSRT_WITH_FREERTOS */
#elif defined(_WIN32)
typedef DWORD ddsrt_pid_t;
#define PRIdPID "u"
#else /* _WIN32 */
#define DDSRT_HAVE_MULTI_PROCESS 1
/* _WIN32 */
#else
#include <unistd.h>
#if defined(_WRS_KERNEL)
typedef RTP_ID ddsrt_pid_t; /* typedef struct wind_rtp *RTP_ID */
#define PRIdPID PRIuPTR
#define DDSRT_HAVE_MULTI_PROCESS 0
#else
typedef pid_t ddsrt_pid_t;
#define PRIdPID "d"
#define DDSRT_HAVE_MULTI_PROCESS 1
#endif
#endif
#endif /* _WIN32 */
#if defined (__cplusplus)
@ -44,6 +55,7 @@ extern "C" {
DDS_EXPORT ddsrt_pid_t
ddsrt_getpid(void);
#if DDSRT_HAVE_MULTI_PROCESS
/**
* @brief Create new process.
@ -60,7 +72,7 @@ ddsrt_getpid(void);
* @param[in] argv Arguments array.
* @param[out] pid ID of the created process.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Process successfully created.
@ -73,7 +85,7 @@ ddsrt_getpid(void);
* @retval DDS_RETCODE_ERROR
* Process could not be created.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_proc_create(
const char *executable,
char *const argv[],
@ -94,10 +106,10 @@ ddsrt_proc_create(
* See ddsrt_proc_waitpids() for waiting on all child processes.
*
* @param[in] pid Process ID (PID) to get the exit code from.
* @param[in] timemout Time within the process is expected to finish.
* @param[in] timeout Time within the process is expected to finish.
* @param[out] code The exit code of the process.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Process has terminated and its exit code has been captured.
@ -112,7 +124,7 @@ ddsrt_proc_create(
* @retval DDS_RETCODE_ERROR
* Getting the exit code failed for an unknown reason.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_proc_waitpid(
ddsrt_pid_t pid,
dds_duration_t timeout,
@ -133,11 +145,11 @@ ddsrt_proc_waitpid(
*
* See ddsrt_proc_waitpid() for waiting on a specific child process.
*
* @param[in] timemout Time within a process is expected to finish.
* @param[in] timeout Time within a process is expected to finish.
* @param[out] pid Process ID (PID) of the finished process.
* @param[out] code The exit code of the process.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* A process has terminated.
@ -153,7 +165,7 @@ ddsrt_proc_waitpid(
* @retval DDS_RETCODE_ERROR
* Getting the exit code failed for an unknown reason.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_proc_waitpids(
dds_duration_t timeout,
ddsrt_pid_t *pid,
@ -164,7 +176,7 @@ ddsrt_proc_waitpids(
*
* @param[in] pid Process ID (PID) to check if it exists.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* The process exists.
@ -173,7 +185,7 @@ ddsrt_proc_waitpids(
* @retval DDS_RETCODE_ERROR
* Determining if a process exists or not, failed.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_proc_exists(
ddsrt_pid_t pid);
@ -190,7 +202,7 @@ ddsrt_proc_exists(
*
* @param[in] pid Process ID (PID) of the process to terminate.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Kill attempt has been started.
@ -201,10 +213,11 @@ ddsrt_proc_exists(
* @retval DDS_RETCODE_ERROR
* Kill failed for an unknown reason.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_proc_kill(
ddsrt_pid_t pid);
#endif /* DDSRT_HAVE_MULTI_PROCESS */
#if defined (__cplusplus)
}

View file

@ -9,7 +9,7 @@
extern "C" {
#endif
typedef int32_t dds_retcode_t;
typedef int32_t dds_return_t;
/*
State is unchanged following a function call returning an error
@ -29,25 +29,25 @@ typedef int32_t dds_retcode_t;
* @{
*/
#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 */
#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))
#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)
@ -84,11 +84,11 @@ typedef int32_t dds_retcode_t;
/**
* @brief Takes the error value and outputs a string corresponding to it.
*
* @param[in] err Error value to be converted to a string
* @param[in] ret 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);
DDS_EXPORT const char *dds_strretcode(dds_return_t ret);
#if defined (__cplusplus)
}

View file

@ -14,8 +14,23 @@
#include <stddef.h>
#if DDSRT_WITH_FREERTOS
#include <FreeRTOS.h>
# if configUSE_TRACE_FACILITY == 1 && \
configGENERATE_RUN_TIME_STATS == 1
# define DDSRT_HAVE_RUSAGE 1
# else
# define DDSRT_HAVE_RUSAGE 0
#endif
#elif defined (_WIN32) || defined (__linux) || defined (__APPLE__)
# define DDSRT_HAVE_RUSAGE 1
#else
# define DDSRT_HAVE_RUSAGE 0
#endif
#include "dds/ddsrt/time.h"
#include "dds/ddsrt/retcode.h"
#include "dds/ddsrt/threads.h"
#if defined (__cplusplus)
extern "C" {
@ -31,8 +46,10 @@ typedef struct {
size_t nivcsw; /* Involuntary context switches. Not maintained on Windows. */
} ddsrt_rusage_t;
#define DDSRT_RUSAGE_SELF (0)
#define DDSRT_RUSAGE_THREAD (1)
enum ddsrt_getrusage_who {
DDSRT_RUSAGE_SELF,
DDSRT_RUSAGE_THREAD
};
/**
* @brief Get resource usage for the current thread or process.
@ -40,7 +57,7 @@ typedef struct {
* @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.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Resource usage successfully returned in @usage.
@ -49,7 +66,26 @@ typedef struct {
* @retval DDS_RETCODE_ERROR
* An unidentified error occurred.
*/
DDS_EXPORT dds_retcode_t ddsrt_getrusage(int who, ddsrt_rusage_t *usage);
DDS_EXPORT dds_return_t ddsrt_getrusage(enum ddsrt_getrusage_who who, ddsrt_rusage_t *usage);
#if DDSRT_HAVE_THREAD_LIST
/**
* @brief Get resource usage for some thread.
*
* @param[in] tid id of the thread of to get the resource usage for
* @param[in] usage Structure where resource usage is returned.
*
* @returns A dds_return_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_return_t ddsrt_getrusage_anythread (ddsrt_thread_list_id_t tid, ddsrt_rusage_t * __restrict usage);
#endif
#if defined (__cplusplus)
}

View file

@ -3,6 +3,10 @@
#include <stdbool.h>
#if !defined(DDSRT_WITH_DNS)
# define DDSRT_WITH_DNS 1
#endif
#include "dds/export.h"
#include "dds/ddsrt/types.h"
#include "dds/ddsrt/attributes.h"
@ -28,53 +32,53 @@ extern const struct in6_addr ddsrt_in6addr_loopback;
#define DDSRT_AF_TERM (-1)
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_gethostname(
char *hostname,
size_t buffersize);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_socket(
ddsrt_socket_t *sockptr,
int domain,
int type,
int protocol);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_close(
ddsrt_socket_t sock);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_connect(
ddsrt_socket_t sock,
const struct sockaddr *addr,
socklen_t addrlen);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_accept(
ddsrt_socket_t sock,
struct sockaddr *addr,
socklen_t *addrlen,
ddsrt_socket_t *connptr);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_listen(
ddsrt_socket_t sock,
int backlog);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_bind(
ddsrt_socket_t sock,
const struct sockaddr *addr,
socklen_t addrlen);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_getsockname(
ddsrt_socket_t sock,
struct sockaddr *addr,
socklen_t *addrlen);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_send(
ddsrt_socket_t sock,
const void *buf,
@ -82,14 +86,14 @@ ddsrt_send(
int flags,
ssize_t *sent);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_sendmsg(
ddsrt_socket_t sock,
const ddsrt_msghdr_t *msg,
int flags,
ssize_t *sent);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_recv(
ddsrt_socket_t sock,
void *buf,
@ -97,14 +101,14 @@ ddsrt_recv(
int flags,
ssize_t *rcvd);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_recvmsg(
ddsrt_socket_t sock,
ddsrt_msghdr_t *msg,
int flags,
ssize_t *rcvd);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_getsockopt(
ddsrt_socket_t sock,
int32_t level, /* SOL_SOCKET */
@ -112,7 +116,7 @@ ddsrt_getsockopt(
void *optval,
socklen_t *optlen);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_setsockopt(
ddsrt_socket_t sock,
int32_t level, /* SOL_SOCKET */
@ -126,7 +130,7 @@ ddsrt_setsockopt(
* @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.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* I/O mode successfully set to (non)blocking.
@ -137,7 +141,7 @@ ddsrt_setsockopt(
* @retval DDS_RETCODE_ERROR
* An unknown error error occurred.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_setsocknonblocking(
ddsrt_socket_t sock,
bool nonblock);
@ -224,11 +228,11 @@ ddsrt_sockaddr_insamesubnet(
const struct sockaddr *mask)
ddsrt_nonnull_all;
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_sockaddrfromstr(
int af, const char *str, void *sa);
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_sockaddrtostr(
const void *sa, char *buf, size_t size);
@ -243,9 +247,9 @@ typedef struct {
*
* @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.
* @param[out] hentp Structure of type ddsrt_hostent_t.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Host name successfully resolved to address(es).
@ -258,7 +262,7 @@ typedef struct {
* @retval DDS_RETCODE_TRY_AGAIN
* Nonauthoratitative host not found.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_gethostbyname(
const char *name,
int af,

View file

@ -12,12 +12,17 @@
#ifndef DDSRT_SOCKETS_POSIX_H
#define DDSRT_SOCKETS_POSIX_H
#if DDSRT_WITH_LWIP
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#else
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#endif
#if defined(__cplusplus)
extern "C" {
@ -27,21 +32,51 @@ 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
#if LWIP_SOCKET
# if LWIP_IPV6
# define DDSRT_HAVE_IPV6 1
# endif
# if LWIP_DNS && LWIP_SOCKET
# define DDSRT_HAVE_DNS DDSRT_WITH_DNS
# define DDSRT_HAVE_GETADDRINFO DDSRT_WITH_DNS
# endif
# define DDSRT_HAVE_SSM 0
# define DDSRT_HAVE_INET_NTOP 1
# define DDSRT_HAVE_INET_PTON 1
# define IFF_UP 0x1
# define IFF_BROADCAST 0x2
# define IFF_LOOPBACK 0x8
# define IFF_POINTOPOINT 0x10
# define IFF_MULTICAST 0x1000
#elif __SunOS_5_6
# define DDSRT_HAVE_IPV6 0
# define DDSRT_HAVE_DNS DDSRT_WITH_DNS
# define DDSRT_HAVE_GETADDRINFO 0
# define DDSRT_HAVE_SSM 0
# define DDSRT_HAVE_INET_NTOP 0
# define DDSRT_HAVE_INET_PTON 0
#else /* LWIP_SOCKET */
# define DDSRT_HAVE_IPV6 1
# define DDSRT_HAVE_DNS DDSRT_WITH_DNS
# define DDSRT_HAVE_GETADDRINFO DDSRT_WITH_DNS
# define DDSRT_HAVE_SSM 1
# define DDSRT_HAVE_INET_NTOP 1
# define DDSRT_HAVE_INET_PTON 1
#endif /* LWIP_SOCKET */
typedef struct iovec ddsrt_iovec_t;
typedef size_t ddsrt_iov_len_t;
#if defined(__linux)
#if defined(__linux) && !LWIP_SOCKET
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)
#if (defined(__sun) && !defined(_XPG4_2)) || \
(defined(LWIP_SOCKET))
# define DDSRT_MSGHDR_FLAGS 0
#else
# define DDSRT_MSGHDR_FLAGS 1

View file

@ -12,8 +12,11 @@ typedef SOCKET ddsrt_socket_t;
#define DDSRT_INVALID_SOCKET (INVALID_SOCKET)
#define PRIdSOCK PRIuPTR
#define DDSRT_HAVE_IPV6 1
#define DDSRT_HAVE_DNS 1
#define DDSRT_HAVE_IPV6 1
#define DDSRT_HAVE_DNS DDSRT_WITH_DNS
#define DDSRT_HAVE_GETADDRINFO DDSRT_WITH_DNS
#define DDSRT_HAVE_INET_NTOP 1
#define DDSRT_HAVE_INET_PTON 1
#if defined(NTDDI_VERSION) && \
defined(_WIN32_WINNT_WS03) && \

View file

@ -0,0 +1,42 @@
/*
* Copyright(c) 2019 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_STATIC_ASSERT_H
#define DDSRT_STATIC_ASSERT_H
/* There are many tricks to use a constant expression to yield an
illegal type or expression at compile time, such as zero-sized
arrays and duplicate case or enum labels. So this is but one of the
many tricks. */
#define DDSRT_STATIC_ASSERT2(line, pred) \
struct static_assert_##line { \
char cond[(pred) ? 1 : -1]; \
}
#define DDSRT_STATIC_ASSERT1(line, pred) \
DDSRT_STATIC_ASSERT2 (line, pred)
#define DDSRT_STATIC_ASSERT(pred) \
DDSRT_STATIC_ASSERT1 (__LINE__, pred)
#ifndef _MSC_VER
#define DDSRT_STATIC_ASSERT_CODE(pred) do { switch(0) { case 0: case (pred): ; } } while (0)
#else
/* Temporarily disabling warning C6326: Potential comparison of a
constant with another constant. */
#define DDSRT_STATIC_ASSERT_CODE(pred) do { \
__pragma (warning (push)) \
__pragma (warning (disable : 6326)) \
switch(0) { case 0: case (pred): ; } \
__pragma (warning (pop)) \
} while (0)
#endif
#endif

View file

@ -12,7 +12,6 @@
#ifndef DDSRT_STRING_H
#define DDSRT_STRING_H
#include <stdbool.h>
#include "dds/export.h"
#include "dds/ddsrt/attributes.h"
#include "dds/ddsrt/retcode.h"
@ -53,21 +52,6 @@ ddsrt_strncasecmp(
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.
*
@ -75,7 +59,7 @@ ddsrt_strtok_r(
* @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,out] stringp String to extract token from.
* @param[in] delim Characters that delimit a token.
*
* @returns The original value of @stringp.
@ -154,7 +138,7 @@ ddsrt_nonnull((1,2));
* 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,out] dest Destination buffer.
* @param[in] src Null terminated string to append to dest.
* @param[in] size Number of bytes available in dest.
*
@ -170,8 +154,6 @@ ddsrt_strlcat(
size_t size)
ddsrt_nonnull((1,2));
/**
* @brief Get description for specified system error number.
*
@ -179,7 +161,7 @@ ddsrt_nonnull((1,2));
* @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.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Description for @errnum was successfully copied to @buf.
@ -188,7 +170,7 @@ ddsrt_nonnull((1,2));
* @retval DDS_RETCODE_NOT_ENOUGH_SPACE
* Buffer was not large enough to hold the description.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_strerror_r(
int errnum,
char *buf,

View file

@ -34,9 +34,9 @@ extern "C" {
* character is stored.
* @param[out] dblptr A double where the result is stored.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_strtod(const char *nptr, char **endptr, double *dblptr);
/**
@ -47,9 +47,9 @@ ddsrt_strtod(const char *nptr, char **endptr, double *dblptr);
* character is stored.
* @param[out] fltptr A float where the floating-point number is stored.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_strtof(const char *nptr, char **endptr, float *fltptr);
/**

View file

@ -37,7 +37,7 @@ extern "C" {
* determine from @str.
* @param[out] llng A long long integer where the number is stored.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* String successfully converted to an integer.
@ -46,7 +46,7 @@ extern "C" {
* @retval DDS_RETCODE_OUT_OF_RANGE
* String converted to an integer, but was out of range.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_strtoll(
const char *str,
char **endptr,
@ -69,7 +69,7 @@ ddsrt_strtoll(
* determine from @str.
* @param[out] ullng A long long integer where the number is stored.
*
* @returns A dds_retcode_t indicating success or failure.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* String successfully converted to an integer.
@ -78,7 +78,7 @@ ddsrt_strtoll(
* @retval DDS_RETCODE_OUT_OF_RANGE
* String converted to an integer, but was out of range.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_strtoull(
const char *str,
char **endptr,
@ -91,7 +91,7 @@ ddsrt_strtoull(
* @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.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* String successfully converted to an integer.
@ -100,7 +100,7 @@ ddsrt_strtoull(
* @retval DDS_RETCODE_OUT_OF_RANGE
* String converted to an integer, but was out of range.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_atoll(
const char *str,
long long *llng);
@ -111,7 +111,7 @@ ddsrt_atoll(
* @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.
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* String successfully converted to an integer.
@ -120,7 +120,7 @@ ddsrt_atoll(
* @retval DDS_RETCODE_OUT_OF_RANGE
* String converted to an integer, but was out of range.
*/
DDS_EXPORT dds_retcode_t
DDS_EXPORT dds_return_t
ddsrt_atoull(
const char *str,
unsigned long long *ullng);

View file

@ -18,8 +18,12 @@
#include "dds/ddsrt/retcode.h"
#include "dds/ddsrt/attributes.h"
#if _WIN32
#if DDSRT_WITH_FREERTOS
#include "dds/ddsrt/sync/freertos.h"
#elif _WIN32
#include "dds/ddsrt/sync/windows.h"
#elif __SunOS_5_6
#include "dds/ddsrt/sync/solaris2.6.h"
#else
#include "dds/ddsrt/sync/posix.h"
#endif

View file

@ -0,0 +1,93 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef DDSRT_SYNC_FREERTOS_H
#define DDSRT_SYNC_FREERTOS_H
#include <FreeRTOS.h>
#include <semphr.h>
#include <task.h>
#include <stddef.h>
#include "dds/ddsrt/atomics.h"
#if (INCLUDE_vTaskSuspend != 1)
/* INCLUDE_vTaskSuspend must be set to 1 to make xSemaphoreTake wait
indefinitely when passed portMAX_DELAY. See reference manual. */
#error "INCLUDE_vTaskSuspend != 1 in FreeRTOSConfig.h"
#endif
#if defined (__cplusplus)
extern "C" {
#endif
typedef struct {
SemaphoreHandle_t sem;
} ddsrt_mutex_t;
typedef struct {
size_t len;
size_t cnt;
size_t off;
size_t end;
TaskHandle_t *tasks;
} ddsrt_tasklist_t;
typedef struct {
SemaphoreHandle_t sem;
ddsrt_tasklist_t tasks;
} ddsrt_cond_t;
/* This readers-writer lock implementation does not prefer writers over readers
or vice versa. Multiple readers are allowed to hold the lock simultaneously
and can acquire it directly if no writers are queued. However, if a writer
is queued, new readers and writers are queued behind it in order. Any reader
that acquires the lock after a writer frees it, notifies the next task. If
that task tries to acquire a write lock it waits until the reader frees the
lock. However, if the task tries to acquire a read lock it will succeed, and
notify the next task, etc. */
typedef struct {
SemaphoreHandle_t sem;
ddsrt_tasklist_t tasks;
int32_t state;
uint32_t cnt;
uint32_t rdcnt;
uint32_t wrcnt;
} ddsrt_rwlock_t;
typedef ddsrt_atomic_uint32_t ddsrt_once_t;
#define DDSRT_ONCE_INIT { .v = (1<<0) /* ONCE_NOT_STARTED */ }
/* The declarations below are here for tests and must be considered private. */
/* Number of buckets to grow buffer by. */
#define DDSRT_TASKLIST_CHUNK (5)
/* Number of buckets to allocate initially. */
#define DDSRT_TASKLIST_INITIAL (DDSRT_TASKLIST_CHUNK * 2)
int ddsrt_tasklist_init(ddsrt_tasklist_t *list);
void ddsrt_tasklist_fini(ddsrt_tasklist_t *list);
void ddsrt_tasklist_ltrim(ddsrt_tasklist_t *list);
void ddsrt_tasklist_rtrim(ddsrt_tasklist_t *list);
void ddsrt_tasklist_pack(ddsrt_tasklist_t *list);
int ddsrt_tasklist_shrink(ddsrt_tasklist_t *list);
int ddsrt_tasklist_grow(ddsrt_tasklist_t *list);
ssize_t ddsrt_tasklist_find(ddsrt_tasklist_t *list, TaskHandle_t task);
TaskHandle_t ddsrt_tasklist_peek(ddsrt_tasklist_t *list, TaskHandle_t task);
TaskHandle_t ddsrt_tasklist_pop(ddsrt_tasklist_t *list, TaskHandle_t task);
int ddsrt_tasklist_push(ddsrt_tasklist_t *list, TaskHandle_t task);
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_SYNC_FREERTOS_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_mutex_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

@ -55,7 +55,7 @@ DDS_EXPORT void ddsrt_thread_pool_purge (ddsrt_thread_pool pool);
Note that if the pool queue has reached it's maximum DDS_RETCODE_TRY_AGAIN is returned.
*/
DDS_EXPORT dds_retcode_t ddsrt_thread_pool_submit
DDS_EXPORT dds_return_t ddsrt_thread_pool_submit
(
ddsrt_thread_pool pool, /* Thread pool instance */
void (*fn) (void *arg), /* Function to be invoked by thread from pool */

View file

@ -25,7 +25,9 @@
#include "dds/ddsrt/attributes.h"
#include "dds/ddsrt/retcode.h"
#if _WIN32
#if DDSRT_WITH_FREERTOS
#include "dds/ddsrt/threads/freertos.h"
#elif _WIN32
#include "dds/ddsrt/threads/windows.h"
#else
#include "dds/ddsrt/threads/posix.h"
@ -119,14 +121,14 @@ ddsrt_nonnull_all;
* @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.
* @returns A dds_return_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
DDS_EXPORT dds_return_t
ddsrt_thread_create(
ddsrt_thread_t *thread,
const char *name,
@ -170,14 +172,14 @@ ddsrt_thread_equal(ddsrt_thread_t t1, ddsrt_thread_t t2);
* @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.
* @returns A dds_return_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
DDS_EXPORT dds_return_t
ddsrt_thread_join(
ddsrt_thread_t thread,
uint32_t *thread_result);
@ -206,9 +208,58 @@ ddsrt_thread_getname(
*
* @param[in] name Name for current thread.
*/
#if DDSRT_HAVE_THREAD_SETNAME
DDS_EXPORT void
ddsrt_thread_setname(
const char *__restrict name);
#endif
#if DDSRT_HAVE_THREAD_LIST
/**
* @brief Get a list of threads in the calling process
*
* @param[out] tids Array of size elements to be filled with thread
* identifiers, may be NULL if size is 0
* @param[in] size The size of the tids array; 0 is allowed
*
* @returns A dds_return_t indicating the number of threads in the process
* or an error code on failure.
*
* @retval > 0
* Number of threads in the process, may be larger than size
* tids[0 .. (return - 1)] are valid
* @retval DDS_RETCODE_ERROR
* Something went wrong, contents of tids is undefined
* @retval DDS_RETCODE_UNSUPPORTED
* Not supported on the platform
*/
DDS_EXPORT dds_return_t ddsrt_thread_list (ddsrt_thread_list_id_t * __restrict tids, size_t size);
/**
* @brief Get the name of the specified thread (in the calling process)
*
* @param[in] tid Thread identifier for which the name is sought
* @param[out] name Filled with the thread name (or a synthesized one)
* on successful return; name is silently truncated
* if the actual name is longer than name can hold;
* always 0-terminated if size > 0
* @param[in] size Number of bytes of name that may be assigned, size
* is 0 is allowed, though somewhat useless
*
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* Possibly truncated name is returned as a null-terminated
* string in name (provided size > 0).
* @retval DDS_RETCODE_NOT_FOUND
* Thread not found; the contents of name is unchanged
* @retval DDS_RETCODE_ERROR
* Unspecified failure, the contents of name is undefined
* @retval DDS_RETCODE_UNSUPPORTED
* Not supported on the platform
*/
DDS_EXPORT dds_return_t ddsrt_thread_getname_anythread (ddsrt_thread_list_id_t tid, char *__restrict name, size_t size);
#endif
/**
* @brief Push cleanup handler onto the cleanup stack
@ -220,7 +271,7 @@ ddsrt_thread_setname(
* @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
DDS_EXPORT dds_return_t
ddsrt_thread_cleanup_push(
void (*routine)(void*),
void *arg);
@ -231,7 +282,7 @@ ddsrt_thread_cleanup_push(
* 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
DDS_EXPORT dds_return_t
ddsrt_thread_cleanup_pop(
int execute);

View file

@ -0,0 +1,36 @@
/*
* 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_THREADS_FREERTOS_H
#define DDSRT_THREADS_FREERTOS_H
#include <FreeRTOS.h>
#include <task.h>
#define DDSRT_HAVE_THREAD_SETNAME (0)
#define DDSRT_HAVE_THREAD_LIST (0)
#if defined(__cplusplus)
extern "C" {
#endif
typedef struct {
TaskHandle_t task;
} ddsrt_thread_t;
typedef UBaseType_t ddsrt_tid_t;
#define PRIdTID "lu"
#if defined(__cplusplus)
}
#endif
#endif /* DDSRT_THREADS_FREERTOS_H */

View file

@ -14,6 +14,17 @@
#include <pthread.h>
#if defined(__VXWORKS__)
#define DDSRT_HAVE_THREAD_SETNAME (0)
#else
#define DDSRT_HAVE_THREAD_SETNAME (1)
#endif
#if defined (__linux) || defined (__APPLE__)
#define DDSRT_HAVE_THREAD_LIST (1)
#else
#define DDSRT_HAVE_THREAD_LIST (0)
#endif
#if defined (__cplusplus)
extern "C" {
#endif
@ -21,6 +32,7 @@ extern "C" {
#if defined(__linux)
typedef long int ddsrt_tid_t;
#define PRIdTID "ld"
typedef long int ddsrt_thread_list_id_t;
/* __linux */
#elif defined(__FreeBSD__) && (__FreeBSD_version >= 900031)
/* FreeBSD >= 9.0 */
@ -32,6 +44,8 @@ typedef int ddsrt_tid_t;
/* macOS X >= 10.6 */
typedef uint64_t ddsrt_tid_t;
#define PRIdTID PRIu64
/* ddsrt_thread_list_id_t is actually a mach_port_t */
typedef uint32_t ddsrt_thread_list_id_t;
/* __APPLE__ */
#elif defined(__VXWORKS__)
/* TODO: Verify taskIdSelf is the right function to use on VxWorks */
@ -43,7 +57,7 @@ typedef TASK_ID ddsrt_tid_t;
# endif
/* __VXWORKS__ */
#else
typedef uintmax_t ddsrt_tid_t;
typedef uintptr_t ddsrt_tid_t;
#define PRIdTID PRIuPTR
#endif

View file

@ -14,6 +14,9 @@
#include "dds/ddsrt/types.h"
#define DDSRT_HAVE_THREAD_SETNAME (1)
#define DDSRT_HAVE_THREAD_LIST (1)
#if defined (__cplusplus)
extern "C" {
#endif
@ -26,6 +29,8 @@ typedef struct {
typedef DWORD ddsrt_tid_t;
#define PRIdTID "u"
typedef HANDLE ddsrt_thread_list_id_t;
#if defined (__cplusplus)
}
#endif

View file

@ -146,4 +146,8 @@ DDS_EXPORT size_t ddsrt_ctime(dds_time_t abstime, char *str, size_t size);
}
#endif
#if DDSRT_WITH_FREERTOS
#include "dds/ddsrt/time/freertos.h"
#endif
#endif /* DDSRT_TIME_H */

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
*/
#ifndef DDSRT_TIME_FREERTOS_H
#define DDSRT_TIME_FREERTOS_H
#include <assert.h>
#include <FreeRTOS.h>
#if defined (__cplusplus)
extern "C" {
#endif
#define DDSRT_NSECS_PER_TICK (DDS_NSECS_IN_SEC / configTICK_RATE_HZ)
inline TickType_t
ddsrt_duration_to_ticks_ceil(
dds_duration_t reltime)
{
TickType_t ticks = 0;
assert(portMAX_DELAY > configTICK_RATE_HZ);
if (reltime == DDS_INFINITY) {
ticks = portMAX_DELAY;
} else if (reltime > 0) {
dds_duration_t max_nsecs =
(DDS_INFINITY / DDSRT_NSECS_PER_TICK < portMAX_DELAY
? DDS_INFINITY - 1 : portMAX_DELAY * DDSRT_NSECS_PER_TICK);
if (reltime > max_nsecs - (DDSRT_NSECS_PER_TICK - 1)) {
ticks = portMAX_DELAY;
} else {
ticks = (TickType_t)((reltime + (DDSRT_NSECS_PER_TICK - 1)) / DDSRT_NSECS_PER_TICK);
}
}
return ticks;
}
#if defined (__cplusplus)
}
#endif
#endif /* DDSRT_TIME_FREERTOS_H */

View file

@ -14,6 +14,10 @@
#include <stdint.h>
#include <inttypes.h>
#if defined(__IAR_SYSTEMS_ICC__)
typedef long int ssize_t;
#else
#include <unistd.h>
#endif
#endif /* DDSRT_TYPES_POSIX_H */

View file

@ -20,10 +20,10 @@
extern "C" {
#endif
typedef int (*ddsrt_xmlp_proc_elem_open_t) (void *varg, uintptr_t parentinfo, uintptr_t *eleminfo, const char *name);
typedef int (*ddsrt_xmlp_proc_attr_t) (void *varg, uintptr_t eleminfo, const char *name, const char *value);
typedef int (*ddsrt_xmlp_proc_elem_data_t) (void *varg, uintptr_t eleminfo, const char *data);
typedef int (*ddsrt_xmlp_proc_elem_close_t) (void *varg, uintptr_t eleminfo);
typedef int (*ddsrt_xmlp_proc_elem_open_t) (void *varg, uintptr_t parentinfo, uintptr_t *eleminfo, const char *name, int line);
typedef int (*ddsrt_xmlp_proc_attr_t) (void *varg, uintptr_t eleminfo, const char *name, const char *value, int line);
typedef int (*ddsrt_xmlp_proc_elem_data_t) (void *varg, uintptr_t eleminfo, const char *data, int line);
typedef int (*ddsrt_xmlp_proc_elem_close_t) (void *varg, uintptr_t eleminfo, int line);
typedef void (*ddsrt_xmlp_error) (void *varg, const char *msg, int line);
struct ddsrt_xmlp_callbacks {
@ -36,9 +36,9 @@ extern "C" {
struct ddsrt_xmlp_state;
#define DDSRT_XMLP_REQUIRE_EOF 1u /* set by default; if not set, junk may follow top-level closing tag */
#define DDSRT_XMLP_ANONYMOUS_CLOSE_TAG 2u /* clear by default; if set allow closing an element with </> instead of </name> */
#define DDSRT_XMLP_REQUIRE_EOF 1u /* set by default; if not set, junk may follow top-level closing tag */
#define DDSRT_XMLP_ANONYMOUS_CLOSE_TAG 2u /* clear by default; if set allow closing an element with </> instead of </name> */
#define DDSRT_XMLP_MISSING_CLOSE_AS_EOF 4u /* clear by default; if set, treat missing close tag as EOF */
DDS_EXPORT struct ddsrt_xmlp_state *ddsrt_xmlp_new_file (FILE *fp, void *varg, const struct ddsrt_xmlp_callbacks *cb);
DDS_EXPORT struct ddsrt_xmlp_state *ddsrt_xmlp_new_string (const char *string, void *varg, const struct ddsrt_xmlp_callbacks *cb);
DDS_EXPORT void ddsrt_xmlp_set_options (struct ddsrt_xmlp_state *st, unsigned options);
@ -46,8 +46,6 @@ extern "C" {
DDS_EXPORT void ddsrt_xmlp_free (struct ddsrt_xmlp_state *st);
DDS_EXPORT int ddsrt_xmlp_parse (struct ddsrt_xmlp_state *st);
DDS_EXPORT int ddsrt_xmlUnescapeInsitu (char *buffer, size_t *n);
#if defined (__cplusplus)
}
#endif

View file

@ -30,6 +30,7 @@ extern inline void ddsrt_atomic_inc32 (volatile ddsrt_atomic_uint32_t *x);
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_ov (volatile ddsrt_atomic_uint32_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);
@ -58,6 +59,7 @@ extern inline void ddsrt_atomic_add64 (volatile ddsrt_atomic_uint64_t *x, uint64
#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_ov (volatile ddsrt_atomic_uint32_t *x, uint32_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);
@ -71,6 +73,7 @@ extern inline void ddsrt_atomic_sub64 (volatile ddsrt_atomic_uint64_t *x, uint64
#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_ov (volatile ddsrt_atomic_uint32_t *x, uint32_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);
@ -122,6 +125,7 @@ extern inline int ddsrt_atomic_casvoidp2 (volatile ddsrt_atomic_uintptr2_t *x, u
/* FENCES */
extern inline void ddsrt_atomic_fence (void);
extern inline void ddsrt_atomic_fence_ldld (void);
extern inline void ddsrt_atomic_fence_stst (void);
extern inline void ddsrt_atomic_fence_acq (void);
extern inline void ddsrt_atomic_fence_rel (void);
@ -161,3 +165,182 @@ void ddsrt_atomic_lifo_pushmany (ddsrt_atomic_lifo_t *head, void *first, void *l
} while (!ddsrt_atomic_casvoidp2 (&head->aba_head, a0, b0, a0+1, (uintptr_t)first));
}
#endif
/* On platforms that don't provide 64-bit atomic operations, emulate them by hashing
the variable's address to a small set of mutexes.
This also defines the GCC builtins on SPARCv8 for 32-bit operations. It would be
more appropriate to simply define the ddsrt_atomic_... functions properly in that
case and avoid squatting in the __sync_... namespace, but SPARCv8 support really
is just for fun and it doesn't seem worth the bother right now */
#if DDSRT_HAVE_ATOMIC64
void ddsrt_atomics_init (void) { }
void ddsrt_atomics_fini (void) { }
#else
#include "dds/ddsrt/sync.h"
/* SPARCv8 depends on these mutexes already for one-shot initialisation of the ddsrt
code. Using PTHREAD_MUTEX_INITIALIZER guarantees they are properly initialized.
Once a platform shows up that defines that macro where we don't used pthread mutexes
something else will have to be done. */
#define N_MUTEXES_LG2 4
#define N_MUTEXES (1 << N_MUTEXES_LG2)
#ifndef PTHREAD_MUTEX_INITIALIZER
static ddsrt_mutex_t mutexes[N_MUTEXES];
void ddsrt_atomics_init (void)
{
for (int i = 0; i < N_MUTEXES; i++)
ddsrt_mutex_init (&mutexes[i]);
}
void ddsrt_atomics_fini (void)
{
for (int i = 0; i < N_MUTEXES; i++)
ddsrt_mutex_destroy (&mutexes[i]);
}
#else
static ddsrt_mutex_t mutexes[N_MUTEXES] = {
{ PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
{ PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
{ PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
{ PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
{ PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
{ PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
{ PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
{ PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }
};
void ddsrt_atomics_init (void) { }
void ddsrt_atomics_fini (void) { }
#endif
static uint32_t atomic64_lock_index (const volatile ddsrt_atomic_uint64_t *x)
{
const uint32_t u = (uint16_t) ((uintptr_t) x >> 3);
const uint32_t v = u * 0xb4817365;
return v >> (32 - N_MUTEXES_LG2);
}
int ddsrt_atomic_cas64 (volatile ddsrt_atomic_uint64_t *x, uint64_t exp, uint64_t des)
{
const uint32_t idx = atomic64_lock_index (x);
ddsrt_mutex_lock (&mutexes[idx]);
if (x->v == exp)
{
x->v = des;
ddsrt_mutex_unlock (&mutexes[idx]);
return true;
}
else
{
ddsrt_mutex_unlock (&mutexes[idx]);
return false;
}
}
#define DDSRT_FAKE_ATOMIC64(name, oper, ret) \
uint64_t ddsrt_atomic_##name##64_##ret (volatile ddsrt_atomic_uint64_t *x, uint64_t v) \
{ \
const uint64_t idx = atomic64_lock_index (x); \
ddsrt_mutex_lock (&mutexes[idx]); \
const uint64_t ov = x->v; \
const uint64_t nv = ov oper v; \
x->v = nv; \
ddsrt_mutex_unlock (&mutexes[idx]); \
return ret; \
}
#define DDSRT_FAKE_ATOMIC64_TRIPLET(name, oper) \
DDSRT_FAKE_ATOMIC64(name, oper, nv) \
DDSRT_FAKE_ATOMIC64(name, oper, ov) \
void ddsrt_atomic_##name##64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) { \
(void) ddsrt_atomic_##name##64_ov (x, v); \
}
uint64_t ddsrt_atomic_ld64 (const volatile ddsrt_atomic_uint64_t *x)
{
const uint32_t idx = atomic64_lock_index (x);
ddsrt_mutex_lock (&mutexes[idx]);
const uint64_t v = x->v;
ddsrt_mutex_unlock (&mutexes[idx]);
return v;
}
void ddsrt_atomic_st64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v)
{
const uint32_t idx = atomic64_lock_index (x);
ddsrt_mutex_lock (&mutexes[idx]);
x->v = v;
ddsrt_mutex_unlock (&mutexes[idx]);
}
DDSRT_FAKE_ATOMIC64_TRIPLET(add, +)
DDSRT_FAKE_ATOMIC64_TRIPLET(sub, -)
DDSRT_FAKE_ATOMIC64_TRIPLET(or, |)
DDSRT_FAKE_ATOMIC64_TRIPLET(and, &)
void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x) {
ddsrt_atomic_add64 (x, 1);
}
uint64_t ddsrt_atomic_inc64_nv (volatile ddsrt_atomic_uint64_t *x) {
return ddsrt_atomic_add64_nv (x, 1);
}
void ddsrt_atomic_dec64 (volatile ddsrt_atomic_uint64_t *x) {
ddsrt_atomic_sub64 (x, 1);
}
uint64_t ddsrt_atomic_dec64_nv (volatile ddsrt_atomic_uint64_t *x) {
return ddsrt_atomic_sub64_nv (x, 1);
}
#undef DDSRT_FAKE_ATOMIC64_TRIPLET
#undef DDSRT_FAKE_ATOMIC64
/* SPARCv8 doesn't support any atomic operations beyond a simple atomic exchange. GCC happily
compiles the __sync_* functions into library calls, and implementing them as such will do
the trick. The rarity of SPARCv8 machines (EOL'd 2 decades ago) */
#ifdef __sparc_v8__
#define DDSRT_FAKE_SYNC(name, size, oper, ret) \
unsigned __sync_##name##_##size (volatile unsigned *x, unsigned v) \
{ \
const uint32_t idx = atomic64_lock_index ((const volatile ddsrt_atomic_uint64_t *) x); \
ddsrt_mutex_lock (&mutexes[idx]); \
const uint32_t ov = *x; \
const uint32_t nv = ov oper v; \
*x = nv; \
ddsrt_mutex_unlock (&mutexes[idx]); \
return ret; \
}
#define DDSRT_FAKE_SYNC_PAIR(name, size, oper) \
DDSRT_FAKE_SYNC(name##_and_fetch, size, oper, nv) \
DDSRT_FAKE_SYNC(fetch_and_##name, size, oper, ov)
DDSRT_FAKE_SYNC_PAIR (add, 4, +)
DDSRT_FAKE_SYNC_PAIR (sub, 4, -)
DDSRT_FAKE_SYNC_PAIR (or, 4, |)
DDSRT_FAKE_SYNC_PAIR (and, 4, &)
bool __sync_bool_compare_and_swap_4 (volatile unsigned *x, unsigned exp, unsigned des)
{
const uint32_t idx = atomic64_lock_index ((const volatile ddsrt_atomic_uint64_t *) x);
ddsrt_mutex_lock (&mutexes[idx]);
if (*x == exp)
{
*x = des;
ddsrt_mutex_unlock (&mutexes[idx]);
return true;
}
else
{
ddsrt_mutex_unlock (&mutexes[idx]);
return false;
}
}
#undef DDSRT_FAKE_SYNC_PAIR
#undef DDSRT_FAKE_SYNC
#endif /* SPARCv8 hack */
#endif /* DDSRT_HAVE_ATOMIC64 */

View file

@ -43,6 +43,7 @@ retry:
ddsrt_time_init();
#endif
ddsrt_random_init();
ddsrt_atomics_init();
ddsrt_atomic_or32(&init_status, INIT_STATUS_OK);
} else {
while (v > 1 && !(v & INIT_STATUS_OK)) {
@ -68,6 +69,7 @@ void ddsrt_fini (void)
{
ddsrt_mutex_destroy(&init_mutex);
ddsrt_random_fini();
ddsrt_atomics_fini();
#if _WIN32
ddsrt_winsock_fini();
ddsrt_time_fini();
@ -139,6 +141,9 @@ ddsrt_cdtor(
#pragma data_seg()
#endif
#else /* _WIN32 */
void __attribute__((constructor)) ddsrt_ctor(void);
void __attribute__((destructor)) ddsrt_dtor(void);
void __attribute__((constructor)) ddsrt_ctor(void)
{
ddsrt_init();

View file

@ -17,9 +17,9 @@
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/io.h"
dds_retcode_t ddsrt_dlopen(const char *name, bool translate,
dds_return_t ddsrt_dlopen(const char *name, bool translate,
ddsrt_dynlib_t *handle) {
dds_retcode_t retcode = DDS_RETCODE_OK;
dds_return_t retcode = DDS_RETCODE_OK;
assert( handle );
*handle = NULL;
@ -53,16 +53,16 @@ dds_retcode_t ddsrt_dlopen(const char *name, bool translate,
return retcode;
}
dds_retcode_t ddsrt_dlclose(ddsrt_dynlib_t handle) {
dds_return_t ddsrt_dlclose(ddsrt_dynlib_t handle) {
assert ( handle );
return (dlclose(handle) == 0) ? DDS_RETCODE_OK : DDS_RETCODE_ERROR;
}
dds_retcode_t ddsrt_dlsym(ddsrt_dynlib_t handle, const char *symbol,
dds_return_t ddsrt_dlsym(ddsrt_dynlib_t handle, const char *symbol,
void **address) {
dds_retcode_t retcode = DDS_RETCODE_OK;
dds_return_t retcode = DDS_RETCODE_OK;
assert( handle );
assert( address );
@ -76,10 +76,10 @@ dds_retcode_t ddsrt_dlsym(ddsrt_dynlib_t handle, const char *symbol,
return retcode;
}
dds_retcode_t ddsrt_dlerror(char *buf, size_t buflen) {
dds_return_t ddsrt_dlerror(char *buf, size_t buflen) {
const char *err;
dds_retcode_t retcode = DDS_RETCODE_OK;
dds_return_t retcode = DDS_RETCODE_OK;
assert (buf );

View file

@ -23,7 +23,7 @@ isenvvar(const char *name)
return (*name == '\0' || strchr(name, '=') != NULL) == 0;
}
dds_retcode_t
dds_return_t
ddsrt_getenv(const char *name, char **value)
{
char *env;
@ -40,7 +40,7 @@ ddsrt_getenv(const char *name, char **value)
return DDS_RETCODE_NOT_FOUND;
}
dds_retcode_t
dds_return_t
ddsrt_setenv(const char *name, const char *value)
{
assert(name != NULL);
@ -65,7 +65,7 @@ ddsrt_setenv(const char *name, const char *value)
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_unsetenv(const char *name)
{
assert(name != NULL);

View file

@ -0,0 +1,100 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "dds/ddsrt/environ.h"
#include "dds/ddsrt/retcode.h"
extern char **environ;
static int
isenvvar(const char *name)
{
return (*name == '\0' || strchr(name, '=') != NULL) == 0;
}
dds_return_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_return_t
ddsrt_setenv(const char *name, const char *value)
{
/* Not MT-Safe -- but it is only used in a tests to set
CYCLONEDDS_URI, so for Solaris 2.6 support it is not worth the
bother to do a better job. Same for a bit of leakage. */
assert(name != NULL);
assert(value != NULL);
if (strlen(value) == 0)
return ddsrt_unsetenv(name);
if (!isenvvar(name))
return DDS_RETCODE_BAD_PARAMETER;
const size_t namelen = strlen (name);
const size_t entrysize = namelen + 1 + strlen (value) + 1;
char *entry = malloc (entrysize);
snprintf (entry, entrysize, "%s=%s", name, value);
size_t n = 0;
while (environ[n] != NULL)
{
if (strncmp (environ[n], name, namelen) == 0 && environ[n][namelen] == '=')
{
environ[n] = entry;
return DDS_RETCODE_OK;
}
n++;
}
environ = realloc (environ, (n + 2) * sizeof (*environ));
environ[n] = entry;
environ[n+1] = NULL;
return DDS_RETCODE_OK;
}
dds_return_t
ddsrt_unsetenv(const char *name)
{
/* Same considerations as setenv. */
assert(name != NULL);
if (!isenvvar(name))
return DDS_RETCODE_BAD_PARAMETER;
const size_t namelen = strlen (name);
size_t n = 0, idx = SIZE_MAX;
while (environ[n] != NULL)
{
if (idx > n && strncmp (environ[n], name, namelen) == 0 && environ[n][namelen] == '=')
idx = n;
n++;
}
if (idx < n)
memmove (&environ[idx], &environ[idx + 1], (n - idx) * sizeof (*environ));
return DDS_RETCODE_OK;
}

View file

@ -25,7 +25,7 @@ isenvvar(const char *name)
}
DDSRT_WARNING_MSVC_OFF(4996)
dds_retcode_t
dds_return_t
ddsrt_getenv(const char *name, char **value)
{
char *env;
@ -43,7 +43,7 @@ ddsrt_getenv(const char *name, char **value)
}
DDSRT_WARNING_MSVC_ON(4996)
dds_retcode_t
dds_return_t
ddsrt_setenv(const char *name, const char *value)
{
assert(name != NULL);
@ -65,7 +65,7 @@ ddsrt_setenv(const char *name, const char *value)
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_unsetenv(const char *name)
{
assert(name != NULL);

View file

@ -19,8 +19,9 @@
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/string.h"
#include "dds/ddsrt/process.h"
typedef char * (*expand_fn)(const char *src0);
typedef char * (*expand_fn)(const char *src0, uint32_t domid);
static void expand_append (char **dst, size_t *sz, size_t *pos, char c)
{
@ -32,34 +33,46 @@ static void expand_append (char **dst, size_t *sz, size_t *pos, char c)
(*pos)++;
}
static char *expand_env (const char *name, char op, const char *alt, expand_fn expand)
static char *expand_env (const char *name, char op, const char *alt, expand_fn expand, uint32_t domid)
{
char idstr[20];
char *env = NULL;
(void)ddsrt_getenv (name, &env);
dds_return_t ret;
if ((ret = ddsrt_getenv (name, &env)) == DDS_RETCODE_OK) {
/* ok */
} else if (strcmp (name, "$") == 0 || strcmp (name, "CYCLONEDDS_PID") == 0) {
snprintf (idstr, sizeof (idstr), "%"PRIdPID, ddsrt_getpid ());
env = idstr;
} else if (strcmp (name, "CYCLONEDDS_DOMAIN_ID") == 0 && domid != UINT32_MAX) {
snprintf (idstr, sizeof (idstr), "%"PRIu32, domid);
env = idstr;
}
switch (op)
{
case 0:
return ddsrt_strdup (env ? env : "");
case '-':
return env && *env ? ddsrt_strdup (env) : expand (alt);
return env && *env ? ddsrt_strdup (env) : expand (alt, domid);
case '?':
if (env && *env) {
return ddsrt_strdup (env);
} else {
char *altx = expand (alt);
DDS_ERROR("%s: %s\n", name, altx);
char *altx = expand (alt, domid);
DDS_ILOG (DDS_LC_ERROR, domid, "%s: %s\n", name, altx);
ddsrt_free (altx);
return NULL;
}
case '+':
return env && *env ? expand (alt) : ddsrt_strdup ("");
return env && *env ? expand (alt, domid) : ddsrt_strdup ("");
default:
abort ();
return NULL;
}
}
static char *expand_envbrace (const char **src, expand_fn expand)
static char *expand_envbrace (const char **src, expand_fn expand, uint32_t domid)
{
const char *start = *src + 1;
char *name, *x;
@ -76,7 +89,7 @@ static char *expand_envbrace (const char **src, expand_fn expand)
name[*src - start] = 0;
if (**src == '}') {
(*src)++;
x = expand_env (name, 0, NULL, expand);
x = expand_env (name, 0, NULL, expand, domid);
ddsrt_free (name);
return x;
} else {
@ -120,7 +133,7 @@ static char *expand_envbrace (const char **src, expand_fn expand)
memcpy (alt, altstart, (size_t) (*src - altstart));
alt[*src - altstart] = 0;
(*src)++;
x = expand_env (name, op, alt, expand);
x = expand_env (name, op, alt, expand, domid);
ddsrt_free (alt);
ddsrt_free (name);
return x;
@ -130,7 +143,7 @@ err:
return NULL;
}
static char *expand_envsimple (const char **src, expand_fn expand)
static char *expand_envsimple (const char **src, expand_fn expand, uint32_t domid)
{
const char *start = *src;
char *name, *x;
@ -141,22 +154,22 @@ static char *expand_envsimple (const char **src, expand_fn expand)
name = ddsrt_malloc ((size_t) (*src - start) + 1);
memcpy (name, start, (size_t) (*src - start));
name[*src - start] = 0;
x = expand_env (name, 0, NULL, expand);
x = expand_env (name, 0, NULL, expand, domid);
ddsrt_free (name);
return x;
}
static char *expand_envchar (const char **src, expand_fn expand)
static char *expand_envchar (const char **src, expand_fn expand, uint32_t domid)
{
char name[2];
assert (**src);
name[0] = **src;
name[1] = 0;
(*src)++;
return expand_env (name, 0, NULL, expand);
return expand_env (name, 0, NULL, expand, domid);
}
char *ddsrt_expand_envvars_sh (const char *src0)
char *ddsrt_expand_envvars_sh (const char *src0, uint32_t domid)
{
/* Expands $X, ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms; $ and \ can be escaped with \ */
const char *src = src0;
@ -179,11 +192,11 @@ char *ddsrt_expand_envvars_sh (const char *src0)
ddsrt_free(dst);
return NULL;
} else if (*src == '{') {
x = expand_envbrace (&src, &ddsrt_expand_envvars_sh);
x = expand_envbrace (&src, &ddsrt_expand_envvars_sh, domid);
} else if (isalnum ((unsigned char) *src) || *src == '_') {
x = expand_envsimple (&src, &ddsrt_expand_envvars_sh);
x = expand_envsimple (&src, &ddsrt_expand_envvars_sh, domid);
} else {
x = expand_envchar (&src, &ddsrt_expand_envvars_sh);
x = expand_envchar (&src, &ddsrt_expand_envvars_sh, domid);
}
if (x == NULL) {
ddsrt_free(dst);
@ -202,7 +215,7 @@ char *ddsrt_expand_envvars_sh (const char *src0)
return dst;
}
char *ddsrt_expand_envvars (const char *src0)
char *ddsrt_expand_envvars (const char *src0, uint32_t domid)
{
/* Expands ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, but not $X */
const char *src = src0;
@ -212,7 +225,7 @@ char *ddsrt_expand_envvars (const char *src0)
if (*src == '$' && *(src + 1) == '{') {
char *x, *xp;
src++;
x = expand_envbrace (&src, &ddsrt_expand_envvars);
x = expand_envbrace (&src, &ddsrt_expand_envvars, domid);
if (x == NULL) {
ddsrt_free(dst);
return NULL;

View file

@ -207,7 +207,7 @@ void *ddsrt_fibheap_extract_min (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap
keys anyway to find the minimum */
{
ddsrt_fibheap_node_t *mark, *cursor, *newmin;
unsigned i;
uint32_t i;
for (i = 0; roots[i] == NULL; i++) {
assert (i+1 < min_degree_noninit);
}

View file

@ -0,0 +1,136 @@
/*
* 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 <FreeRTOS.h>
#if defined(configSUPPORT_DYNAMIC_ALLOCATION) && \
(configSUPPORT_DYNAMIC_ALLOCATION == 0)
# error Dynamic memory allocation is not supported
#endif
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
static const size_t ofst = sizeof(size_t);
void *ddsrt_malloc_s(size_t size)
{
void *ptr = NULL;
if (size == 0) {
size = 1;
}
if ((SIZE_MAX - size) < ofst) {
errno = ERANGE;
} else {
ptr = pvPortMalloc(size + ofst);
if (ptr == NULL) {
errno = ENOMEM;
} else {
*((size_t *)ptr) = size;
ptr += ofst;
}
}
return ptr;
}
void *ddsrt_malloc(size_t size)
{
void *ptr;
if ((ptr = ddsrt_malloc_s(size)) == NULL) {
abort();
}
return ptr;
}
void *ddsrt_calloc_s(size_t nmemb, size_t size)
{
void *ptr = NULL;
if (nmemb == 0 || size == 0) {
nmemb = size = 1;
}
if ((SIZE_MAX / nmemb) <= size) {
errno = ERANGE;
} else {
ptr = ddsrt_malloc_s(nmemb * size);
(void)memset(ptr, 0, nmemb * size);
}
return ptr;
}
void *ddsrt_calloc(size_t nmemb, size_t size)
{
void *ptr = NULL;
if ((ptr = ddsrt_calloc_s(nmemb, size)) == NULL) {
abort();
}
return ptr;
}
/* pvPortMalloc may be used instead of directly invoking malloc and free as
offered by the standard C library. Unfortunately FreeRTOS does not offer a
realloc compatible function and extra information must be embedded in every
memory block in order to support reallocation of memory (otherwise the
number of bytes that must be copied is unavailable). */
void *ddsrt_realloc_s(void *memblk, size_t size)
{
void *ptr = NULL;
size_t origsize = 0;
if (memblk != NULL) {
origsize = *((size_t *)(memblk - ofst));
}
if (size != origsize || origsize == 0) {
if ((ptr = ddsrt_malloc_s(size)) == NULL) {
return NULL;
}
if (memblk != NULL) {
if (size > 0) {
(void)memcpy(ptr, memblk, size > origsize ? origsize : size);
}
vPortFree(memblk - ofst);
}
memblk = ptr;
}
return memblk;
}
void *ddsrt_realloc(void *memblk, size_t size)
{
void *ptr = NULL;
if ((ptr = ddsrt_realloc_s(memblk, size)) == NULL) {
abort();
}
return ptr;
}
void
ddsrt_free(void *ptr)
{
if (ptr != NULL) {
vPortFree(ptr - ofst);
}
}

View file

@ -12,6 +12,7 @@
#include <assert.h>
#include <string.h>
#include "dds/ddsrt/attributes.h"
#include "dds/ddsrt/atomics.h"
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/sync.h"
@ -22,8 +23,255 @@
#define NOT_A_BUCKET (~(uint32_t)0)
/************* SEQUENTIAL VERSION ***************/
struct ddsrt_hh_bucket {
uint32_t hopinfo;
void *data;
};
struct ddsrt_hh {
uint32_t size; /* power of 2 */
struct ddsrt_hh_bucket *buckets;
ddsrt_hh_hash_fn hash;
ddsrt_hh_equals_fn equals;
};
static void ddsrt_hh_init (struct ddsrt_hh *rt, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals)
{
uint32_t size;
uint32_t i;
/* degenerate case to minimize memory use */
if (init_size == 1) {
size = 1;
} else {
size = HH_HOP_RANGE;
while (size < init_size) {
size *= 2;
}
}
rt->hash = hash;
rt->equals = equals;
rt->size = size;
rt->buckets = ddsrt_malloc (size * sizeof (*rt->buckets));
for (i = 0; i < size; i++) {
rt->buckets[i].hopinfo = 0;
rt->buckets[i].data = NULL;
}
}
static void ddsrt_hh_fini (struct ddsrt_hh *rt)
{
ddsrt_free (rt->buckets);
}
struct ddsrt_hh *ddsrt_hh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals)
{
struct ddsrt_hh *hh = ddsrt_malloc (sizeof (*hh));
ddsrt_hh_init (hh, init_size, hash, equals);
return hh;
}
void ddsrt_hh_free (struct ddsrt_hh * __restrict hh)
{
ddsrt_hh_fini (hh);
ddsrt_free (hh);
}
static void *ddsrt_hh_lookup_internal (const struct ddsrt_hh *rt, const uint32_t bucket, const void *template)
{
const uint32_t idxmask = rt->size - 1;
uint32_t hopinfo = rt->buckets[bucket].hopinfo;
uint32_t idx;
for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) {
const uint32_t bidx = (bucket + idx) & idxmask;
void *data = rt->buckets[bidx].data;
if (data && rt->equals (data, template))
return data;
}
return NULL;
}
void *ddsrt_hh_lookup (const struct ddsrt_hh * __restrict rt, const void * __restrict template)
{
const uint32_t hash = rt->hash (template);
const uint32_t idxmask = rt->size - 1;
const uint32_t bucket = hash & idxmask;
return ddsrt_hh_lookup_internal (rt, bucket, template);
}
static uint32_t ddsrt_hh_find_closer_free_bucket (struct ddsrt_hh *rt, uint32_t free_bucket, uint32_t *free_distance)
{
const uint32_t idxmask = rt->size - 1;
uint32_t move_bucket, free_dist;
move_bucket = (free_bucket - (HH_HOP_RANGE - 1)) & idxmask;
for (free_dist = HH_HOP_RANGE - 1; free_dist > 0; free_dist--) {
uint32_t move_free_distance = NOT_A_BUCKET;
uint32_t mask = 1;
uint32_t i;
for (i = 0; i < free_dist; i++, mask <<= 1) {
if (mask & rt->buckets[move_bucket].hopinfo) {
move_free_distance = i;
break;
}
}
if (move_free_distance != NOT_A_BUCKET) {
uint32_t new_free_bucket = (move_bucket + move_free_distance) & idxmask;
rt->buckets[move_bucket].hopinfo |= 1u << free_dist;
rt->buckets[free_bucket].data = rt->buckets[new_free_bucket].data;
rt->buckets[new_free_bucket].data = NULL;
rt->buckets[move_bucket].hopinfo &= ~(1u << move_free_distance);
*free_distance -= free_dist - move_free_distance;
return new_free_bucket;
}
move_bucket = (move_bucket + 1) & idxmask;
}
return NOT_A_BUCKET;
}
static void ddsrt_hh_resize (struct ddsrt_hh *rt)
{
if (rt->size == 1) {
assert (rt->size == 1);
assert (rt->buckets[0].hopinfo == 1);
assert (rt->buckets[0].data != NULL);
rt->size = HH_HOP_RANGE;
const uint32_t hash = rt->hash (rt->buckets[0].data);
const uint32_t idxmask = rt->size - 1;
const uint32_t start_bucket = hash & idxmask;
struct ddsrt_hh_bucket *newbs = ddsrt_malloc (rt->size * sizeof (*newbs));
for (uint32_t i = 0; i < rt->size; i++) {
newbs[i].hopinfo = 0;
newbs[i].data = NULL;
}
newbs[start_bucket] = rt->buckets[0];
ddsrt_free (rt->buckets);
rt->buckets = newbs;
} else {
struct ddsrt_hh_bucket *bs1;
uint32_t i, idxmask0, idxmask1;
bs1 = ddsrt_malloc (2 * rt->size * sizeof (*rt->buckets));
for (i = 0; i < 2 * rt->size; i++) {
bs1[i].hopinfo = 0;
bs1[i].data = NULL;
}
idxmask0 = rt->size - 1;
idxmask1 = 2 * rt->size - 1;
for (i = 0; i < rt->size; i++) {
void *data = rt->buckets[i].data;
if (data) {
const uint32_t hash = rt->hash (data);
const uint32_t old_start_bucket = hash & idxmask0;
const uint32_t new_start_bucket = hash & idxmask1;
const uint32_t dist = (i >= old_start_bucket) ? (i - old_start_bucket) : (rt->size + i - old_start_bucket);
const uint32_t newb = (new_start_bucket + dist) & idxmask1;
assert (dist < HH_HOP_RANGE);
bs1[new_start_bucket].hopinfo |= 1u << dist;
bs1[newb].data = data;
}
}
ddsrt_free (rt->buckets);
rt->size *= 2;
rt->buckets = bs1;
}
}
int ddsrt_hh_add (struct ddsrt_hh * __restrict rt, const void * __restrict data)
{
const uint32_t hash = rt->hash (data);
const uint32_t idxmask = rt->size - 1;
const uint32_t start_bucket = hash & idxmask;
uint32_t free_distance, free_bucket;
if (ddsrt_hh_lookup_internal (rt, start_bucket, data)) {
return 0;
}
free_bucket = start_bucket;
for (free_distance = 0; free_distance < HH_ADD_RANGE; free_distance++) {
if (rt->buckets[free_bucket].data == NULL)
break;
free_bucket = (free_bucket + 1) & idxmask;
}
if (free_distance < HH_ADD_RANGE) {
do {
if (free_distance < HH_HOP_RANGE) {
assert ((uint32_t) free_bucket == ((start_bucket + free_distance) & idxmask));
rt->buckets[start_bucket].hopinfo |= 1u << free_distance;
rt->buckets[free_bucket].data = (void *) data;
return 1;
}
free_bucket = ddsrt_hh_find_closer_free_bucket (rt, free_bucket, &free_distance);
assert (free_bucket == NOT_A_BUCKET || free_bucket <= idxmask);
} while (free_bucket != NOT_A_BUCKET);
}
ddsrt_hh_resize (rt);
return ddsrt_hh_add (rt, data);
}
int ddsrt_hh_remove (struct ddsrt_hh * __restrict rt, const void * __restrict template)
{
const uint32_t hash = rt->hash (template);
const uint32_t idxmask = rt->size - 1;
const uint32_t bucket = hash & idxmask;
uint32_t hopinfo;
uint32_t idx;
hopinfo = rt->buckets[bucket].hopinfo;
for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) {
if (hopinfo & 1) {
const uint32_t bidx = (bucket + idx) & idxmask;
void *data = rt->buckets[bidx].data;
if (data && rt->equals (data, template)) {
rt->buckets[bidx].data = NULL;
rt->buckets[bucket].hopinfo &= ~(1u << idx);
return 1;
}
}
}
return 0;
}
void ddsrt_hh_enum (struct ddsrt_hh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg)
{
uint32_t i;
for (i = 0; i < rt->size; i++) {
void *data = rt->buckets[i].data;
if (data) {
f (data, f_arg);
}
}
}
void *ddsrt_hh_iter_first (struct ddsrt_hh * __restrict rt, struct ddsrt_hh_iter * __restrict iter)
{
iter->hh = rt;
iter->cursor = 0;
return ddsrt_hh_iter_next (iter);
}
void *ddsrt_hh_iter_next (struct ddsrt_hh_iter * __restrict iter)
{
struct ddsrt_hh *rt = iter->hh;
while (iter->cursor < rt->size) {
void *data = rt->buckets[iter->cursor].data;
iter->cursor++;
if (data) {
return data;
}
}
return NULL;
}
/********** CONCURRENT VERSION ************/
#if ! ddsrt_has_feature_thread_sanitizer
#define N_BACKING_LOCKS 32
#define N_RESIZE_LOCKS 8
@ -51,6 +299,7 @@ struct ddsrt_chh {
ddsrt_hh_equals_fn equals;
ddsrt_rwlock_t resize_locks[N_RESIZE_LOCKS];
ddsrt_hh_buckets_gc_fn gc_buckets;
void *gc_buckets_arg;
};
#define CHH_MAX_TRIES 4
@ -61,7 +310,7 @@ static int ddsrt_chh_data_valid_p (void *data)
return data != NULL && data != CHH_BUSY;
}
static int ddsrt_chh_init (struct ddsrt_chh *rt, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets)
static int ddsrt_chh_init (struct ddsrt_chh *rt, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets, void *gc_buckets_arg)
{
uint32_t size;
uint32_t i;
@ -74,6 +323,7 @@ static int ddsrt_chh_init (struct ddsrt_chh *rt, uint32_t init_size, ddsrt_hh_ha
rt->hash = hash;
rt->equals = equals;
rt->gc_buckets = gc_buckets;
rt->gc_buckets_arg = gc_buckets_arg;
buckets = ddsrt_malloc (offsetof (struct ddsrt_chh_bucket_array, bs) + size * sizeof (*buckets->bs));
ddsrt_atomic_stvoidp (&rt->buckets, buckets);
@ -111,10 +361,10 @@ static void ddsrt_chh_fini (struct ddsrt_chh *rt)
}
}
struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets)
struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets, void *gc_buckets_arg)
{
struct ddsrt_chh *hh = ddsrt_malloc (sizeof (*hh));
if (ddsrt_chh_init (hh, init_size, hash, equals, gc_buckets) < 0) {
if (ddsrt_chh_init (hh, init_size, hash, equals, gc_buckets, gc_buckets_arg) < 0) {
ddsrt_free (hh);
return NULL;
} else {
@ -228,7 +478,7 @@ static void *ddsrt_chh_lookup_internal (struct ddsrt_chh_bucket_array const * co
#define ddsrt_atomic_rmw32_nonatomic(var_, tmp_, expr_) do { \
ddsrt_atomic_uint32_t *var__ = (var_); \
uint32_t tmp_ = ddsrt_atomic_ld32 (var__); \
uint32_t tmp_ = ddsrt_atomic_ld32 (var__); \
ddsrt_atomic_st32 (var__, (expr_)); \
} while (0)
@ -324,7 +574,7 @@ static void ddsrt_chh_resize (struct ddsrt_chh *rt)
ddsrt_atomic_fence ();
ddsrt_atomic_stvoidp (&rt->buckets, bsary1);
rt->gc_buckets (bsary0);
rt->gc_buckets (bsary0, rt->gc_buckets_arg);
}
int ddsrt_chh_add (struct ddsrt_chh * __restrict rt, const void * __restrict data)
@ -467,224 +717,78 @@ void *ddsrt_chh_iter_first (struct ddsrt_chh * __restrict rt, struct ddsrt_chh_i
return ddsrt_chh_iter_next (it);
}
/************* SEQUENTIAL VERSION ***************/
#else
struct ddsrt_hh_bucket {
uint32_t hopinfo;
void *data;
struct ddsrt_chh {
ddsrt_mutex_t lock;
struct ddsrt_hh rt;
};
struct ddsrt_hh {
uint32_t size; /* power of 2 */
struct ddsrt_hh_bucket *buckets;
ddsrt_hh_hash_fn hash;
ddsrt_hh_equals_fn equals;
};
static void ddsrt_hh_init (struct ddsrt_hh *rt, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals)
struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc)
{
uint32_t size = HH_HOP_RANGE;
uint32_t i;
while (size < init_size) {
size *= 2;
}
rt->hash = hash;
rt->equals = equals;
rt->size = size;
rt->buckets = ddsrt_malloc (size * sizeof (*rt->buckets));
for (i = 0; i < size; i++) {
rt->buckets[i].hopinfo = 0;
rt->buckets[i].data = NULL;
}
struct ddsrt_chh *hh = ddsrt_malloc (sizeof (*hh));
(void) gc;
ddsrt_mutex_init (&hh->lock);
ddsrt_hh_init (&hh->rt, init_size, hash, equals);
return hh;
}
static void ddsrt_hh_fini (struct ddsrt_hh *rt)
void ddsrt_chh_free (struct ddsrt_chh * __restrict hh)
{
ddsrt_free (rt->buckets);
ddsrt_hh_fini (&hh->rt);
ddsrt_mutex_destroy (&hh->lock);
ddsrt_free (hh);
}
struct ddsrt_hh *ddsrt_hh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals)
void *ddsrt_chh_lookup (struct ddsrt_chh * __restrict hh, const void * __restrict template)
{
struct ddsrt_hh *hh = ddsrt_malloc (sizeof (*hh));
ddsrt_hh_init (hh, init_size, hash, equals);
return hh;
ddsrt_mutex_lock (&hh->lock);
void *x = ddsrt_hh_lookup (&hh->rt, template);
ddsrt_mutex_unlock (&hh->lock);
return x;
}
void ddsrt_hh_free (struct ddsrt_hh * __restrict hh)
int ddsrt_chh_add (struct ddsrt_chh * __restrict hh, const void * __restrict data)
{
ddsrt_hh_fini (hh);
ddsrt_free (hh);
ddsrt_mutex_lock (&hh->lock);
int x = ddsrt_hh_add (&hh->rt, data);
ddsrt_mutex_unlock (&hh->lock);
return x;
}
static void *ddsrt_hh_lookup_internal (const struct ddsrt_hh *rt, const uint32_t bucket, const void *template)
int ddsrt_chh_remove (struct ddsrt_chh * __restrict hh, const void * __restrict template)
{
const uint32_t idxmask = rt->size - 1;
uint32_t hopinfo = rt->buckets[bucket].hopinfo;
uint32_t idx;
for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) {
const uint32_t bidx = (bucket + idx) & idxmask;
void *data = rt->buckets[bidx].data;
if (data && rt->equals (data, template))
return data;
}
return NULL;
ddsrt_mutex_lock (&hh->lock);
int x = ddsrt_hh_remove (&hh->rt, template);
ddsrt_mutex_unlock (&hh->lock);
return x;
}
void *ddsrt_hh_lookup (const struct ddsrt_hh * __restrict rt, const void * __restrict template)
void ddsrt_chh_enum_unsafe (struct ddsrt_chh * __restrict hh, void (*f) (void *a, void *f_arg), void *f_arg)
{
const uint32_t hash = rt->hash (template);
const uint32_t idxmask = rt->size - 1;
const uint32_t bucket = hash & idxmask;
return ddsrt_hh_lookup_internal (rt, bucket, template);
ddsrt_mutex_lock (&hh->lock);
ddsrt_hh_enum (&hh->rt, f, f_arg);
ddsrt_mutex_unlock (&hh->lock);
}
static uint32_t ddsrt_hh_find_closer_free_bucket (struct ddsrt_hh *rt, uint32_t free_bucket, uint32_t *free_distance)
void *ddsrt_chh_iter_first (struct ddsrt_chh * __restrict hh, struct ddsrt_chh_iter *it)
{
const uint32_t idxmask = rt->size - 1;
uint32_t move_bucket, free_dist;
move_bucket = (free_bucket - (HH_HOP_RANGE - 1)) & idxmask;
for (free_dist = HH_HOP_RANGE - 1; free_dist > 0; free_dist--) {
uint32_t move_free_distance = NOT_A_BUCKET;
uint32_t mask = 1;
uint32_t i;
for (i = 0; i < free_dist; i++, mask <<= 1) {
if (mask & rt->buckets[move_bucket].hopinfo) {
move_free_distance = i;
break;
}
}
if (move_free_distance != NOT_A_BUCKET) {
uint32_t new_free_bucket = (move_bucket + move_free_distance) & idxmask;
rt->buckets[move_bucket].hopinfo |= 1u << free_dist;
rt->buckets[free_bucket].data = rt->buckets[new_free_bucket].data;
rt->buckets[new_free_bucket].data = NULL;
rt->buckets[move_bucket].hopinfo &= ~(1u << move_free_distance);
*free_distance -= free_dist - move_free_distance;
return new_free_bucket;
}
move_bucket = (move_bucket + 1) & idxmask;
}
return NOT_A_BUCKET;
ddsrt_mutex_lock (&hh->lock);
it->chh = hh;
void *x = ddsrt_hh_iter_first (&hh->rt, &it->it);
ddsrt_mutex_unlock (&hh->lock);
return x;
}
static void ddsrt_hh_resize (struct ddsrt_hh *rt)
void *ddsrt_chh_iter_next (struct ddsrt_chh_iter *it)
{
struct ddsrt_hh_bucket *bs1;
uint32_t i, idxmask0, idxmask1;
bs1 = ddsrt_malloc (2 * rt->size * sizeof (*rt->buckets));
for (i = 0; i < 2 * rt->size; i++) {
bs1[i].hopinfo = 0;
bs1[i].data = NULL;
}
idxmask0 = rt->size - 1;
idxmask1 = 2 * rt->size - 1;
for (i = 0; i < rt->size; i++) {
void *data = rt->buckets[i].data;
if (data) {
const uint32_t hash = rt->hash (data);
const uint32_t old_start_bucket = hash & idxmask0;
const uint32_t new_start_bucket = hash & idxmask1;
const uint32_t dist = (i >= old_start_bucket) ? (i - old_start_bucket) : (rt->size + i - old_start_bucket);
const uint32_t newb = (new_start_bucket + dist) & idxmask1;
assert (dist < HH_HOP_RANGE);
bs1[new_start_bucket].hopinfo |= 1u << dist;
bs1[newb].data = data;
}
}
ddsrt_free (rt->buckets);
rt->size *= 2;
rt->buckets = bs1;
ddsrt_mutex_lock (&it->chh->lock);
void *x = ddsrt_hh_iter_next (&it->it);
ddsrt_mutex_unlock (&it->chh->lock);
return x;
}
int ddsrt_hh_add (struct ddsrt_hh * __restrict rt, const void * __restrict data)
{
const uint32_t hash = rt->hash (data);
const uint32_t idxmask = rt->size - 1;
const uint32_t start_bucket = hash & idxmask;
uint32_t free_distance, free_bucket;
if (ddsrt_hh_lookup_internal (rt, start_bucket, data)) {
return 0;
}
free_bucket = start_bucket;
for (free_distance = 0; free_distance < HH_ADD_RANGE; free_distance++) {
if (rt->buckets[free_bucket].data == NULL)
break;
free_bucket = (free_bucket + 1) & idxmask;
}
if (free_distance < HH_ADD_RANGE) {
do {
if (free_distance < HH_HOP_RANGE) {
assert ((uint32_t) free_bucket == ((start_bucket + free_distance) & idxmask));
rt->buckets[start_bucket].hopinfo |= 1u << free_distance;
rt->buckets[free_bucket].data = (void *) data;
return 1;
}
free_bucket = ddsrt_hh_find_closer_free_bucket (rt, free_bucket, &free_distance);
assert (free_bucket == NOT_A_BUCKET || free_bucket <= idxmask);
} while (free_bucket != NOT_A_BUCKET);
}
ddsrt_hh_resize (rt);
return ddsrt_hh_add (rt, data);
}
int ddsrt_hh_remove (struct ddsrt_hh * __restrict rt, const void * __restrict template)
{
const uint32_t hash = rt->hash (template);
const uint32_t idxmask = rt->size - 1;
const uint32_t bucket = hash & idxmask;
uint32_t hopinfo;
uint32_t idx;
hopinfo = rt->buckets[bucket].hopinfo;
for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) {
if (hopinfo & 1) {
const uint32_t bidx = (bucket + idx) & idxmask;
void *data = rt->buckets[bidx].data;
if (data && rt->equals (data, template)) {
rt->buckets[bidx].data = NULL;
rt->buckets[bucket].hopinfo &= ~(1u << idx);
return 1;
}
}
}
return 0;
}
void ddsrt_hh_enum (struct ddsrt_hh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg)
{
uint32_t i;
for (i = 0; i < rt->size; i++) {
void *data = rt->buckets[i].data;
if (data) {
f (data, f_arg);
}
}
}
void *ddsrt_hh_iter_first (struct ddsrt_hh * __restrict rt, struct ddsrt_hh_iter * __restrict iter)
{
iter->hh = rt;
iter->cursor = 0;
return ddsrt_hh_iter_next (iter);
}
void *ddsrt_hh_iter_next (struct ddsrt_hh_iter * __restrict iter)
{
struct ddsrt_hh *rt = iter->hh;
while (iter->cursor < rt->size) {
void *data = rt->buckets[iter->cursor].data;
iter->cursor++;
if (data) {
return data;
}
}
return NULL;
}
#endif
/************* SEQUENTIAL VERSION WITH EMBEDDED DATA ***************/

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 <string.h>
#include <lwip/inet.h>
#include <lwip/netif.h> /* netif_list */
#include <lwip/sockets.h>
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/io.h"
#include "dds/ddsrt/ifaddrs.h"
#include "dds/ddsrt/retcode.h"
#include "dds/ddsrt/string.h"
extern const int *const os_supp_afs;
static uint32_t
getflags(
const struct netif *netif,
const ip_addr_t *addr)
{
uint32_t flags = 0;
if (netif->flags & NETIF_FLAG_UP) {
flags |= IFF_UP;
}
if (netif->flags & NETIF_FLAG_BROADCAST) {
flags |= IFF_BROADCAST;
}
if (netif->flags & NETIF_FLAG_IGMP) {
flags |= IFF_MULTICAST;
}
if (ip_addr_isloopback(addr)) {
flags |= IFF_LOOPBACK;
}
return flags;
}
static void
sockaddr_from_ip_addr(
struct sockaddr *sockaddr,
const ip_addr_t *addr)
{
if (IP_IS_V4(addr)) {
memset(sockaddr, 0, sizeof(struct sockaddr_in));
((struct sockaddr_in *)sockaddr)->sin_len = sizeof(struct sockaddr_in);
((struct sockaddr_in *)sockaddr)->sin_family = AF_INET;
inet_addr_from_ip4addr(&((struct sockaddr_in *)sockaddr)->sin_addr, addr);
#if DDSRT_HAVE_IPV6
} else {
assert(IP_IS_V6(addr));
memset(sockaddr, 0, sizeof(struct sockaddr_in6));
((struct sockaddr_in6 *)sockaddr)->sin6_len = sizeof(struct sockaddr_in6);
((struct sockaddr_in6 *)sockaddr)->sin6_family = AF_INET6;
inet6_addr_from_ip6addr(&((struct sockaddr_in6 *)sockaddr)->sin6_addr, addr);
#endif
}
}
static dds_return_t
copyaddr(
ddsrt_ifaddrs_t **ifap,
const struct netif *netif,
const ip_addr_t *addr)
{
dds_return_t rc = DDS_RETCODE_OK;
ddsrt_ifaddrs_t *ifa;
struct sockaddr_storage sa;
assert(ifap != NULL);
assert(netif != NULL);
assert(addr != NULL);
sockaddr_from_ip_addr((struct sockaddr *)&sa, addr);
/* Network interface name is of the form "et0", where the first two letters
are the "name" field and the digit is the num field of the netif
structure as described in lwip/netif.h */
if ((ifa = ddsrt_calloc_s(1, sizeof(*ifa))) == NULL ||
(ifa->addr = ddsrt_memdup(&sa, sa.s2_len)) == NULL ||
(ddsrt_asprintf(&ifa->name, "%s%d", netif->name, netif->num) == -1))
{
rc = DDS_RETCODE_OUT_OF_RESOURCES;
} else {
ifa->flags = getflags(netif, addr);
ifa->index = netif->num;
ifa->type = DDSRT_IFTYPE_UNKNOWN;
if (IP_IS_V4(addr)) {
static const size_t sz = sizeof(struct sockaddr_in);
if ((ifa->netmask = ddsrt_calloc_s(1, sz)) == NULL ||
(ifa->broadaddr = ddsrt_calloc_s(1, sz)) == NULL)
{
rc = DDS_RETCODE_OUT_OF_RESOURCES;
} else {
ip_addr_t broadaddr = IPADDR4_INIT(
ip_2_ip4(&netif->ip_addr)->addr |
ip_2_ip4(&netif->netmask)->addr);
sockaddr_from_ip_addr((struct sockaddr*)ifa->netmask, &netif->netmask);
sockaddr_from_ip_addr((struct sockaddr*)ifa->broadaddr, &broadaddr);
}
}
}
if (rc == DDS_RETCODE_OK) {
*ifap = ifa;
} else {
ddsrt_freeifaddrs(ifa);
}
return rc;
}
dds_return_t
ddsrt_getifaddrs(
ddsrt_ifaddrs_t **ifap,
const int *afs)
{
dds_return_t rc = DDS_RETCODE_OK;
int use_ip4, use_ip6;
struct netif *netif;
ddsrt_ifaddrs_t *ifa, *next_ifa, *root_ifa;
assert(ifap != NULL);
if (afs == NULL) {
afs = os_supp_afs;
}
use_ip4 = use_ip6 = 0;
for (int i = 0; afs[i] != DDSRT_AF_TERM; i++) {
if (afs[i] == AF_INET) {
use_ip4 = 1;
} else if (afs[i] == AF_INET6) {
use_ip6 = 1;
}
}
ifa = next_ifa = root_ifa = NULL;
for (netif = netif_list;
netif != NULL && rc == DDS_RETCODE_OK;
netif = netif->next)
{
if (use_ip4 && IP_IS_V4(&netif->ip_addr)) {
rc = copyaddr(&next_ifa, netif, &netif->ip_addr);
if (rc == DDS_RETCODE_OK) {
if (ifa == NULL) {
ifa = root_ifa = next_ifa;
} else {
ifa->next = next_ifa;
ifa = next_ifa;
}
}
}
#if DDSRT_HAVE_IPV6
if (use_ip6) {
int pref = 1;
again:
/* List preferred IPv6 address first. */
for (int i = 0;
i < LWIP_IPV6_NUM_ADDRESSES && rc == DDS_RETCODE_OK;
i++)
{
if ((ip6_addr_ispreferred(netif->ip_addr_state[i]) && pref) ||
(ip6_addr_isvalid(netif->ip_addr_state[i]) && !pref))
{
rc = copyaddr(&next_ifa, netif, &netif->ip_addr[i]);
if (rc == DDS_RETCODE_OK) {
if (ifa == NULL) {
ifa = root_ifa = next_ifa;
} else {
ifa->next = next_ifa;
ifa = next_ifa;
}
}
}
}
if (rc == DDS_RETCODE_OK && pref) {
pref = 0;
goto again;
}
}
#endif
}
if (rc == DDS_RETCODE_OK) {
*ifap = ifa;
} else {
ddsrt_freeifaddrs(root_ifa);
}
return rc;
}

View file

@ -21,10 +21,115 @@
extern const int *const os_supp_afs;
static dds_retcode_t
copyaddr(ddsrt_ifaddrs_t **ifap, const struct ifaddrs *sys_ifa)
#if defined __linux
#include <stdio.h>
static enum ddsrt_iftype guess_iftype (const struct ifaddrs *sys_ifa)
{
dds_retcode_t err = DDS_RETCODE_OK;
FILE *fp;
char ifnam[IFNAMSIZ + 1]; /* not sure whether IFNAMSIZ includes a terminating 0, can't be bothered */
int c;
size_t np;
enum ddsrt_iftype type = DDSRT_IFTYPE_UNKNOWN;
if ((fp = fopen ("/proc/net/wireless", "r")) == NULL)
return type;
/* expected format:
:Inter-| sta-| Quality | Discarded packets | Missed | WE
: face | tus | link level noise | nwid crypt frag retry misc | beacon | 22
: wlan0: 0000 67. -43. -256 0 0 0 0 0 0
(where : denotes the start of the line)
SKIP_HEADER_1 skips up to and including the first newline; then SKIP_TO_EOL skips
up to and including the second newline, so the first line that gets interpreted is
the third.
*/
enum { SKIP_HEADER_1, SKIP_WHITE, READ_NAME, SKIP_TO_EOL } state = SKIP_HEADER_1;
np = 0;
while (type != DDSRT_IFTYPE_WIFI && (c = fgetc (fp)) != EOF) {
switch (state) {
case SKIP_HEADER_1:
if (c == '\n') {
state = SKIP_TO_EOL;
}
break;
case SKIP_WHITE:
if (c != ' ' && c != '\t') {
ifnam[np++] = (char) c;
state = READ_NAME;
}
break;
case READ_NAME:
if (c == ':') {
ifnam[np] = 0;
if (strcmp (ifnam, sys_ifa->ifa_name) == 0)
type = DDSRT_IFTYPE_WIFI;
state = SKIP_TO_EOL;
np = 0;
} else if (np < sizeof (ifnam) - 1) {
ifnam[np++] = (char) c;
}
break;
case SKIP_TO_EOL:
if (c == '\n') {
state = SKIP_WHITE;
}
break;
}
}
fclose (fp);
return type;
}
#elif defined __APPLE__ /* probably works for all BSDs */
#include <sys/ioctl.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <net/if_media.h>
static enum ddsrt_iftype guess_iftype (const struct ifaddrs *sys_ifa)
{
int sock;
if ((sock = socket (sys_ifa->ifa_addr->sa_family, SOCK_DGRAM, 0)) == -1)
return DDSRT_IFTYPE_UNKNOWN;
struct ifmediareq ifmr;
enum ddsrt_iftype type;
memset (&ifmr, 0, sizeof (ifmr));
ddsrt_strlcpy (ifmr.ifm_name, sys_ifa->ifa_name, sizeof (ifmr.ifm_name));
if (ioctl (sock, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0)
{
type = DDSRT_IFTYPE_UNKNOWN;
}
else
{
switch (IFM_TYPE (ifmr.ifm_active))
{
case IFM_ETHER:
case IFM_TOKEN:
case IFM_FDDI:
type = DDSRT_IFTYPE_WIRED;
break;
case IFM_IEEE80211:
type = DDSRT_IFTYPE_WIFI;
break;
default:
type = DDSRT_IFTYPE_UNKNOWN;
break;
}
}
close (sock);
return type;
}
#else
static enum ddsrt_iftype guess_iftype (const struct ifaddrs *sys_ifa)
{
return DDSRT_IFTYPE_UNKNOWN;
}
#endif
static dds_return_t
copyaddr(ddsrt_ifaddrs_t **ifap, const struct ifaddrs *sys_ifa, enum ddsrt_iftype type)
{
dds_return_t err = DDS_RETCODE_OK;
ddsrt_ifaddrs_t *ifa;
size_t sz;
@ -37,6 +142,7 @@ copyaddr(ddsrt_ifaddrs_t **ifap, const struct ifaddrs *sys_ifa)
err = DDS_RETCODE_OUT_OF_RESOURCES;
} else {
ifa->index = if_nametoindex(sys_ifa->ifa_name);
ifa->type = type;
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 ||
@ -64,12 +170,12 @@ copyaddr(ddsrt_ifaddrs_t **ifap, const struct ifaddrs *sys_ifa)
return err;
}
dds_retcode_t
dds_return_t
ddsrt_getifaddrs(
ddsrt_ifaddrs_t **ifap,
const int *afs)
{
dds_retcode_t err = DDS_RETCODE_OK;
dds_return_t err = DDS_RETCODE_OK;
int use;
ddsrt_ifaddrs_t *ifa, *ifa_root, *ifa_next;
struct ifaddrs *sys_ifa, *sys_ifa_root;
@ -109,7 +215,8 @@ ddsrt_getifaddrs(
}
if (use) {
err = copyaddr(&ifa_next, sys_ifa);
enum ddsrt_iftype type = guess_iftype (sys_ifa);
err = copyaddr(&ifa_next, sys_ifa, type);
if (err == DDS_RETCODE_OK) {
if (ifa == NULL) {
ifa = ifa_root = ifa_next;

View file

@ -0,0 +1,84 @@
/*
* 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/ifaddrs.h"
#include <string.h>
#include <stdio.h>
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/retcode.h"
#include "dds/ddsrt/string.h"
extern const int *const os_supp_afs;
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/sockio.h>
#include <stdlib.h>
dds_return_t
ddsrt_getifaddrs(
ddsrt_ifaddrs_t **ret_ifap,
const int *afs)
{
int sock;
char *buf;
int32_t n;
struct ifconf ifc;
struct ifreq *ifr;
/* get interfaces */
buf = ddsrt_malloc (8192);
memset (&ifc, 0, sizeof (ifc));
ifc.ifc_len = 8192;
ifc.ifc_buf = buf;
sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ioctl (sock, SIOCGIFCONF, (char *) &ifc) < 0)
{
perror ("ioctl (SIOCGIFCONF)");
exit (77);
}
ddsrt_ifaddrs_t **ifap, *ifa_root;
ifap = &ifa_root; ifa_root = NULL;
ifr = ifc.ifc_req;
for (n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0; ifr++)
{
ddsrt_ifaddrs_t *ifa;
if (ifr->ifr_name[0] == '\0')
continue; /* Forget about anonymous network devices */
if (ifr->ifr_addr.sa_family != AF_INET) {
printf ("%s: not INET\n", ifr->ifr_name);
continue;
}
ifa = ddsrt_malloc (sizeof (*ifa));
memset (ifa, 0, sizeof (*ifa));
ifa->index = (int) (ifr - ifc.ifc_req);
ifa->flags = IFF_UP | ((strcmp(ifr->ifr_name, "lo0")==0) ? IFF_LOOPBACK : IFF_MULTICAST);
ifa->name = strdup (ifr->ifr_name);
ifa->addr = ddsrt_memdup (&ifr->ifr_addr, sizeof (struct sockaddr_in));
ifa->netmask = ddsrt_memdup (&ifr->ifr_addr, sizeof (struct sockaddr_in));
((struct sockaddr_in *) ifa->netmask)->sin_addr.s_addr = htonl (0xffffff00);
ifa->broadaddr = NULL;
ifa->next = NULL;
*ifap = ifa;
ifap = &ifa->next;
}
ddsrt_free (buf);
close (sock);
*ret_ifap = ifa_root;
return DDS_RETCODE_OK;
}

View file

@ -23,10 +23,10 @@
extern const int *const os_supp_afs;
static dds_retcode_t
static dds_return_t
getifaces(PIP_ADAPTER_ADDRESSES *ptr)
{
dds_retcode_t err = DDS_RETCODE_NOT_ENOUGH_SPACE;
dds_return_t err = DDS_RETCODE_NOT_ENOUGH_SPACE;
PIP_ADAPTER_ADDRESSES buf = NULL;
ULONG bufsz = 0; /* Size is determined on first iteration. */
ULONG ret;
@ -72,10 +72,10 @@ getifaces(PIP_ADAPTER_ADDRESSES *ptr)
return err;
}
static dds_retcode_t
static dds_return_t
getaddrtable(PMIB_IPADDRTABLE *ptr)
{
dds_retcode_t err = DDS_RETCODE_NOT_ENOUGH_SPACE;
dds_return_t err = DDS_RETCODE_NOT_ENOUGH_SPACE;
PMIB_IPADDRTABLE buf = NULL;
ULONG bufsz = 0;
DWORD ret;
@ -152,6 +152,21 @@ getflags(const PIP_ADAPTER_ADDRESSES iface)
return flags;
}
static enum ddsrt_iftype
guess_iftype (const PIP_ADAPTER_ADDRESSES iface)
{
switch (iface->IfType) {
case IF_TYPE_IEEE80211:
return DDSRT_IFTYPE_WIFI;
case IF_TYPE_ETHERNET_CSMACD:
case IF_TYPE_IEEE1394:
case IF_TYPE_ISO88025_TOKENRING:
return DDSRT_IFTYPE_WIRED;
default:
return DDSRT_IFTYPE_UNKNOWN;
}
}
static int
copyaddr(
ddsrt_ifaddrs_t **ifap,
@ -159,7 +174,7 @@ copyaddr(
const PMIB_IPADDRTABLE addrtable,
const PIP_ADAPTER_UNICAST_ADDRESS addr)
{
dds_retcode_t err = DDS_RETCODE_OK;
dds_return_t err = DDS_RETCODE_OK;
ddsrt_ifaddrs_t *ifa;
struct sockaddr *sa;
size_t sz;
@ -175,6 +190,7 @@ copyaddr(
err = DDS_RETCODE_OUT_OF_RESOURCES;
} else {
ifa->flags = getflags(iface);
ifa->type = guess_iftype(iface);
ifa->addr = ddsrt_memdup(sa, sz);
(void)ddsrt_asprintf(&ifa->name, "%wS", iface->FriendlyName);
if (ifa->addr == NULL || ifa->name == NULL) {
@ -220,7 +236,7 @@ copyaddr(
return err;
}
dds_retcode_t
dds_return_t
ddsrt_getifaddrs(
ddsrt_ifaddrs_t **ifap,
const int *afs)

View file

@ -18,10 +18,12 @@
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/threads.h"
#include "dds/ddsrt/static_assert.h"
#define MAX_ID_LEN (10)
#define MAX_TIMESTAMP_LEN (10 + 1 + 6)
#define MAX_TID_LEN (10)
#define HDR_LEN (MAX_TIMESTAMP_LEN + 1 + MAX_TID_LEN + 2)
#define HDR_LEN (MAX_TIMESTAMP_LEN + 2 + MAX_ID_LEN + 2 + MAX_TID_LEN + 2)
#define BUF_OFFSET HDR_LEN
@ -31,7 +33,7 @@ typedef struct {
} log_buffer_t;
typedef struct {
dds_log_write_fn_t funcs[2];
dds_log_write_fn_t func;
void *ptr;
FILE *out;
} log_sink_t;
@ -41,50 +43,58 @@ 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;
struct ddsrt_log_cfg_impl {
struct ddsrt_log_cfg_common c;
FILE *sink_fps[2];
};
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);
}
DDSRT_STATIC_ASSERT (sizeof (struct ddsrt_log_cfg_impl) <= sizeof (struct ddsrt_log_cfg));
static void nop_sink(void *ptr, const dds_log_data_t *data)
static void default_sink (void *ptr, const dds_log_data_t *data)
{
(void)ptr;
(void)data;
return;
if (ptr)
{
fwrite (data->message - data->hdrsize, 1, data->hdrsize + data->size + 1, (FILE *) ptr);
fflush ((FILE *) ptr);
}
}
#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 }
static struct ddsrt_log_cfg_impl logconfig = {
.c = {
.mask = DDS_LC_ERROR | DDS_LC_WARNING,
.tracemask = 0,
.domid = UINT32_MAX
},
.sink_fps = {
[LOG] = NULL,
[TRACE] = NULL
}
};
uint32_t *const dds_log_mask = &log_mask;
static log_sink_t sinks[2] = {
[LOG] = { .func = default_sink, .ptr = NULL, .out = NULL },
[TRACE] = { .func = default_sink, .ptr = NULL, .out = NULL }
};
#define RDLOCK (1)
#define WRLOCK (2)
uint32_t * const dds_log_mask = &logconfig.c.mask;
static void init_lock(void)
static void init_lock (void)
{
ddsrt_rwlock_init(&lock);
ddsrt_rwlock_init (&lock);
sinks[LOG].ptr = sinks[TRACE].ptr = stderr;
sinks[LOG].out = sinks[TRACE].out = stderr;
logconfig.sink_fps[LOG] = sinks[LOG].ptr;
logconfig.sink_fps[TRACE] = sinks[TRACE].ptr;
}
static void lock_sink(int type)
{
assert(type == RDLOCK || type == WRLOCK);
ddsrt_once(&lock_inited, &init_lock);
enum lock_type { RDLOCK, WRLOCK };
static void lock_sink (enum lock_type type)
{
ddsrt_once (&lock_inited, &init_lock);
if (type == RDLOCK) {
ddsrt_rwlock_read(&lock);
} else {
@ -92,154 +102,134 @@ static void lock_sink(int type)
}
}
static void unlock_sink(void)
static void unlock_sink (void)
{
ddsrt_rwlock_unlock(&lock);
ddsrt_rwlock_unlock (&lock);
}
static void set_active_log_sinks(void)
static void set_log_sink (log_sink_t *sink, dds_log_write_fn_t func, void *ptr)
{
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);
assert (sink != NULL);
assert (sink == &sinks[0] || sink == &sinks[1]);
/* 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();
lock_sink (WRLOCK);
sink->func = (func != 0) ? func : default_sink;
sink->ptr = ptr;
unlock_sink ();
}
/* dds_set_log_file must be considered private. */
void dds_set_log_file(FILE *file)
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();
lock_sink (WRLOCK);
logconfig.sink_fps[LOG] = (file == NULL ? stderr : file);
unlock_sink ();
}
void dds_set_trace_file(FILE *file)
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();
lock_sink (WRLOCK);
logconfig.sink_fps[TRACE] = (file == NULL ? stderr : file);
unlock_sink ();
}
void dds_set_log_sink(
dds_log_write_fn_t callback,
void *userdata)
void dds_set_log_sink (dds_log_write_fn_t callback, void *userdata)
{
set_log_sink(&sinks[LOG], callback, userdata);
set_log_sink (&sinks[LOG], callback, userdata);
}
void dds_set_trace_sink(
dds_log_write_fn_t callback,
void *userdata)
void dds_set_trace_sink (dds_log_write_fn_t callback, void *userdata)
{
set_log_sink(&sinks[TRACE], callback, userdata);
set_log_sink (&sinks[TRACE], callback, userdata);
}
extern inline uint32_t
dds_get_log_mask(void);
extern inline uint32_t dds_get_log_mask (void);
void
dds_set_log_mask(uint32_t cats)
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();
lock_sink (WRLOCK);
logconfig.c.tracemask = cats & DDS_TRACE_MASK;
logconfig.c.mask = (cats & (DDS_LOG_MASK | DDS_TRACE_MASK)) | DDS_LC_FATAL;
unlock_sink ();
}
static void print_header(char *str)
void dds_log_cfg_init (struct ddsrt_log_cfg *cfg, uint32_t domid, uint32_t tracemask, FILE *log_fp, FILE *trace_fp)
{
int cnt;
struct ddsrt_log_cfg_impl *cfgimpl = (struct ddsrt_log_cfg_impl *) cfg;
assert (domid != UINT32_MAX); /* because that's reserved for global use */
memset (cfgimpl, 0, sizeof (*cfgimpl));
cfgimpl->c.mask = tracemask | DDS_LOG_MASK;
cfgimpl->c.tracemask = tracemask;
cfgimpl->c.domid = domid;
cfgimpl->sink_fps[LOG] = log_fp;
cfgimpl->sink_fps[TRACE] = trace_fp;
}
static size_t print_header (char *str, uint32_t id)
{
int cnt, off;
char *tid, buf[MAX_TID_LEN+1] = { 0 };
static const char fmt[] = "%10u.%06d/%*.*s:";
static const char fmt_no_id[] = "%10u.%06d [] %*.*s:";
static const char fmt_with_id[] = "%10u.%06d [%"PRIu32"] %*.*s:";
dds_time_t time;
unsigned sec;
int usec;
(void)ddsrt_thread_getname(buf, sizeof(buf));
(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);
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. */
if (id == UINT32_MAX)
{
off = MAX_ID_LEN;
cnt = snprintf (str + off, HDR_LEN, fmt_no_id, sec, usec, MAX_TID_LEN, MAX_TID_LEN, tid);
}
else
{
/* low domain ids tend to be most used from what I have seen */
off = 9;
if (id >= 10)
for (uint32_t thres = 10; off > 0 && id >= thres; off--, thres *= 10);
cnt = snprintf (str + off, HDR_LEN, fmt_with_id, sec, usec, id, MAX_TID_LEN, MAX_TID_LEN, tid);
}
assert (off + cnt == (HDR_LEN - 1));
str[off + cnt] = ' '; /* Replace snprintf null byte by space. */
return (size_t) cnt;
}
static void vlog(
uint32_t cat,
const char *file,
uint32_t line,
const char *func,
const char *fmt,
va_list ap)
static void vlog1 (const struct ddsrt_log_cfg_impl *cfg, uint32_t cat, uint32_t domid, 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;
/* id can be used to override the id in logconfig, so that the global
logging configuration can be used for reporting errors while inlcuding
a domain id. This simply verifies that the id override is only ever
used with the global one. */
assert (domid == cfg->c.domid || cfg == &logconfig);
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;
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);
n = vsnprintf (lb->buf + lb->pos, nrem, fmt, ap);
if (n >= 0 && (size_t) n < nrem) {
lb->pos += (size_t) n;
} else {
@ -249,54 +239,89 @@ static void vlog(
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);
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);
if (fmt[strlen (fmt) - 1] == '\n' && lb->pos > BUF_OFFSET + 1) {
assert (lb->pos > BUF_OFFSET);
size_t hdrsize = print_header (lb->buf, domid);
data.priority = cat;
data.file = file;
data.function = func;
data.line = line;
data.message = lb->buf + BUF_OFFSET;
data.size = strlen(data.message) - 1;
data.size = lb->pos - BUF_OFFSET - 1;
data.hdrsize = hdrsize;
for (size_t i = (cat & DDS_LOG_MASK) ? LOG : TRACE;
i < sizeof(sinks) / sizeof(sinks[0]);
i++)
dds_log_write_fn_t f = 0;
void *f_arg = NULL;
if (cat & DDS_LOG_MASK)
{
sinks[i].funcs[USE](sinks[i].ptr, &data);
f = sinks[LOG].func;
f_arg = (f == default_sink) ? cfg->sink_fps[LOG] : sinks[LOG].ptr;
assert (f != 0);
f (f_arg, &data);
}
/* if tracing is enabled, then print to trace if it matches the
trace flags or if it got written to the log
(mask == (tracemask | DDS_LOG_MASK)) */
if (cfg->c.tracemask && (cat & cfg->c.mask))
{
dds_log_write_fn_t const g = sinks[TRACE].func;
void * const g_arg = (g == default_sink) ? cfg->sink_fps[TRACE] : sinks[TRACE].ptr;
assert (g != 0);
if (g != f || g_arg != f_arg)
g (g_arg, &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,
...)
static void vlog (const struct ddsrt_log_cfg_impl *cfg, uint32_t cat, uint32_t domid, const char *file, uint32_t line, const char *func, const char *fmt, va_list ap)
{
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) {
lock_sink (RDLOCK);
vlog1 (cfg, cat, domid, file, line, func, fmt, ap);
unlock_sink ();
if (cat & DDS_LC_FATAL)
abort();
}
return 0;
}
void dds_log_cfg (const struct ddsrt_log_cfg *cfg, uint32_t cat, const char *file, uint32_t line, const char *func, const char *fmt, ...)
{
const struct ddsrt_log_cfg_impl *cfgimpl = (const struct ddsrt_log_cfg_impl *) cfg;
/* cfgimpl->c.mask is too weak a test because it has all DDS_LOG_MASK bits set,
rather than just the ones in dds_get_log_mask() (so as not to cache the latter
and have to keep them synchronized */
if ((cfgimpl->c.mask & cat) && ((dds_get_log_mask () | cfgimpl->c.tracemask) & cat)) {
va_list ap;
va_start (ap, fmt);
vlog (cfgimpl, cat, cfgimpl->c.domid, file, line, func, fmt, ap);
va_end (ap);
}
}
void dds_log_id (uint32_t cat, uint32_t id, const char *file, uint32_t line, const char *func, const char *fmt, ...)
{
if (dds_get_log_mask () & cat) {
va_list ap;
va_start (ap, fmt);
vlog (&logconfig, cat, id, file, line, func, fmt, ap);
va_end (ap);
}
}
void dds_log (uint32_t cat, const char *file, uint32_t line, const char *func, const char *fmt, ...)
{
if (dds_get_log_mask () & cat) {
va_list ap;
va_start (ap, fmt);
vlog (&logconfig, cat, UINT32_MAX, file, line, func, fmt, ap);
va_end (ap);
}
}

View file

@ -0,0 +1,130 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_types.h>
#include <net/if.h>
#include <net/if_mib.h>
#include <errno.h>
#include <dds/ddsrt/heap.h>
#include <dds/ddsrt/string.h>
#include <dds/ddsrt/netstat.h>
struct ddsrt_netstat_control {
char *name;
int cached_row;
};
static dds_return_t ddsrt_netstat_get_int (struct ddsrt_netstat_control *control, struct ddsrt_netstat *stats)
{
int name[6];
size_t len;
int count;
struct ifmibdata ifmd;
if (control->cached_row > 0)
{
name[0] = CTL_NET;
name[1] = PF_LINK;
name[2] = NETLINK_GENERIC;
name[3] = IFMIB_IFDATA;
name[4] = control->cached_row;
name[5] = IFDATA_GENERAL;
len = sizeof (ifmd);
if (sysctl (name, 6, &ifmd, &len, NULL, 0) != 0)
control->cached_row = 0;
else if (strcmp (ifmd.ifmd_name, control->name) != 0)
control->cached_row = 0;
}
if (control->cached_row == 0)
{
name[0] = CTL_NET;
name[1] = PF_LINK;
name[2] = NETLINK_GENERIC;
name[3] = IFMIB_SYSTEM;
name[4] = IFMIB_IFCOUNT;
len = sizeof (count);
if (sysctl (name, 5, &count, &len, NULL, 0) != 0)
goto error;
for (int row = 1; row <= count; row++)
{
name[0] = CTL_NET;
name[1] = PF_LINK;
name[2] = NETLINK_GENERIC;
name[3] = IFMIB_IFDATA;
name[4] = row;
name[5] = IFDATA_GENERAL;
len = sizeof (ifmd);
if (sysctl (name, 6, &ifmd, &len, NULL, 0) != 0)
{
if (errno != ENOENT)
goto error;
}
else if (strcmp (control->name, ifmd.ifmd_name) == 0)
{
control->cached_row = row;
break;
}
}
}
if (control->cached_row == 0)
return DDS_RETCODE_NOT_FOUND;
else
{
stats->ipkt = ifmd.ifmd_data.ifi_ipackets;
stats->opkt = ifmd.ifmd_data.ifi_opackets;
stats->ibytes = ifmd.ifmd_data.ifi_ibytes;
stats->obytes = ifmd.ifmd_data.ifi_obytes;
return DDS_RETCODE_OK;
}
error:
control->cached_row = -1;
return DDS_RETCODE_ERROR;
}
dds_return_t ddsrt_netstat_new (struct ddsrt_netstat_control **control, const char *device)
{
struct ddsrt_netstat_control *c = ddsrt_malloc (sizeof (*c));
struct ddsrt_netstat dummy;
c->name = ddsrt_strdup (device);
c->cached_row = 0;
if (ddsrt_netstat_get_int (c, &dummy) != DDS_RETCODE_OK)
{
ddsrt_free (c->name);
ddsrt_free (c);
*control = NULL;
return DDS_RETCODE_ERROR;
}
else
{
*control = c;
return DDS_RETCODE_OK;
}
}
dds_return_t ddsrt_netstat_free (struct ddsrt_netstat_control *control)
{
ddsrt_free (control->name);
ddsrt_free (control);
return DDS_RETCODE_OK;
}
dds_return_t ddsrt_netstat_get (struct ddsrt_netstat_control *control, struct ddsrt_netstat *stats)
{
if (control->cached_row < 0)
return DDS_RETCODE_ERROR;
else
return ddsrt_netstat_get_int (control, stats);
}

View file

@ -0,0 +1,146 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <dds/ddsrt/heap.h>
#include <dds/ddsrt/string.h>
#include <dds/ddsrt/netstat.h>
struct ddsrt_netstat_control {
char *name;
};
dds_return_t ddsrt_netstat_get (struct ddsrt_netstat_control *control, struct ddsrt_netstat *stats)
{
FILE *fp;
char save[256];
int c;
size_t np;
int field = 0;
if ((fp = fopen ("/proc/net/dev", "r")) == NULL)
return DDS_RETCODE_ERROR;
/* expected format: 2 header lines, then on each line, white space/interface
name/colon and then numbers. Received bytes is 1st data field, transmitted
bytes is 9th.
SKIP_HEADER_1 skips up to and including the first newline; then SKIP_TO_EOL
skips up to and including the second newline, so the first line that gets
interpreted is the third.
*/
dds_return_t res = DDS_RETCODE_NOT_FOUND;
enum { SKIP_HEADER_1, SKIP_WHITE, READ_NAME, SKIP_TO_EOL, READ_SEP, READ_INT } state = SKIP_HEADER_1;
np = 0;
while (res == DDS_RETCODE_NOT_FOUND && (c = fgetc (fp)) != EOF) {
switch (state) {
case SKIP_HEADER_1:
if (c == '\n') {
state = SKIP_TO_EOL;
}
break;
case SKIP_WHITE:
if (c != ' ' && c != '\t') {
save[np++] = (char) c;
state = READ_NAME;
}
break;
case READ_NAME:
if (c == ':') {
save[np] = 0;
np = 0;
if (strcmp (save, control->name) != 0)
state = SKIP_TO_EOL;
else
state = READ_SEP;
} else if (np < sizeof (save) - 1) {
save[np++] = (char) c;
}
break;
case SKIP_TO_EOL:
if (c == '\n') {
state = SKIP_WHITE;
}
break;
case READ_SEP:
if (c == '\n')
{
/* unexpected end of line */
res = DDS_RETCODE_ERROR;
}
else if (c >= '0' && c <= '9')
{
field++;
save[np++] = (char) c;
state = READ_INT;
}
break;
case READ_INT:
if (c >= '0' && c <= '9')
{
if (np == sizeof (save) - 1)
{
res = DDS_RETCODE_ERROR;
break;
}
save[np++] = (char) c;
}
else
{
save[np] = 0;
np = 0;
if (field == 1 || field == 2 || field == 9 || field == 10)
{
int pos;
uint64_t val;
if (sscanf (save, "%"SCNu64"%n", &val, &pos) != 1 || save[pos] != 0)
res = DDS_RETCODE_ERROR;
else
{
switch (field)
{
case 1: stats->ibytes = val; break;
case 2: stats->ipkt = val; break;
case 9: stats->obytes = val; break;
case 10: stats->opkt = val; res = DDS_RETCODE_OK; break;
}
}
}
if (c == '\n' && res != DDS_RETCODE_OK)
{
/* newline before all expected fields have been read */
res = DDS_RETCODE_ERROR;
}
state = READ_SEP;
}
break;
}
}
fclose (fp);
return res;
}
dds_return_t ddsrt_netstat_new (struct ddsrt_netstat_control **control, const char *device)
{
struct ddsrt_netstat_control *c = ddsrt_malloc (sizeof (*c));
struct ddsrt_netstat dummy;
c->name = ddsrt_strdup (device);
if (ddsrt_netstat_get (c, &dummy) != DDS_RETCODE_OK)
{
ddsrt_free (c->name);
ddsrt_free (c);
*control = NULL;
return DDS_RETCODE_ERROR;
}
else
{
*control = c;
return DDS_RETCODE_OK;
}
}
dds_return_t ddsrt_netstat_free (struct ddsrt_netstat_control *control)
{
ddsrt_free (control->name);
ddsrt_free (control);
return DDS_RETCODE_OK;
}

View file

@ -0,0 +1,115 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <ws2def.h>
#include <ws2ipdef.h>
#include <iphlpapi.h>
#include <dds/ddsrt/heap.h>
#include <dds/ddsrt/string.h>
#include <dds/ddsrt/netstat.h>
struct ddsrt_netstat_control {
wchar_t *name;
bool errored;
bool have_index;
NET_IFINDEX index;
};
static void copy_data (struct ddsrt_netstat *dst, const MIB_IF_ROW2 *src)
{
dst->ipkt = src->InUcastPkts + src->InNUcastPkts;
dst->opkt = src->OutUcastPkts + src->OutNUcastPkts;
dst->ibytes = src->InOctets;
dst->obytes = src->OutOctets;
}
static bool is_desired_interface (const struct ddsrt_netstat_control *control, const MIB_IF_ROW2 *info)
{
return wcscmp (control->name, info->Description) == 0 || wcscmp (control->name, info->Alias) == 0;
}
static dds_return_t ddsrt_netstat_get_int (struct ddsrt_netstat_control *control, struct ddsrt_netstat *stats)
{
if (control->errored)
return DDS_RETCODE_ERROR;
if (control->have_index)
{
MIB_IF_ROW2 info;
memset (&info, 0, sizeof (info));
info.InterfaceIndex = control->index;
if (GetIfEntry2 (&info) != NO_ERROR || !is_desired_interface (control, &info))
control->have_index = false;
else
{
copy_data (stats, &info);
return DDS_RETCODE_OK;
}
}
MIB_IF_TABLE2 *table;
if (GetIfTable2 (&table) != NO_ERROR)
goto error;
control->have_index = false;
for (ULONG row = 0; row < table->NumEntries; row++)
{
if (is_desired_interface (control, &table->Table[row]))
{
control->index = table->Table[row].InterfaceIndex;
control->have_index = true;
copy_data (stats, &table->Table[row]);
break;
}
}
FreeMibTable (table);
return control->have_index ? DDS_RETCODE_OK : DDS_RETCODE_NOT_FOUND;
error:
control->errored = true;
return DDS_RETCODE_ERROR;
}
dds_return_t ddsrt_netstat_new (struct ddsrt_netstat_control **control, const char *device)
{
struct ddsrt_netstat_control *c = ddsrt_malloc (sizeof (*c));
struct ddsrt_netstat dummy;
size_t name_size = strlen (device) + 1;
c->name = ddsrt_malloc (name_size * sizeof (*c->name));
size_t cnt = 0;
mbstowcs_s (&cnt, c->name, name_size, device, _TRUNCATE);
c->have_index = false;
c->errored = false;
c->index = 0;
if (ddsrt_netstat_get_int (c, &dummy) != DDS_RETCODE_OK)
{
ddsrt_free (c->name);
ddsrt_free (c);
*control = NULL;
return DDS_RETCODE_ERROR;
}
else
{
*control = c;
return DDS_RETCODE_OK;
}
}
dds_return_t ddsrt_netstat_free (struct ddsrt_netstat_control *control)
{
ddsrt_free (control->name);
ddsrt_free (control);
return DDS_RETCODE_OK;
}
dds_return_t ddsrt_netstat_get (struct ddsrt_netstat_control *control, struct ddsrt_netstat *stats)
{
return ddsrt_netstat_get_int (control, stats);
}

View file

@ -0,0 +1,22 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "dds/ddsrt/process.h"
#include <FreeRTOS.h>
#include <task.h>
ddsrt_pid_t
ddsrt_getpid(void)
{
return xTaskGetCurrentTaskHandle();
}

View file

@ -72,7 +72,7 @@ static void no_op(int sig)
}
static dds_retcode_t
static dds_return_t
waitpids(
ddsrt_pid_t request_pid,
dds_duration_t timeout,
@ -81,7 +81,7 @@ waitpids(
{
struct sigaction sigactold;
struct sigaction sigact;
dds_retcode_t rv;
dds_return_t rv;
int options = 0;
int ret;
int s;
@ -148,13 +148,13 @@ waitpids(
dds_retcode_t
dds_return_t
ddsrt_proc_create(
const char *executable,
char *const argv[],
ddsrt_pid_t *pid)
{
dds_retcode_t rv;
dds_return_t rv;
char **exec_argv;
int exec_fds[2];
int exec_err;
@ -253,7 +253,7 @@ fail_pipe:
dds_retcode_t
dds_return_t
ddsrt_proc_waitpid(
ddsrt_pid_t pid,
dds_duration_t timeout,
@ -267,7 +267,7 @@ ddsrt_proc_waitpid(
dds_retcode_t
dds_return_t
ddsrt_proc_waitpids(
dds_duration_t timeout,
ddsrt_pid_t *pid,
@ -278,7 +278,7 @@ ddsrt_proc_waitpids(
dds_retcode_t
dds_return_t
ddsrt_proc_exists(
ddsrt_pid_t pid)
{
@ -294,7 +294,7 @@ ddsrt_proc_exists(
dds_retcode_t
dds_return_t
ddsrt_proc_kill(
ddsrt_pid_t pid)
{

View file

@ -29,24 +29,24 @@ ddsrt_getpid(void)
static HANDLE pid_to_phdl (ddsrt_pid_t pid);
static dds_retcode_t process_get_exit_code(HANDLE phdl, int32_t *code);
static dds_retcode_t process_kill (HANDLE phdl);
static char* commandline (const char *exe, char *const argv_in[]);
static BOOL child_add (HANDLE phdl);
static void child_remove (HANDLE phdl);
static DWORD child_list (HANDLE *list, DWORD max);
static HANDLE child_handle (ddsrt_pid_t pid);
static HANDLE pid_to_phdl (ddsrt_pid_t pid);
static dds_return_t process_get_exit_code(HANDLE phdl, int32_t *code);
static dds_return_t process_kill (HANDLE phdl);
static char* commandline (const char *exe, char *const argv_in[]);
static BOOL child_add (HANDLE phdl);
static void child_remove (HANDLE phdl);
static DWORD child_list (HANDLE *list, DWORD max);
static HANDLE child_handle (ddsrt_pid_t pid);
dds_retcode_t
dds_return_t
ddsrt_proc_create(
const char *executable,
char *const argv[],
ddsrt_pid_t *pid)
{
dds_retcode_t rv = DDS_RETCODE_ERROR;
dds_return_t rv = DDS_RETCODE_ERROR;
PROCESS_INFORMATION process_info;
STARTUPINFO si;
char *cmd;
@ -111,13 +111,13 @@ ddsrt_proc_create(
dds_retcode_t
dds_return_t
ddsrt_proc_waitpid(
ddsrt_pid_t pid,
dds_duration_t timeout,
int32_t *code)
{
dds_retcode_t rv = DDS_RETCODE_OK;
dds_return_t rv = DDS_RETCODE_OK;
HANDLE phdl;
DWORD ret;
@ -155,13 +155,13 @@ ddsrt_proc_waitpid(
dds_retcode_t
dds_return_t
ddsrt_proc_waitpids(
dds_duration_t timeout,
ddsrt_pid_t *pid,
int32_t *code)
{
dds_retcode_t rv = DDS_RETCODE_OK;
dds_return_t rv = DDS_RETCODE_OK;
HANDLE hdls[MAXIMUM_WAIT_OBJECTS];
HANDLE phdl;
DWORD cnt;
@ -208,11 +208,11 @@ ddsrt_proc_waitpids(
dds_retcode_t
dds_return_t
ddsrt_proc_exists(
ddsrt_pid_t pid)
{
dds_retcode_t rv = DDS_RETCODE_NOT_FOUND;
dds_return_t rv = DDS_RETCODE_NOT_FOUND;
HANDLE phdl;
phdl = pid_to_phdl(pid);
@ -235,11 +235,11 @@ ddsrt_proc_exists(
dds_retcode_t
dds_return_t
ddsrt_proc_kill(
ddsrt_pid_t pid)
{
dds_retcode_t rv = DDS_RETCODE_BAD_PARAMETER;
dds_return_t rv = DDS_RETCODE_BAD_PARAMETER;
HANDLE phdl;
phdl = pid_to_phdl(pid);
@ -262,12 +262,12 @@ pid_to_phdl(ddsrt_pid_t pid)
static dds_retcode_t
static dds_return_t
process_get_exit_code(
HANDLE phdl,
int32_t *code)
{
dds_retcode_t rv = DDS_RETCODE_ERROR;
dds_return_t rv = DDS_RETCODE_ERROR;
DWORD tr;
assert(phdl != 0);
@ -289,7 +289,7 @@ process_get_exit_code(
/* Forcefully kill the given process. */
static dds_retcode_t
static dds_return_t
process_kill(HANDLE phdl)
{
assert(phdl != 0);

View file

@ -61,6 +61,7 @@
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/time.h"
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/static_assert.h"
#define N DDSRT_MT19937_N
#define M 397
@ -186,9 +187,7 @@ void ddsrt_random_init (void)
if (!ddsrt_prng_makeseed (&seed))
{
/* Poor man's initialisation */
struct lengthof_seed_large_enough {
char ok[sizeof (seed.key) / sizeof (seed.key[0]) >= 3 ? 1 : -1];
};
DDSRT_STATIC_ASSERT (sizeof (seed.key) / sizeof (seed.key[0]) >= 3);
memset (&seed, 0, sizeof (seed));
dds_time_t now = dds_time ();
seed.key[0] = (uint32_t) ddsrt_getpid ();

View file

@ -11,8 +11,7 @@
*/
#include "dds/ddsrt/retcode.h"
static const char *retcodes[] =
{
static const char *retcodes[] = {
"Success",
"Error",
"Unsupported",
@ -42,19 +41,20 @@ static const char *xretcodes[] = {
"Not found"
};
const char *
dds_strretcode (dds_retcode_t rc)
const char *dds_strretcode (dds_return_t rc)
{
if (rc >= 0 &&
rc < (dds_retcode_t)(sizeof(retcodes) / sizeof(retcodes[0])))
{
const dds_return_t nretcodes = (dds_return_t) (sizeof (retcodes) / sizeof (retcodes[0]));
const dds_return_t nxretcodes = (dds_return_t) (sizeof (xretcodes) / sizeof (xretcodes[0]));
/* Retcodes used to be positive, but return values from the API would be a negative
and so there are/were/may be places outside the core library where dds_strretcode
is called with a -N for N a API return value, so ... play it safe and use the
magnitude */
if (rc < 0)
rc = -rc;
if (rc >= 0 && rc < nretcodes)
return retcodes[rc];
} else if (rc >= (DDS_XRETCODE_BASE) &&
rc < (dds_retcode_t)(DDS_XRETCODE_BASE + (sizeof(xretcodes) / sizeof(xretcodes[0]))))
{
else if (rc >= DDS_XRETCODE_BASE && rc < DDS_XRETCODE_BASE + nxretcodes)
return xretcodes[rc - DDS_XRETCODE_BASE];
}
return "Unknown return code";
else
return "Unknown return code";
}

View file

@ -0,0 +1,106 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <FreeRTOS.h>
#include <task.h>
#include <string.h>
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/rusage.h"
/* Task CPU time statistics require a high resolution timer. FreeRTOS
recommends a time base between 10 and 100 times faster than the tick
interrupt (https://www.freertos.org/rtos-run-time-stats.html), but does not
define a macro or function to retrieve the base. */
/* Require time base to be defined for conversion to nanoseconds. */
#define DDSRT_NSECS_IN_RUSAGE_TIME_BASE (1) /* FIXME: Make configurable! */
#if !defined(DDSRT_NSECS_IN_RUSAGE_TIME_BASE)
#error "Time base for run time stats is not defined"
#endif
static dds_return_t
rusage_self(ddsrt_rusage_t *usage)
{
dds_return_t rc = DDS_RETCODE_OK;
dds_duration_t nsecs;
UBaseType_t cnt, len;
TaskStatus_t *states = NULL, *ptr;
size_t size;
do {
len = uxTaskGetNumberOfTasks();
size = len * sizeof(*states);
if ((ptr = ddsrt_realloc_s(states, size)) == NULL) {
rc = DDS_RETCODE_OUT_OF_RESOURCES;
} else {
states = ptr;
/* uxTaskGetSystemState returns 0 if the TaskStatus_t buffer is not
sufficiently large enough. */
cnt = uxTaskGetSystemState(states, len, NULL);
}
} while (rc == DDS_RETCODE_OK && cnt == 0);
if (rc == DDS_RETCODE_OK) {
memset(usage, 0, sizeof(*usage));
for (len = cnt, cnt = 0; cnt < len; cnt++) {
nsecs = states[cnt].ulRunTimeCounter * DDSRT_NSECS_IN_RUSAGE_TIME_BASE;
usage->stime += nsecs; /* FIXME: Protect against possible overflow! */
}
}
ddsrt_free(states);
return rc;
}
static dds_return_t
rusage_thread(ddsrt_rusage_t *usage)
{
TaskStatus_t states;
memset(usage, 0, sizeof(*usage));
memset(&states, 0, sizeof(states));
vTaskGetInfo(xTaskGetCurrentTaskHandle(), &states, pdFALSE, eInvalid);
usage->stime = states.ulRunTimeCounter * DDSRT_NSECS_IN_RUSAGE_TIME_BASE;
return DDS_RETCODE_OK;
}
#if ! DDSRT_HAVE_THREAD_LIST
static
#endif
dds_return_t
ddsrt_getrusage_anythread(ddsrt_thread_list_id_t tid, ddsrt_rusage_t *__restrict usage)
{
assert(usage != NULL);
return rusage_thread(tid, usage);
}
dds_return_t
ddsrt_getrusage(enum ddsrt_getrusage_who who, ddsrt_rusage_t *usage)
{
dds_return_t rc;
assert(who == DDSRT_RUSAGE_SELF || who == DDSRT_RUSAGE_THREAD);
assert(usage != NULL);
if (who == DDSRT_RUSAGE_THREAD) {
rc = rusage_thread_anythread(xTaskGetCurrentTaskHandle(), usage);
} else {
rc = rusage_self(usage);
}
return rc;
}

View file

@ -15,87 +15,212 @@
#include <string.h>
#include <sys/resource.h>
#if defined(__APPLE__)
#include "dds/ddsrt/rusage.h"
#if defined __linux
#include <stdio.h>
#include <dirent.h>
dds_return_t
ddsrt_getrusage_anythread (
ddsrt_thread_list_id_t tid,
ddsrt_rusage_t * __restrict usage)
{
/* Linux' man pages happily state that the second field is the process/task name
in parentheses, and that %s is the correct scanf conversion. As it turns out
the process name itself can contain spaces and parentheses ... so %s is not a
good choice for the general case. The others are spec'd as a character or a
number, which suggests the correct procedure is to have the 2nd field start at
the first ( and end at the last ) ...
RSS is per-process, so no point in populating that one
field 14, 15: utime, stime (field 1 is first)
Voluntary and involuntary context switches can be found in .../status, but
not in stat; and .../status does not give the time. Crazy. */
const double hz = (double) sysconf (_SC_CLK_TCK);
char file[100];
FILE *fp;
int pos;
pos = snprintf (file, sizeof (file), "/proc/self/task/%lu/stat", (unsigned long) tid);
if (pos < 0 || pos >= (int) sizeof (file))
return DDS_RETCODE_ERROR;
if ((fp = fopen (file, "r")) == NULL)
return DDS_RETCODE_NOT_FOUND;
/* max 2 64-bit ints plus some whitespace; need 1 extra for detecting something
went wrong and we ended up gobbling up garbage; 64 will do */
char save[64];
size_t savepos = 0;
int prevc, c;
int field = 1;
for (prevc = 0; (c = fgetc (fp)) != EOF; prevc = c)
{
if (field == 1)
{
if (c == '(')
field = 2;
}
else if (field >= 2)
{
/* each close paren resets the field counter to 3 (the first is common,
further ones are rare and occur only if the thread name contains a
closing parenthesis), as well as the save space for fields 14 & 15
that we care about. */
if (c == ')')
{
field = 2;
savepos = 0;
}
else
{
/* next field on transition of whitespace to non-whitespace */
if (c != ' ' && prevc == ' ')
field++;
/* save fields 14 & 15 while continuing scanning to EOF on the off-chance
that 14&15 initially appear to be in what ultimately turns out to be
task name */
if (field == 14 || field == 15)
{
if (savepos < sizeof (save) - 1)
save[savepos++] = (char) c;
}
}
}
}
fclose (fp);
assert (savepos < sizeof (save));
save[savepos] = 0;
if (savepos == sizeof (save) - 1)
return DDS_RETCODE_ERROR;
/* it's really integer, but the conversion from an unknown HZ value is much
less tricky in floating-point */
double user, sys;
if (sscanf (save, "%lf %lf%n", &user, &sys, &pos) != 2 || (save[pos] != 0 && save[pos] != ' '))
return DDS_RETCODE_ERROR;
usage->utime = (dds_time_t) (1e9 * user / hz);
usage->stime = (dds_time_t) (1e9 * sys / hz);
usage->idrss = 0;
usage->maxrss = 0;
usage->nvcsw = 0;
usage->nivcsw = 0;
pos = snprintf (file, sizeof (file), "/proc/self/task/%lu/status", (unsigned long) tid);
if (pos < 0 || pos >= (int) sizeof (file))
return DDS_RETCODE_ERROR;
if ((fp = fopen (file, "r")) == NULL)
return DDS_RETCODE_NOT_FOUND;
enum { ERROR, READ_HEADING, SKIP_TO_EOL, READ_VCSW, READ_IVCSW } state = READ_HEADING;
savepos = 0;
while (state != ERROR && (c = fgetc (fp)) != EOF)
{
switch (state)
{
case READ_HEADING:
if (savepos < sizeof (save) - 1)
save[savepos++] = (char) c;
if (c == ':')
{
save[savepos] = 0;
savepos = 0;
if (strcmp (save, "voluntary_ctxt_switches:") == 0)
state = READ_VCSW;
else if (strcmp (save, "nonvoluntary_ctxt_switches:") == 0)
state = READ_IVCSW;
else
state = SKIP_TO_EOL;
}
break;
case SKIP_TO_EOL:
if (c == '\n')
state = READ_HEADING;
break;
case READ_VCSW:
case READ_IVCSW:
if (fscanf (fp, "%zu", (state == READ_VCSW) ? &usage->nvcsw : &usage->nivcsw) != 1)
state = ERROR;
else
state = SKIP_TO_EOL;
break;
case ERROR:
break;
}
}
fclose (fp);
return (state == ERROR) ? DDS_RETCODE_ERROR : DDS_RETCODE_OK;
}
dds_return_t
ddsrt_getrusage (enum ddsrt_getrusage_who who, ddsrt_rusage_t *usage)
{
struct rusage buf;
assert (who == DDSRT_RUSAGE_SELF || who == DDSRT_RUSAGE_THREAD);
assert (usage != NULL);
memset (&buf, 0, sizeof(buf));
if (getrusage ((who == DDSRT_RUSAGE_SELF) ? RUSAGE_SELF : RUSAGE_THREAD, &buf) == -1)
return DDS_RETCODE_ERROR;
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 = 1024 * (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;
return DDS_RETCODE_OK;
}
#elif 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)
dds_return_t
ddsrt_getrusage_anythread (
ddsrt_thread_list_id_t tid,
ddsrt_rusage_t * __restrict usage)
{
int err = 0;
struct rusage buf;
dds_retcode_t rc;
mach_msg_type_number_t cnt;
thread_basic_info_data_t info;
cnt = THREAD_BASIC_INFO_COUNT;
if (thread_info ((mach_port_t) tid, THREAD_BASIC_INFO, (thread_info_t) &info, &cnt) != KERN_SUCCESS)
return DDS_RETCODE_ERROR;
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;
/* Don't see an (easy) way to get context switch counts */
usage->utime = info.user_time.seconds * DDS_NSECS_IN_SEC + info.user_time.microseconds * DDS_NSECS_IN_USEC;
usage->stime = info.system_time.seconds * DDS_NSECS_IN_SEC + info.system_time.microseconds * DDS_NSECS_IN_USEC;
usage->idrss = 0;
usage->maxrss = 0;
usage->nivcsw = 0;
usage->nvcsw = 0;
return DDS_RETCODE_OK;
}
dds_return_t
ddsrt_getrusage (enum ddsrt_getrusage_who who, ddsrt_rusage_t *usage)
{
struct rusage buf;
dds_return_t rc;
assert (usage != NULL);
memset (&buf, 0, sizeof(buf));
if (getrusage (RUSAGE_SELF, &buf) == -1)
return DDS_RETCODE_ERROR;
switch (who) {
case DDSRT_RUSAGE_THREAD:
if ((rc = ddsrt_getrusage_anythread (pthread_mach_thread_np (pthread_self()), usage)) < 0)
return rc;
break;
case DDSRT_RUSAGE_SELF:
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->nvcsw = (size_t) buf.ru_nvcsw;
usage->nivcsw = (size_t) buf.ru_nivcsw;
break;
}
usage->maxrss = (size_t) buf.ru_maxrss;
usage->idrss = (size_t) buf.ru_idrss;
return DDS_RETCODE_OK;
}
#endif

View file

@ -18,36 +18,60 @@
#include <psapi.h>
dds_time_t
filetime_to_time(const FILETIME *ft)
filetime_to_time (const FILETIME *ft)
{
/* FILETIME structures express times in 100-nanosecond time units. */
return ((ft->dwHighDateTime << 31) + (ft->dwLowDateTime)) * 100;
return (dds_time_t) ((((uint64_t) ft->dwHighDateTime << 31) + (ft->dwLowDateTime)) * 100);
}
dds_retcode_t
ddsrt_getrusage(int who, ddsrt_rusage_t *usage)
dds_return_t
ddsrt_getrusage_anythread (ddsrt_thread_list_id_t tid, ddsrt_rusage_t * __restrict usage)
{
FILETIME stime, utime, ctime, etime;
PROCESS_MEMORY_COUNTERS pmctrs;
assert(who == DDSRT_RUSAGE_SELF || who == DDSRT_RUSAGE_THREAD);
assert(usage != NULL);
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;
if (!GetThreadTimes (tid, &ctime, &etime, &stime, &utime))
return DDS_RETCODE_ERROR;
memset (usage, 0, sizeof (*usage));
usage->stime = filetime_to_time (&stime);
usage->utime = filetime_to_time (&utime);
return DDS_RETCODE_OK;
}
dds_return_t
ddsrt_getrusage (enum ddsrt_getrusage_who who, ddsrt_rusage_t *usage)
{
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)))
return DDS_RETCODE_ERROR;
if (who == DDSRT_RUSAGE_THREAD)
{
dds_return_t rc;
if ((rc = ddsrt_getrusage_anythread (GetCurrentThread (), usage)) < 0)
return rc;
}
else
{
FILETIME stime, utime, ctime, etime;
if (!GetProcessTimes (GetCurrentProcess (), &ctime, &etime, &stime, &utime))
return DDS_RETCODE_ERROR;
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;
}

View file

@ -15,19 +15,21 @@
#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"
#if !LWIP_SOCKET
# 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 */
#endif /* LWIP_SOCKET */
extern inline struct timeval *
ddsrt_duration_to_timeval_ceil(dds_duration_t reltime, struct timeval *tv);
@ -37,7 +39,7 @@ const struct in6_addr ddsrt_in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
#endif
const int afs[] = {
#ifdef __linux
#if defined(__linux) && !LWIP_SOCKET
AF_PACKET,
#endif /* __linux */
#if DDSRT_HAVE_IPV6
@ -62,7 +64,7 @@ ddsrt_sockaddr_get_size(const struct sockaddr *const sa)
sz = sizeof(struct sockaddr_in6);
break;
#endif /* DDSRT_HAVE_IPV6 */
#ifdef __linux
#if defined(__linux) && !LWIP_SOCKET
case AF_PACKET:
sz = sizeof(struct sockaddr_ll);
break;
@ -175,7 +177,7 @@ ddsrt_sockaddr_insamesubnet(
return eq;
}
dds_retcode_t
dds_return_t
ddsrt_sockaddrfromstr(int af, const char *str, void *sa)
{
assert(str != NULL);
@ -184,13 +186,19 @@ ddsrt_sockaddrfromstr(int af, const char *str, void *sa)
switch (af) {
case AF_INET: {
struct in_addr buf;
#if DDSRT_HAVE_INET_PTON
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));
}
#else
buf.s_addr = inet_addr (str);
if (buf.s_addr == (in_addr_t)-1) {
return DDS_RETCODE_BAD_PARAMETER;
}
#endif
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: {
@ -211,17 +219,28 @@ ddsrt_sockaddrfromstr(int af, const char *str, void *sa)
return DDS_RETCODE_OK;
}
dds_retcode_t ddsrt_sockaddrtostr(const void *sa, char *buf, size_t size)
dds_return_t ddsrt_sockaddrtostr(const void *sa, char *buf, size_t size)
{
const char *ptr;
assert(sa != NULL);
assert(buf != NULL);
#if LWIP_SOCKET
DDSRT_WARNING_GNUC_OFF(sign-conversion)
#endif
switch (((struct sockaddr *)sa)->sa_family) {
case AF_INET:
#if DDSRT_HAVE_INET_NTOP
ptr = inet_ntop(
AF_INET, &((struct sockaddr_in *)sa)->sin_addr, buf, (socklen_t)size);
#else
{
in_addr_t x = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
snprintf(buf,size,"%u.%u.%u.%u",(x>>24),(x>>16)&0xff,(x>>8)&0xff,x&0xff);
ptr = buf;
}
#endif
break;
#if DDSRT_HAVE_IPV6
case AF_INET6:
@ -232,6 +251,9 @@ dds_retcode_t ddsrt_sockaddrtostr(const void *sa, char *buf, size_t size)
default:
return DDS_RETCODE_BAD_PARAMETER;
}
#if LWIP_SOCKET
DDSRT_WARNING_GNUC_ON(sign-conversion)
#endif
if (ptr == NULL) {
return DDS_RETCODE_NOT_ENOUGH_SPACE;
@ -241,7 +263,8 @@ dds_retcode_t ddsrt_sockaddrtostr(const void *sa, char *buf, size_t size)
}
#if DDSRT_HAVE_DNS
dds_retcode_t
#if DDSRT_HAVE_GETADDRINFO
dds_return_t
ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp)
{
int gai_err = 0;
@ -279,7 +302,6 @@ ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp)
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:
@ -312,10 +334,14 @@ ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp)
/* Other system error. */
return DDS_RETCODE_ERROR;
#endif
#if defined(EAI_BADFLAGS)
case EAI_BADFLAGS: /* Invalid flags in hints.ai_flags. */
#endif
case EAI_FAMILY: /* Address family not supported. */
case EAI_SERVICE: /* Service not available for socket type. */
#if defined(EAI_SOCKTYPE)
case EAI_SOCKTYPE: /* Socket type not supported. */
#endif
case 0: {
struct addrinfo *ai;
size_t addrno, naddrs, size;
@ -344,11 +370,30 @@ ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp)
freeaddrinfo(res);
} break;
default:
DDS_ERROR("getaddrinfo returned unkown error %d\n", gai_err);
DDS_ERROR ("getaddrinfo returned unkown error %d\n", gai_err);
return DDS_RETCODE_ERROR;
}
*hentp = hent;
return DDS_RETCODE_OK;
}
#else
dds_return_t
ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp)
{
struct hostent hest, *he;
char buf[256];
int err;
he = gethostbyname_r (name, &hest, buf, sizeof (buf), &err);
if (he == NULL) {
return DDS_RETCODE_HOST_NOT_FOUND;
} else {
size_t size = sizeof(**hentp) + (1 * sizeof((*hentp)->addrs[0]));
*hentp = ddsrt_calloc_s(1, size);
(*hentp)->naddrs = 1;
memcpy(&(*hentp)->addrs[0], he->h_addr, he->h_length);
return DDS_RETCODE_OK;
}
}
#endif /* DDSRT_HAVE_GETADDRINFO */
#endif /* DDSRT_HAVE_DNS */

View file

@ -17,6 +17,7 @@
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/sockets.h"
#include "dds/ddsrt/time.h"
#include "dds/ddsrt/static_assert.h"
#if defined(__cplusplus)
extern "C" {
@ -27,12 +28,8 @@ 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.
*
@ -52,19 +49,21 @@ ddsrt_duration_to_timeval_ceil(dds_duration_t reltime, struct timeval *tv)
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);
DDSRT_STATIC_ASSERT (CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 32 || CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 64);
if (CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 32)
max_nsecs = INT32_MAX * DDS_NSECS_IN_SEC;
} else {
max_nsecs = DDSRT_TIME_T_MAX / DDS_NSECS_IN_SEC;
}
else
max_nsecs = INT64_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);
tv->tv_usec = (int)((reltime % DDS_NSECS_IN_SEC) / DDS_NSECS_IN_USEC);
} else {
tv->tv_sec = DDSRT_TIME_T_MAX;
if (CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 32)
tv->tv_sec = (ddsrt_tv_sec_t) INT32_MAX;
else
tv->tv_sec = (ddsrt_tv_sec_t) INT64_MAX;
tv->tv_usec = 999999;
}
} else {

View file

@ -10,22 +10,46 @@
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include "dds/ddsrt/sockets.h"
#include "dds/ddsrt/string.h"
#if !LWIP_SOCKET
#include <errno.h>
#endif
#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
#if !defined(HOST_NAME_MAX)
# if LWIP_SOCKET
# define HOST_NAME_MAX DNS_MAX_NAME_LENGTH
# elif defined(_POSIX_HOST_NAME_MAX)
# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
# endif
#endif
#include "dds/ddsrt/sockets.h"
#include "dds/ddsrt/string.h"
dds_retcode_t
#if LWIP_SOCKET
dds_return_t
ddsrt_gethostname(
char *name,
size_t len)
{
if (ddsrt_strlcpy(name, "localhost", len) >= len) {
return DDS_RETCODE_NOT_ENOUGH_SPACE;
}
return DDS_RETCODE_OK;
}
#else
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 256
#endif
dds_return_t
ddsrt_gethostname(
char *name,
size_t len)
@ -59,3 +83,4 @@ ddsrt_gethostname(
return DDS_RETCODE_ERROR;
}
#endif

View file

@ -10,10 +10,14 @@
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/sockets_priv.h"
#if !LWIP_SOCKET
#if defined(__VXWORKS__)
#include <vxWorks.h>
#include <sockLib.h>
@ -21,6 +25,7 @@
#else
#include <sys/fcntl.h>
#endif /* __VXWORKS__ */
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#ifdef __sun
@ -30,12 +35,9 @@
#ifdef __APPLE__
#include <sys/sockio.h>
#endif /* __APPLE__ */
#endif /* LWIP_SOCKET */
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/sockets_priv.h"
dds_retcode_t
dds_return_t
ddsrt_socket(ddsrt_socket_t *sockptr, int domain, int type, int protocol)
{
ddsrt_socket_t sock;
@ -66,7 +68,7 @@ ddsrt_socket(ddsrt_socket_t *sockptr, int domain, int type, int protocol)
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_close(
ddsrt_socket_t sock)
{
@ -85,7 +87,7 @@ ddsrt_close(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_bind(
ddsrt_socket_t sock,
const struct sockaddr *addr,
@ -110,7 +112,7 @@ ddsrt_bind(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_listen(
ddsrt_socket_t sock,
int backlog)
@ -133,7 +135,7 @@ ddsrt_listen(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_connect(
ddsrt_socket_t sock,
const struct sockaddr *addr,
@ -175,7 +177,7 @@ ddsrt_connect(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_accept(
ddsrt_socket_t sock,
struct sockaddr *addr,
@ -222,7 +224,7 @@ ddsrt_accept(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_getsockname(
ddsrt_socket_t sock,
struct sockaddr *addr,
@ -246,7 +248,7 @@ ddsrt_getsockname(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_getsockopt(
ddsrt_socket_t sock,
int32_t level,
@ -254,6 +256,15 @@ ddsrt_getsockopt(
void *optval,
socklen_t *optlen)
{
#if LWIP_SOCKET
if (optname == SO_SNDBUF || optname == SO_RCVBUF)
return DDS_RETCODE_BAD_PARAMETER;
# if !SO_REUSE
if (optname == SO_REUSEADDR)
return DDS_RETCODE_BAD_PARAMETER;
# endif /* SO_REUSE */
#endif /* LWIP_SOCKET */
if (getsockopt(sock, level, optname, optval, optlen) == 0)
return DDS_RETCODE_OK;
@ -271,7 +282,7 @@ ddsrt_getsockopt(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_setsockopt(
ddsrt_socket_t sock,
int32_t level,
@ -279,6 +290,15 @@ ddsrt_setsockopt(
const void *optval,
socklen_t optlen)
{
#if LWIP_SOCKET
if (optname == SO_SNDBUF || optname == SO_RCVBUF)
return DDS_RETCODE_BAD_PARAMETER;
# if !SO_REUSE
if (optname == SO_REUSEADDR)
return DDS_RETCODE_BAD_PARAMETER;
# endif /* SO_REUSE */
#endif /* LWIP_SOCKET */
switch (optname) {
case SO_SNDBUF:
case SO_RCVBUF:
@ -319,7 +339,7 @@ err_setsockopt:
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_setsocknonblocking(
ddsrt_socket_t sock,
bool nonblock)
@ -357,7 +377,7 @@ err_fcntl:
return DDS_RETCODE_ERROR;
}
static inline dds_retcode_t
static inline dds_return_t
recv_error_to_retcode(int errnum)
{
switch (errnum) {
@ -386,7 +406,7 @@ recv_error_to_retcode(int errnum)
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_recv(
ddsrt_socket_t sock,
void *buf,
@ -405,7 +425,25 @@ ddsrt_recv(
return recv_error_to_retcode(errno);
}
dds_retcode_t
#if LWIP_SOCKET && !defined(recvmsg)
static ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
{
assert(msg->msg_iovlen == 1);
assert(msg->msg_controllen == 0);
msg->msg_flags = 0;
return recvfrom(
sockfd,
msg->msg_iov[0].iov_base,
msg->msg_iov[0].iov_len,
flags,
msg->msg_name,
&msg->msg_namelen);
}
#endif /* LWIP_SOCKET */
dds_return_t
ddsrt_recvmsg(
ddsrt_socket_t sock,
ddsrt_msghdr_t *msg,
@ -423,11 +461,12 @@ ddsrt_recvmsg(
return recv_error_to_retcode(errno);
}
static inline dds_retcode_t
static inline dds_return_t
send_error_to_retcode(int errnum)
{
switch (errnum) {
case EACCES:
case EPERM:
return DDS_RETCODE_NOT_ALLOWED;
case EAGAIN:
#if EAGAIN != EWOULDBLOCK
@ -465,7 +504,7 @@ send_error_to_retcode(int errnum)
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_send(
ddsrt_socket_t sock,
const void *buf,
@ -484,7 +523,7 @@ ddsrt_send(
return send_error_to_retcode(errno);
}
dds_retcode_t
dds_return_t
ddsrt_sendmsg(
ddsrt_socket_t sock,
const ddsrt_msghdr_t *msg,
@ -502,7 +541,7 @@ ddsrt_sendmsg(
return send_error_to_retcode(errno);
}
dds_retcode_t
dds_return_t
ddsrt_select(
int32_t nfds,
fd_set *readfds,

View file

@ -52,11 +52,11 @@ ddsrt_winsock_fini(void)
WSACleanup();
}
dds_retcode_t
dds_return_t
ddsrt_socket(ddsrt_socket_t *sockptr, int domain, int type, int protocol)
{
int err;
dds_retcode_t ret = DDS_RETCODE_OK;
dds_return_t ret = DDS_RETCODE_OK;
ddsrt_socket_t sock = DDSRT_INVALID_SOCKET;
assert(sockptr != NULL);
@ -93,7 +93,7 @@ ddsrt_socket(ddsrt_socket_t *sockptr, int domain, int type, int protocol)
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_close(ddsrt_socket_t sock)
{
int err;
@ -120,7 +120,7 @@ ddsrt_close(ddsrt_socket_t sock)
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_accept(
ddsrt_socket_t sock,
struct sockaddr *addr,
@ -162,7 +162,7 @@ ddsrt_accept(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_bind(ddsrt_socket_t sock, const struct sockaddr *addr, socklen_t addrlen)
{
int err;
@ -195,7 +195,7 @@ ddsrt_bind(ddsrt_socket_t sock, const struct sockaddr *addr, socklen_t addrlen)
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_listen(
ddsrt_socket_t sock,
int backlog)
@ -227,7 +227,7 @@ ddsrt_listen(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_connect(
ddsrt_socket_t sock,
const struct sockaddr *addr,
@ -275,7 +275,7 @@ ddsrt_connect(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_getsockname(
ddsrt_socket_t sock,
struct sockaddr *addr,
@ -309,7 +309,7 @@ ddsrt_getsockname(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_getsockopt(
ddsrt_socket_t sock,
int32_t level,
@ -358,7 +358,7 @@ ddsrt_getsockopt(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_setsockopt(
ddsrt_socket_t sock,
int32_t level,
@ -404,7 +404,7 @@ ddsrt_setsockopt(
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_setsocknonblocking(
ddsrt_socket_t sock,
bool nonblock)
@ -435,7 +435,7 @@ ddsrt_setsocknonblocking(
return DDS_RETCODE_ERROR;
}
static dds_retcode_t recv_error_to_retcode(int errnum)
static dds_return_t recv_error_to_retcode(int errnum)
{
assert(errnum != WSANOTINITIALISED);
switch (errnum) {
@ -470,7 +470,7 @@ static dds_retcode_t recv_error_to_retcode(int errnum)
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_recv(
ddsrt_socket_t sock,
void *buf,
@ -490,7 +490,7 @@ ddsrt_recv(
return recv_error_to_retcode(WSAGetLastError());
}
dds_retcode_t
dds_return_t
ddsrt_recvmsg(
ddsrt_socket_t sock,
ddsrt_msghdr_t *msg,
@ -531,7 +531,7 @@ ddsrt_recvmsg(
return recv_error_to_retcode(err);
}
static dds_retcode_t
static dds_return_t
send_error_to_retcode(int errnum)
{
assert(errnum != WSANOTINITIALISED);
@ -577,7 +577,7 @@ send_error_to_retcode(int errnum)
return DDS_RETCODE_ERROR;
}
dds_retcode_t
dds_return_t
ddsrt_send(
ddsrt_socket_t sock,
const void *buf,
@ -608,7 +608,7 @@ struct iovec_matches_WSABUF {
char len_size_matches[sizeof(((ddsrt_iovec_t *)8)->iov_len) == sizeof(((WSABUF *)8)->len) ? 1 : -1];
};
dds_retcode_t
dds_return_t
ddsrt_sendmsg(
ddsrt_socket_t sock,
const ddsrt_msghdr_t *msg,
@ -639,7 +639,7 @@ ddsrt_sendmsg(
return send_error_to_retcode(WSAGetLastError());
}
dds_retcode_t
dds_return_t
ddsrt_select(
int32_t nfds,
fd_set *readfds,

View file

@ -12,9 +12,6 @@
#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"
@ -65,19 +62,6 @@ ddsrt_strncasecmp(
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)
{
@ -178,4 +162,3 @@ ddsrt_strdup(
return ddsrt_memdup(str, strlen(str) + 1);
}

View file

@ -21,7 +21,7 @@
#include "dds/ddsrt/string.h"
dds_retcode_t
dds_return_t
ddsrt_strerror_r(int errnum, char *buf, size_t buflen)
{
assert(buf != NULL);

View file

@ -0,0 +1,34 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/* 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 <stdio.h>
#include "dds/ddsrt/string.h"
dds_return_t
ddsrt_strerror_r(int errnum, char *buf, size_t buflen)
{
assert(buf != NULL);
assert(buflen > 0);
if (snprintf (buf, buflen, "errno=%d", errnum) >= buflen)
return DDS_RETCODE_NOT_ENOUGH_SPACE;
else
return DDS_RETCODE_OK;
}

View file

@ -96,12 +96,12 @@ os_lcNumericReplace(char *str) {
}
}
dds_retcode_t
dds_return_t
ddsrt_strtod(const char *nptr, char **endptr, double *dblptr)
{
double dbl;
int orig_errno;
dds_retcode_t ret = DDS_RETCODE_OK;
dds_return_t ret = DDS_RETCODE_OK;
assert(nptr != NULL);
assert(dblptr != NULL);
@ -161,7 +161,7 @@ ddsrt_strtod(const char *nptr, char **endptr, double *dblptr)
return ret;
}
dds_retcode_t
dds_return_t
ddsrt_strtof(const char *nptr, char **endptr, float *fltptr)
{
/* Just use os_strtod(). */
@ -169,7 +169,7 @@ ddsrt_strtof(const char *nptr, char **endptr, float *fltptr)
point number is definitely not a double-precision floating point
number. */
double dbl = 0.0;
dds_retcode_t ret;
dds_return_t ret;
assert(nptr != NULL);
assert(fltptr != NULL);

View file

@ -16,7 +16,7 @@
#include "dds/ddsrt/strtol.h"
int ddsrt_todigit(const int chr)
static int ddsrt_todigit(const int chr)
{
if (chr >= '0' && chr <= '9') {
return chr - '0';
@ -29,7 +29,7 @@ int ddsrt_todigit(const int chr)
return -1;
}
static dds_retcode_t
static dds_return_t
ullfstr(
const char *str,
char **endptr,
@ -37,7 +37,7 @@ ullfstr(
unsigned long long *ullng,
unsigned long long max)
{
dds_retcode_t rc = DDS_RETCODE_OK;
dds_return_t rc = DDS_RETCODE_OK;
int num;
size_t cnt = 0;
unsigned long long tot = 0;
@ -86,14 +86,14 @@ ullfstr(
return rc;
}
dds_retcode_t
dds_return_t
ddsrt_strtoll(
const char *str,
char **endptr,
int32_t base,
long long *llng)
{
dds_retcode_t rc = DDS_RETCODE_OK;
dds_return_t rc = DDS_RETCODE_OK;
size_t cnt = 0;
long long tot = 1;
unsigned long long ullng = 0, max = INT64_MAX;
@ -122,14 +122,14 @@ ddsrt_strtoll(
return rc;
}
dds_retcode_t
dds_return_t
ddsrt_strtoull(
const char *str,
char **endptr,
int32_t base,
unsigned long long *ullng)
{
dds_retcode_t rc = DDS_RETCODE_OK;
dds_return_t rc = DDS_RETCODE_OK;
size_t cnt = 0;
unsigned long long tot = 1;
unsigned long long max = UINT64_MAX;
@ -157,7 +157,7 @@ ddsrt_strtoull(
return rc;
}
dds_retcode_t
dds_return_t
ddsrt_atoll(
const char *str,
long long *llng)
@ -165,7 +165,7 @@ ddsrt_atoll(
return ddsrt_strtoll(str, NULL, 10, llng);
}
dds_retcode_t
dds_return_t
ddsrt_atoull(
const char *str,
unsigned long long *ullng)

View file

@ -0,0 +1,467 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <FreeRTOS.h>
#include <task.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/timeconv.h"
void ddsrt_mutex_init(ddsrt_mutex_t *mutex)
{
SemaphoreHandle_t sem;
assert(mutex != NULL);
if ((sem = xSemaphoreCreateMutex()) == NULL) {
abort();
}
(void)memset(mutex, 0, sizeof(*mutex));
mutex->sem = sem;
}
void ddsrt_mutex_destroy(ddsrt_mutex_t *mutex)
{
assert(mutex != NULL);
vSemaphoreDelete(mutex->sem);
(void)memset(mutex, 0, sizeof(*mutex));
}
static bool
mutex_lock(ddsrt_mutex_t *mutex, int blk)
{
assert(mutex != NULL);
if (xSemaphoreTake(mutex->sem, (blk == 1 ? portMAX_DELAY : 0)) != pdPASS) {
/* xSemaphoreTake will only return pdFAIL on timeout. The wait will be
indefinite if INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h
and portMAX_DELAY was passed. */
assert(blk == 0);
return false;
}
return true;
}
void ddsrt_mutex_lock(ddsrt_mutex_t *mutex)
{
if (!mutex_lock(mutex, 1)) {
DDS_FATAL("Failed to lock 0x%p", mutex);
}
}
bool ddsrt_mutex_trylock(ddsrt_mutex_t *mutex)
{
return mutex_lock(mutex, 0);
}
void ddsrt_mutex_unlock(ddsrt_mutex_t *mutex)
{
assert(mutex != NULL);
if (xSemaphoreGive(mutex->sem) != pdPASS) {
DDS_FATAL("Failed to unlock 0x%p", mutex->sem);
}
}
static dds_return_t
cond_timedwait(
ddsrt_cond_t *cond,
ddsrt_mutex_t *mutex,
dds_duration_t reltime)
{
dds_return_t rc = DDS_RETCODE_OK;
dds_time_t abstime;
TaskHandle_t task;
TickType_t ticks = 0;
assert(cond != NULL);
assert(mutex != NULL);
abstime = ddsrt_time_add_duration(dds_time(), reltime);
ticks = ddsrt_duration_to_ticks_ceil(reltime);
xSemaphoreTake(cond->sem, portMAX_DELAY);
ddsrt_mutex_unlock(mutex);
task = xTaskGetCurrentTaskHandle();
/* Register current task with condition. */
ddsrt_tasklist_push(&cond->tasks, task);
/* Discard pending notifications. */
ulTaskNotifyTake(1, 0);
xSemaphoreGive(cond->sem);
/* Wait to be notified. */
switch (ulTaskNotifyTake(1, ticks)) {
case 0:
xSemaphoreTake(cond->sem, ticks);
ddsrt_tasklist_pop(&cond->tasks, task);
xSemaphoreGive(cond->sem);
break;
default:
/* Task already removed from condition. */
break;
}
/* Timeout must only be returned if the time has actually passed. */
if (dds_time() >= abstime) {
rc = DDS_RETCODE_TIMEOUT;
}
ddsrt_mutex_lock(mutex);
return rc;
}
void ddsrt_cond_init(ddsrt_cond_t *cond)
{
SemaphoreHandle_t sem;
ddsrt_tasklist_t tasks;
assert(cond != NULL);
if (ddsrt_tasklist_init(&tasks) == -1) {
abort();
}
if ((sem = xSemaphoreCreateMutex()) == NULL) {
ddsrt_tasklist_fini(&tasks);
abort();
}
(void)memset(cond, 0, sizeof(*cond));
cond->sem = sem;
cond->tasks = tasks;
}
void ddsrt_cond_destroy(ddsrt_cond_t *cond)
{
assert(cond != NULL);
vSemaphoreDelete(cond->sem);
ddsrt_tasklist_fini(&cond->tasks);
(void)memset(cond, 0, sizeof(*cond));
}
void ddsrt_cond_wait(ddsrt_cond_t *cond, ddsrt_mutex_t *mutex)
{
assert(cond != NULL);
assert(mutex != NULL);
(void)cond_timedwait(cond, mutex, DDS_INFINITY);
}
bool
ddsrt_cond_waitfor(
ddsrt_cond_t *cond,
ddsrt_mutex_t *mutex,
dds_duration_t reltime)
{
dds_return_t rc;
assert(cond != NULL);
assert(mutex != NULL);
switch ((rc = cond_timedwait(cond, mutex, reltime))) {
case DDS_RETCODE_OUT_OF_RESOURCES:
abort();
case DDS_RETCODE_TIMEOUT:
return false;
default:
assert(rc == DDS_RETCODE_OK);
break;
}
return true;
}
bool
ddsrt_cond_waituntil(
ddsrt_cond_t *cond,
ddsrt_mutex_t *mutex,
dds_time_t abstime)
{
dds_return_t rc;
dds_time_t time;
dds_duration_t reltime;
assert(cond != NULL);
assert(mutex != NULL);
time = dds_time();
reltime = (abstime > time ? abstime - time : 0);
switch ((rc = cond_timedwait(cond, mutex, reltime))) {
case DDS_RETCODE_OUT_OF_RESOURCES:
abort();
case DDS_RETCODE_TIMEOUT:
return false;
default:
assert(rc == DDS_RETCODE_OK);
break;
}
return true;
}
void ddsrt_cond_signal(ddsrt_cond_t *cond)
{
TaskHandle_t task;
assert(cond != NULL);
xSemaphoreTake(cond->sem, portMAX_DELAY);
if ((task = ddsrt_tasklist_pop(&cond->tasks, NULL)) != NULL) {
xTaskNotifyGive(task);
}
xSemaphoreGive(cond->sem);
}
void ddsrt_cond_broadcast(ddsrt_cond_t *cond)
{
TaskHandle_t task;
assert(cond != NULL);
xSemaphoreTake(cond->sem, portMAX_DELAY);
while ((task = ddsrt_tasklist_pop(&cond->tasks, NULL)) != NULL) {
xTaskNotifyGive(task);
}
xSemaphoreGive(cond->sem);
}
#define WRITE_LOCKED (-1)
#define UNLOCKED (0)
#define READ_LOCKED (1)
void ddsrt_rwlock_init(ddsrt_rwlock_t *rwlock)
{
SemaphoreHandle_t sem;
ddsrt_tasklist_t tasks;
assert(rwlock != NULL);
if (ddsrt_tasklist_init(&tasks) == -1) {
abort();
}
if ((sem = xSemaphoreCreateMutex()) == NULL) {
ddsrt_tasklist_fini(&tasks);
abort();
}
memset(rwlock, 0, sizeof(*rwlock));
rwlock->sem = sem;
rwlock->tasks = tasks;
rwlock->state = UNLOCKED;
}
void ddsrt_rwlock_destroy(ddsrt_rwlock_t *rwlock)
{
assert(rwlock != NULL);
vSemaphoreDelete(rwlock->sem);
ddsrt_tasklist_fini(&rwlock->tasks);
memset(rwlock, 0, sizeof(*rwlock));
}
void ddsrt_rwlock_read(ddsrt_rwlock_t *rwlock)
{
TaskHandle_t task = xTaskGetCurrentTaskHandle();
assert(rwlock != NULL);
xSemaphoreTake(rwlock->sem, portMAX_DELAY);
rwlock->rdcnt++;
if (rwlock->wrcnt != 0) {
ddsrt_tasklist_push(&rwlock->tasks, task);
/* Discard pending notifications. */
ulTaskNotifyTake(1, 0);
xSemaphoreGive(rwlock->sem);
/* Wait to be notified. */
ulTaskNotifyTake(1, portMAX_DELAY);
xSemaphoreTake(rwlock->sem, portMAX_DELAY);
ddsrt_tasklist_pop(&rwlock->tasks, task);
}
assert(rwlock->state == UNLOCKED ||
rwlock->state == READ_LOCKED);
rwlock->cnt++;
rwlock->state = READ_LOCKED;
/* Notify next task, if any. */
if ((task = ddsrt_tasklist_peek(&rwlock->tasks, NULL)) != NULL) {
xTaskNotifyGive(task);
}
xSemaphoreGive(rwlock->sem);
}
void ddsrt_rwlock_write(ddsrt_rwlock_t *rwlock)
{
TaskHandle_t task = xTaskGetCurrentTaskHandle();
assert(rwlock != NULL);
xSemaphoreTake(rwlock->sem, portMAX_DELAY);
rwlock->wrcnt++;
if (rwlock->rdcnt != 0 || rwlock->wrcnt != 1) {
ddsrt_tasklist_push(&rwlock->tasks, task);
do {
/* Discard pending notifications. */
ulTaskNotifyTake(1, 0);
xSemaphoreGive(rwlock->sem);
/* Wait to be notified. */
ulTaskNotifyTake(1, portMAX_DELAY);
xSemaphoreTake(rwlock->sem, portMAX_DELAY);
} while (rwlock->state != UNLOCKED);
ddsrt_tasklist_pop(&rwlock->tasks, task);
}
assert(rwlock->cnt == 0);
assert(rwlock->state == UNLOCKED);
rwlock->cnt++;
rwlock->state = WRITE_LOCKED;
xSemaphoreGive(rwlock->sem);
}
bool ddsrt_rwlock_tryread(ddsrt_rwlock_t *rwlock)
{
bool locked = false;
TaskHandle_t task;
assert(rwlock != NULL);
xSemaphoreTake(rwlock->sem, portMAX_DELAY);
if (rwlock->wrcnt == 0) {
locked = true;
rwlock->cnt++;
rwlock->rdcnt++;
rwlock->state = READ_LOCKED;
/* Notify next task, if any. */
if ((task = ddsrt_tasklist_peek(&rwlock->tasks, NULL)) != NULL) {
xTaskNotifyGive(task);
}
}
xSemaphoreGive(rwlock->sem);
return locked;
}
bool ddsrt_rwlock_trywrite(ddsrt_rwlock_t *rwlock)
{
bool locked = false;
assert(rwlock != NULL);
xSemaphoreTake(rwlock->sem, 0);
if (rwlock->rdcnt == 0 && rwlock->wrcnt == 0) {
locked = true;
rwlock->cnt++;
rwlock->wrcnt++;
rwlock->state = WRITE_LOCKED;
}
xSemaphoreGive(rwlock->sem);
return locked;
}
void ddsrt_rwlock_unlock(ddsrt_rwlock_t *rwlock)
{
TaskHandle_t task;
assert(rwlock != NULL);
xSemaphoreTake(rwlock->sem, portMAX_DELAY);
assert(rwlock->cnt != 0);
rwlock->cnt--;
if (rwlock->state == READ_LOCKED) {
assert(rwlock->rdcnt != 0);
rwlock->rdcnt--;
if (rwlock->rdcnt == 0) {
rwlock->state = UNLOCKED;
}
} else {
assert(rwlock->state == WRITE_LOCKED);
assert(rwlock->wrcnt != 0);
assert(rwlock->cnt == 0);
rwlock->wrcnt--;
rwlock->state = UNLOCKED;
}
/* Notify next task, if any. */
if ((rwlock->state == UNLOCKED) &&
(task = ddsrt_tasklist_peek(&rwlock->tasks, NULL)) != NULL)
{
assert(rwlock->rdcnt != 0 ||
rwlock->wrcnt != 0);
xTaskNotifyGive(task);
}
xSemaphoreGive(rwlock->sem);
}
#define ONCE_NOT_STARTED (1<<0)
#define ONCE_IN_PROGRESS (1<<1)
#define ONCE_FINISHED (1<<2)
/* Wait one millisecond (tick) between polls. */
static const TickType_t once_delay = (configTICK_RATE_HZ / 1000);
void
ddsrt_once(
ddsrt_once_t *control,
ddsrt_once_fn init_fn)
{
int ret, brk = 0;
uint32_t stat;
while (brk == 0) {
stat = ddsrt_atomic_ld32(control);
/* Verify once control was initialized properly. */
assert(stat == ONCE_NOT_STARTED ||
stat == ONCE_IN_PROGRESS ||
stat == ONCE_FINISHED);
if ((stat & ONCE_FINISHED) != 0) {
/* The initialization function has been executed. No reason to block
execution of this thread. Continue. */
brk = 1;
} else if ((stat & ONCE_IN_PROGRESS) != 0) {
/* Another thread is executing the initialization function. Wait around
for it to be finished. The polling loop is required because FreeRTOS
does not offer futexes. */
vTaskDelay(once_delay);
/* Repeat. */
} else {
/* No thread was executing the initialization function (one might be
executing it now) at the time of the load. If the atomic compare and
swap operation is successful, this thread will run the initialization
function. */
if (ddsrt_atomic_cas32(
control, ONCE_NOT_STARTED, ONCE_IN_PROGRESS) != 0)
{
/* Function must never block or yield, see reference manual. */
init_fn();
ret = (0 == ddsrt_atomic_cas32(
control, ONCE_IN_PROGRESS, ONCE_FINISHED));
assert(ret == 0); (void)ret;
brk = 1;
} else {
/* Another thread updated the state first. Repeat. */
}
}
}
return;
}

View file

@ -0,0 +1,396 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/sync.h"
/* Task list is a buffer used to keep track of blocked tasks. The buffer is
cyclic to avoid memory (re)allocation as much as possible. To avoid memory
relocation, the window is allowed to be sparse too.
Active buckets must always reside in the window denoted by the first active
bucket and the last active bucket.
A buffer with 10 buckets will be neatly packed at first.
X : Used bucket in window.
o : Empty (invalidated) bucket.
-----------------------
| X X X X X o o o o o | length: 10, count: 5
--^-------^------------
1st nth
As soon as the first task is unblocked.
-----------------------
| o X X X X o o o o o | length: 10, count: 4
----^-----^------------
1st nth
After a while the window will wrap around.
-----------------------
| X X X o o o o o X X | length: 10, count: 5
------^-----------^----
nth 1st
When a task is popped, e.g. a task was not notified in due time.
-----------------------
| o X X o X X o o o o | length: 10, count: 4
----^-------^----------
1st nth
*/
#ifndef NDEBUG
static void tasklist_assert(ddsrt_tasklist_t *list)
{
size_t i;
assert(list != NULL);
if (list->cnt == 0) {
assert(list->off == 0);
assert(list->end == 0);
assert(list->len == DDSRT_TASKLIST_INITIAL);
for (i = 0; i < list->len; i++) {
assert(list->tasks[i] == NULL);
}
}
/* FIXME: add more checks */
}
#else
#define tasklist_assert(...)
#endif /* NDEBUG */
int ddsrt_tasklist_init(ddsrt_tasklist_t *list)
{
TaskHandle_t *p;
assert(list != NULL);
p = ddsrt_malloc(DDSRT_TASKLIST_INITIAL * sizeof(*list->tasks));
if (p == NULL) {
return -1;
}
memset(list, 0, sizeof(*list));
memset(p, 0, DDSRT_TASKLIST_INITIAL * sizeof(*list->tasks));
list->tasks = p;
list->len = DDSRT_TASKLIST_INITIAL;
return 0;
}
void ddsrt_tasklist_fini(ddsrt_tasklist_t *list)
{
ddsrt_free(list->tasks);
memset(list, 0, sizeof(*list));
}
void ddsrt_tasklist_ltrim(ddsrt_tasklist_t *list)
{
size_t i;
assert(list != NULL);
assert(list->cnt != 0);
i = list->off;
for (; i < list->len - 1 && list->tasks[i] == NULL; i++) { }
/* Take into account wrap around. */
if (list->tasks[i] == NULL) {
assert(i == list->len - 1);
assert(list->off > list->end);
i = 0;
/* Trim invalidated buckets from head. */
for (; i < list->len - 1 && list->tasks[i] == NULL; i++) { }
}
list->off = i;
}
void ddsrt_tasklist_rtrim(ddsrt_tasklist_t *list)
{
size_t i;
assert(list != NULL);
assert(list->cnt != 0);
i = list->end;
for (; i > 0 && list->tasks[i] == NULL; i--) { }
/* Take into account wrap around. */
if (list->tasks[i] == NULL) {
assert(i == 0);
assert(list->off > list->end);
i = list->len - 1;
/* Trim invalidated buckets from tail. */
for (; i > 0 && list->tasks[i] == NULL; i--) { }
}
list->end = i;
}
void ddsrt_tasklist_pack(ddsrt_tasklist_t *list)
{
size_t i, j;
/* Pack operation is trickier on wrap around. */
if (list->end < list->off) {
/* Compress tail.
*
* ------------------------- -----------------------
* | c . d . e | . a . b . | >> | c d e . . | . a . b |
* ------------------------- -----------------------
*/
for (i = j = 0; i <= list->end; i++) {
if (list->tasks[i] != NULL) {
if (i != j) {
list->tasks[j] = list->tasks[i];
}
j++;
}
}
assert(j != 0);
list->end = (j == 0 ? 0 : j - 1);
/* Compress head.
*
* ------------------------- -------------------------
* | c d e . . | . a . b . | >> | c d e . . | . . . a b |
* ------------------------- -------------------------
*/
for (i = j = list->len - 1; i >= list->off; i--) {
if (list->tasks[i] != NULL) {
if (i != j) {
list->tasks[j] = list->tasks[i];
}
j--;
}
}
assert(j != list->len - 1);
list->off = (j == list->len - 1 ? list->len - 1 : j + 1);
} else {
/* Compress.
*
* ------------------------- --------------------------
* | . . a . . | b . c d e | >> | a b c d e | . . . . . |
* ------------------------- --------------------------
*/
for (i = list->off, j = 0; i <= list->end; i++) {
if (list->tasks[i] != NULL) {
if (i != j) {
list->tasks[j] = list->tasks[i];
}
j++;
}
}
assert(j != 0);
list->off = 0;
list->end = j - 1;
assert(list->end == list->cnt - 1);
}
}
int ddsrt_tasklist_shrink(ddsrt_tasklist_t *list)
{
static const size_t x = DDSRT_TASKLIST_CHUNK;
TaskHandle_t *p;
size_t mv = 0, n;
assert(list != NULL);
/* Shrink by one chunk too, but only if the difference is at least two
chunks to avoid memory (re)allocation if a task is pushed and popped
just over the boundary. */
if (list->cnt > (list->len - (x * 2)) || (list->len - x) < DDSRT_TASKLIST_INITIAL)
{
return 0;
}
/* List can be sparse. Pack to ensure list can be compacted. */
ddsrt_tasklist_pack(list);
/* Pack operation moved head to end of buffer on wrap around. Move head back
to not discard it on reallocation. */
if (list->off != 0) {
assert(list->end < list->off);
mv = (list->len - list->off) * sizeof(*p);
memmove(list->tasks + (list->off - x), list->tasks + list->off, mv);
list->off -= x;
}
n = list->len - x;
if ((p = ddsrt_realloc(list->tasks, n * sizeof(*p))) == NULL) {
/* Move head back to end of buffer. */
if (mv != 0) {
memmove(list->tasks + (list->off + x), list->tasks + list->off, mv);
list->off += x;
}
return -1;
}
list->tasks = p;
list->len = n;
return 0;
}
int ddsrt_tasklist_grow(ddsrt_tasklist_t *list)
{
static const size_t x = DDSRT_TASKLIST_CHUNK;
TaskHandle_t *p;
size_t n;
assert(list != NULL);
/* Should not be called if room is available. */
assert(list->cnt == list->len);
n = list->len + x;
if ((p = ddsrt_realloc(list->tasks, n * sizeof(*p))) == NULL) {
return -1;
}
/* Move head to end of newly allocated memory. */
if (list->off != 0) {
assert(list->end < list->off);
memmove(p + (list->off + x), p + list->off, (list->len - list->off) * sizeof(*p));
list->off += x;
}
/* Zero newly allocated memory. */
memset(p + (list->end + 1), 0, x * sizeof(*p));
list->tasks = p;
list->len = n;
return 0;
}
ssize_t ddsrt_tasklist_find(ddsrt_tasklist_t *list, TaskHandle_t task)
{
size_t i, n;
assert(task != NULL);
/* No need to check if list is empty. */
if (list->cnt != 0) {
/* Task list is circular, so window does not have to be consecutive. */
n = list->off <= list->end ? list->end : list->len - 1;
for (i = list->off; i <= n; i++) {
if (list->tasks[i] == task)
return (ssize_t)i;
}
if (list->off > list->end) {
n = list->end;
for (i = 0; i <= n; i++) {
if (list->tasks[i] == task)
return (ssize_t)i;
}
}
}
return -1;
}
TaskHandle_t ddsrt_tasklist_peek(ddsrt_tasklist_t *list, TaskHandle_t task)
{
tasklist_assert(list);
if (list->cnt == 0) {
return NULL;
} else if (task != NULL) {
return ddsrt_tasklist_find(list, task) == -1 ? NULL : task;
}
return list->tasks[list->off];
}
TaskHandle_t ddsrt_tasklist_pop(ddsrt_tasklist_t *list, TaskHandle_t task)
{
ssize_t i;
tasklist_assert(list);
if (list->cnt == 0) {
return NULL;
} else if (task == NULL) {
i = (ssize_t)list->off;
} else if ((i = ddsrt_tasklist_find(list, task)) == -1) {
return NULL;
}
task = list->tasks[i];
if (task != NULL) {
/* Invalidate bucket. */
list->tasks[i] = NULL;
list->cnt--;
if (list->cnt == 0) {
list->off = list->end = 0;
} else if (i == (ssize_t)list->end) {
/* Trim invalidated buckets from tail of window. */
ddsrt_tasklist_rtrim(list);
} else if (i == (ssize_t)list->off) {
/* Trim invalidated buckets from head of window. */
ddsrt_tasklist_ltrim(list);
} else {
/* Window is now sparse. */
}
if (list->cnt <= (list->len - DDSRT_TASKLIST_CHUNK*2)) {
/* Shrink operation failure can safely be ignored. */
(void)ddsrt_tasklist_shrink(list);
}
}
return task;
}
int ddsrt_tasklist_push(ddsrt_tasklist_t *list, TaskHandle_t task)
{
tasklist_assert(list);
assert(task != NULL);
/* Ensure task is not listed. */
if (ddsrt_tasklist_find(list, task) != -1) {
return 0;
}
/* Grow number of buckets if none are available. */
if (list->cnt == list->len) {
if (ddsrt_tasklist_grow(list) == -1) {
return -1;
}
list->end++;
/* Wrap around if there is room at the head. */
} else if (list->end == list->len - 1 && list->off != 0) {
list->end = 0;
} else {
/* List can be sparse. */
if (list->end == list->len - 1 || list->end + 1 == list->off) {
ddsrt_tasklist_pack(list);
}
/* Room is guaranteed to be available at the tail. */
list->end += (list->cnt > 0);
}
list->tasks[list->end] = task;
list->cnt++;
return 0;
}

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_mutex_init(&rwlock->rwlock, NULL)) != 0)
abort();
}
void
ddsrt_rwlock_destroy (ddsrt_rwlock_t *rwlock)
{
int err;
assert(rwlock != NULL);
if ((err = pthread_mutex_destroy (&rwlock->rwlock)) != 0)
abort();
}
void ddsrt_rwlock_read (ddsrt_rwlock_t *rwlock)
{
int err;
assert(rwlock != NULL);
err = pthread_mutex_lock(&rwlock->rwlock);
assert(err == 0);
(void)err;
}
void ddsrt_rwlock_write (ddsrt_rwlock_t *rwlock)
{
int err;
assert(rwlock != NULL);
err = pthread_mutex_lock (&rwlock->rwlock);
assert(err == 0);
(void)err;
}
bool ddsrt_rwlock_tryread (ddsrt_rwlock_t *rwlock)
{
int err;
assert(rwlock != NULL);
err = pthread_mutex_trylock(&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_mutex_trylock(&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_mutex_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

@ -88,13 +88,13 @@ static uint32_t ddsrt_thread_start_fn (void * arg)
return 0;
}
static dds_retcode_t ddsrt_thread_pool_new_thread (ddsrt_thread_pool pool)
static dds_return_t ddsrt_thread_pool_new_thread (ddsrt_thread_pool pool)
{
static unsigned char pools = 0; /* Pool counter - TODO make atomic */
char name [64];
ddsrt_thread_t id;
dds_retcode_t res;
dds_return_t res;
(void) snprintf (name, sizeof (name), "OSPL-%u-%u", pools++, pool->m_count++);
res = ddsrt_thread_create (&id, name, &pool->m_attr, &ddsrt_thread_start_fn, pool);
@ -205,9 +205,9 @@ void ddsrt_thread_pool_free (ddsrt_thread_pool pool)
ddsrt_free (pool);
}
dds_retcode_t ddsrt_thread_pool_submit (ddsrt_thread_pool pool, void (*fn) (void *arg), void * arg)
dds_return_t ddsrt_thread_pool_submit (ddsrt_thread_pool pool, void (*fn) (void *arg), void * arg)
{
dds_retcode_t res = DDS_RETCODE_OK;
dds_return_t res = DDS_RETCODE_OK;
ddsi_work_queue_job_t job;
ddsrt_mutex_lock (&pool->m_mutex);

View file

@ -0,0 +1,545 @@
/*
* 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 <FreeRTOS.h>
#include <task.h>
#include <string.h>
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/retcode.h"
#include "dds/ddsrt/string.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/threads_priv.h"
typedef enum {
THREAD_STARTING = 0,
THREAD_RUNNING,
THREAD_EXITING /* Indicates the thread has returned from the specified
start_routine, but FreeRTOS may not report it as deleted
yet. */
} thread_state_t;
typedef struct {
ddsrt_thread_routine_t func;
void *arg;
TaskHandle_t task; /* Thread identifier for looking up thread context from
another thread. Read-only, read by other threads. */
thread_state_t stat;
thread_cleanup_t *dtors; /* Cleanup routines. Private. */
uint32_t ret; /* Return value. NULL if thread has not terminated, maybe
NULL if thread has terminated, read by other thread(s)
after termination. */
TaskHandle_t blkd; /* Thread blocked until thread terminates. may or may
not be empty when thread terminates. Written by other
thread, protected by registry mutex. */
} thread_context_t;
/* Thread registry (in combination with thread context) is required to properly
implement thread join functionality. */
/* Threads have their own context. The context is automatically allocated and
initialized, either when the thread is created (local threads) or when the
API is first used. */
/* FIXME: The same mechanism more-or-less exists in DDSI, perhaps more of the
logic in DDSI can be moved down at some point? */
typedef struct {
ddsrt_mutex_t mutex;
/* The number of available spaces in the thread context array does not have
to equal the number of used spaces. e.g. when a memory allocation for a
new thread context array fails when destroying a context it is better to
leave one space unused. */
thread_context_t **ctxs;
size_t cnt;
size_t len;
} thread_registry_t;
static ddsrt_thread_local thread_context_t *thread_context = NULL;
static thread_registry_t thread_registry;
static ddsrt_once_t thread_registry_once = DDSRT_ONCE_INIT;
static uint32_t non_local_thread(void *arg) { (void)arg; return 0;}
/* FreeRTOS documentation states vTaskGetInfo is intended for debugging because
its use results in the scheduler remaining suspended for an extended period,
but the scheduler is only suspended if eTaskState is not eInvalid. */
ddsrt_tid_t
ddsrt_gettid(void)
{
TaskStatus_t status;
vTaskGetInfo(xTaskGetCurrentTaskHandle(), &status, pdFALSE, eInvalid);
return status.xTaskNumber;
}
ddsrt_thread_t
ddsrt_thread_self(void)
{
ddsrt_thread_t thr = { .task = xTaskGetCurrentTaskHandle() };
return thr;
}
bool ddsrt_thread_equal(ddsrt_thread_t a, ddsrt_thread_t b)
{
return (a.task == b.task);
}
size_t
ddsrt_thread_getname(char *__restrict name, size_t size)
{
char *ptr;
assert(name != NULL);
assert(size >= 1);
if ((ptr = pcTaskGetName(NULL)) == NULL) {
ptr = "";
}
return ddsrt_strlcpy(name, ptr, size);
}
static void
thread_registry_init(void)
{
/* One time initialization guaranteed by ddsrt_once. */
(void)memset(&thread_registry, 0, sizeof(thread_registry));
ddsrt_mutex_init(&thread_registry.mutex);
}
static thread_context_t *
thread_context_find(TaskHandle_t task)
{
thread_context_t *ctx = NULL;
for (size_t i = 0; i < thread_registry.cnt && ctx == NULL; i++) {
if (thread_registry.ctxs[i] != NULL &&
thread_registry.ctxs[i]->task == task)
{
ctx = thread_registry.ctxs[i];
}
}
return ctx;
}
static dds_return_t
thread_context_create(thread_context_t **ctxptr)
{
dds_return_t rc = DDS_RETCODE_OK;
size_t len;
thread_context_t *ctx = NULL, **ctxs = NULL;
assert(ctxptr != NULL);
ctx = ddsrt_calloc(1, sizeof(*ctx));
if (ctx == NULL) {
rc = DDS_RETCODE_OUT_OF_RESOURCES;
} else {
if (thread_registry.cnt < thread_registry.len) {
len = thread_registry.len;
ctxs = thread_registry.ctxs;
} else {
assert(thread_registry.cnt == thread_registry.len);
len = thread_registry.len + 1;
ctxs = ddsrt_realloc(thread_registry.ctxs, len * sizeof(ctx));
}
if (ctxs == NULL) {
ddsrt_free(ctx);
rc = DDS_RETCODE_OUT_OF_RESOURCES;
} else {
ctxs[thread_registry.cnt++] = *ctxptr = ctx;
thread_registry.len = len;
thread_registry.ctxs = ctxs;
}
}
return rc;
}
#define thread_context_require() thread_context_acquire(NULL)
static dds_return_t
thread_context_acquire(thread_context_t **ctxptr)
{
dds_return_t rc = DDS_RETCODE_OK;
thread_context_t *ctx = thread_context;
if (ctx == NULL) {
/* Dynamically initialize global thread registry (exactly once). */
ddsrt_once(&thread_registry_once, &thread_registry_init);
ddsrt_mutex_lock(&thread_registry.mutex);
if ((rc = thread_context_create(&ctx)) == 0) {
/* This situation only arises for non-native (not created in our code)
threads. Some members must therefore still be initialized to ensure
proper operation. */
ctx->func = &non_local_thread;
ctx->stat = THREAD_RUNNING;
ctx->task = xTaskGetCurrentTaskHandle();
}
ddsrt_mutex_unlock(&thread_registry.mutex);
thread_context = ctx;
} else {
assert(ctx->func != NULL);
assert(ctx->stat == THREAD_RUNNING);
assert(ctx->task == xTaskGetCurrentTaskHandle());
}
if (rc == DDS_RETCODE_OK && ctxptr != NULL) {
assert(ctx != NULL);
*ctxptr = ctx;
}
return rc;
}
static void
thread_context_destroy(thread_context_t *ctx)
{
size_t i = 0;
thread_context_t **arr;
if (ctx != NULL) {
while (i < thread_registry.cnt && thread_registry.ctxs[i] != ctx) {
i++;
}
if (i < thread_registry.cnt) {
thread_registry.ctxs[i] = NULL;
if (i < (thread_registry.cnt - 1)) {
(void)memmove(
thread_registry.ctxs + (i),
thread_registry.ctxs + (i+1),
(thread_registry.cnt - (i+1)) * sizeof(*thread_registry.ctxs));
}
thread_registry.cnt--;
/* Free contexts when count reaches zero. */
if (thread_registry.cnt == 0) {
ddsrt_free(thread_registry.ctxs);
thread_registry.ctxs = NULL;
thread_registry.len = 0;
} else {
arr = ddsrt_realloc(
thread_registry.ctxs,
thread_registry.cnt * sizeof(*thread_registry.ctxs));
/* Ignore allocation failure, save free spot. */
if (arr != NULL) {
thread_registry.ctxs = arr;
thread_registry.len = thread_registry.cnt;
}
}
}
ddsrt_free(ctx);
}
}
static void
thread_fini(thread_context_t *ctx, uint32_t ret)
{
thread_cleanup_t *tail;
assert(ctx != NULL);
/* Acquire registry lock to publish task result and state. */
ddsrt_mutex_lock(&thread_registry.mutex);
/* Pop all cleanup handlers from the thread's cleanup stack. */
while ((tail = ctx->dtors) != NULL) {
ctx->dtors = tail->prev;
if (tail->routine != 0) {
tail->routine(tail->arg);
}
ddsrt_free(tail);
}
/* FreeRTOS can report task state, but doesn't register the result or
notifies a thread that wants to join. */
ctx->ret = ret;
ctx->stat = THREAD_EXITING;
/* Thread resources will be leaked (especially for non-local threads)
if not reclaimed by a thread join. Local threads (threads created
within the DDS stack) are required to be joined. Thread resource
leakage for local threads must be considered a bug. Non-local
threads, however, are not aware that there are resources that must
be reclaimed and local threads might not be aware that there are
non-local threads that must be joined. Therefore, if a non-local thread
exits, it's resources are reclaimed if no thread is waiting to join. */
if (ctx->blkd != NULL) {
/* Task join functionality is based on notifications, as it is
significantly faster than using a queue, semaphore or event group to
perform an equivalent operation.
When a task receives a notification, it's notification state is set to
pending. When it reads it's notification state, the notification state
is set to not-pending. A task can wait, with an optional time out, for
it's notification state to become pending. */
/* Ignore result, there's nothing that can be done on failure and it always
returns pdPASS. */
(void)xTaskNotifyGive(ctx->blkd);
} else if (ctx->func == &non_local_thread) {
assert(ret == 0);
thread_context_destroy(ctx);
}
ddsrt_mutex_unlock(&thread_registry.mutex);
}
static void
thread_start_routine(void *arg)
{
thread_context_t *ctx = (thread_context_t *)arg;
uint32_t ret;
ddsrt_mutex_lock(&thread_registry.mutex);
/* Context for the current task is always correctly initialized and
registered at this stage. It's not strictly required to update task
state, but the synchronization itself is. */
ctx->stat = THREAD_RUNNING;
ddsrt_mutex_unlock(&thread_registry.mutex);
/* Thread-local storage is initialized by the function that creates the
thread because a reference to the thread's context is stored and
synchronization is considerably easier if it's handled there. */
thread_context = ctx;
ret = ctx->func(ctx->arg);
thread_fini(ctx, ret); /* DO NOT DEREFERENCE THREAD CONTEXT ANYMORE! */
/* Delete current task. */
vTaskDelete(NULL);
}
/* xTaskCreate takes the stack depth in the number of words (NOT bytes). In
practice this simply means it multiplies the given number with the size
of StackType_t in bytes (see tasks.c). FreeRTOSConfig.h must define
configMINIMAL_STACK_SIZE, which is the stack size in words allocated for
the idle task. */
#define WORD_SIZE (sizeof(StackType_t))
/* configMINIMAL_STACK_SIZE is applied as the default stack size. Whether or
not this is considered a sane default depends on the target. The default can
be adjusted in FreeRTOSConfig.h Of course the configuration file also allows
the user to change it on a per-thread basis at runtime. */
#define MIN_STACK_SIZE ((uint16_t)(configMINIMAL_STACK_SIZE * WORD_SIZE))
dds_return_t
ddsrt_thread_create(
ddsrt_thread_t *thread,
const char *name,
const ddsrt_threadattr_t *attr,
ddsrt_thread_routine_t start_routine,
void *arg)
{
dds_return_t rc;
TaskHandle_t task;
UBaseType_t prio;
uint16_t size = MIN_STACK_SIZE;
thread_context_t *ctx = NULL;
assert(thread != NULL);
assert(name != NULL);
assert(attr != NULL);
assert(start_routine != 0);
if ((rc = thread_context_require()) != DDS_RETCODE_OK) {
return rc;
}
/* Non-realtime scheduling does not exist in FreeRTOS. */
if (attr->schedClass != DDSRT_SCHED_DEFAULT &&
attr->schedClass != DDSRT_SCHED_REALTIME)
{
return DDS_RETCODE_BAD_PARAMETER;
} else if (attr->schedPriority < 0 ||
attr->schedPriority > (configMAX_PRIORITIES - 1))
{
return DDS_RETCODE_BAD_PARAMETER;
}
/* Stack size is quietly increased to match at least the minimum. */
if (attr->stackSize > size) {
size = (uint16_t)(attr->stackSize / WORD_SIZE);
if (attr->stackSize % WORD_SIZE) {
size++;
}
}
/* Assume that when the default priority of zero (0) is specified, the user
wants the thread to inherit the priority of the calling thread. */
assert(0 == tskIDLE_PRIORITY);
if (attr->schedPriority == 0) {
prio = uxTaskPriorityGet(NULL);
} else {
prio = (UBaseType_t)attr->schedPriority;
}
ddsrt_mutex_lock(&thread_registry.mutex);
/* Thread context is allocated here so that it can be handled when no more
memory is available. Simply storing the entire context in thread-local
storage would have been possible, but would require the implementation to
define and allocate a separate struct in order to support thread joins. */
if ((rc = thread_context_create(&ctx)) == DDS_RETCODE_OK) {
ctx->func = start_routine;
ctx->arg = arg;
if (pdPASS != xTaskCreate(
&thread_start_routine, name, size, ctx, prio, &task))
{
thread_context_destroy(ctx);
rc = DDS_RETCODE_OUT_OF_RESOURCES;
} else {
thread->task = ctx->task = task;
}
}
ddsrt_mutex_unlock(&thread_registry.mutex);
return rc;
}
void
ddsrt_thread_init(void)
{
if (thread_context_require() != DDS_RETCODE_OK) {
assert(0);
}
}
void
ddsrt_thread_fini(void)
{
thread_context_t *ctx;
/* NO-OP if no context exists since thread-local storage and cleanup
handler references are both stored in the thread context. */
if ((ctx = thread_context) != NULL) {
assert(ctx->func != &non_local_thread);
thread_fini(ctx, 0);
}
}
dds_return_t
ddsrt_thread_join(ddsrt_thread_t thread, uint32_t *thread_result)
{
dds_return_t rc;
thread_context_t *ctx;
eTaskState status;
if ((rc = thread_context_require()) != DDS_RETCODE_OK) {
return rc;
}
ddsrt_mutex_lock(&thread_registry.mutex);
ctx = thread_context_find(thread.task);
if (ctx != NULL) {
/* Task should never be joined by multiple tasks simultaneously */
assert(ctx->blkd == NULL);
rc = DDS_RETCODE_TRY_AGAIN;
do {
(void)memset(&status, 0, sizeof(status));
status = eTaskGetState(thread.task);
if (status == eDeleted) {
/* FreeRTOS reports the task is deleted. Require the context to exist,
fetch the result and free the context afterwards. */
assert(ctx != NULL);
rc = DDS_RETCODE_OK;
} else if (status != eInvalid) {
assert(ctx != NULL);
/* FreeRTOS reports the task is still active. That does not mean the
task has not yet returned from start_routine. */
if (ctx->stat == THREAD_EXITING) {
/* Thread context will not be accessed by the thread itself anymore
and it should be safe to free it. */
rc = DDS_RETCODE_OK;
} else {
ctx->blkd = xTaskGetCurrentTaskHandle();
/* Reset notify state and counter. */
ulTaskNotifyTake(pdTRUE, 0);
ddsrt_mutex_unlock(&thread_registry.mutex);
/* Wait to be notified. */
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
ddsrt_mutex_lock(&thread_registry.mutex);
}
} else {
rc = DDS_RETCODE_BAD_PARAMETER;
}
} while (rc == DDS_RETCODE_TRY_AGAIN);
if (rc == DDS_RETCODE_OK) {
if (thread_result != NULL) {
*thread_result = ctx->ret;
}
thread_context_destroy(ctx);
}
}
ddsrt_mutex_unlock(&thread_registry.mutex);
return rc;
}
dds_return_t
ddsrt_thread_cleanup_push(void (*routine)(void *), void *arg)
{
dds_return_t rc = DDS_RETCODE_OK;
thread_cleanup_t *tail = NULL;
thread_context_t *ctx;
assert(routine != NULL);
if (thread_context_acquire(&ctx) == 0) {
if ((tail = ddsrt_malloc(sizeof(*tail))) == NULL) {
rc = DDS_RETCODE_OUT_OF_RESOURCES;
} else {
tail->prev = ctx->dtors;
tail->routine = routine;
tail->arg = arg;
ctx->dtors = tail;
}
}
return rc;
}
dds_return_t
ddsrt_thread_cleanup_pop(int execute)
{
thread_cleanup_t *tail;
thread_context_t *ctx;
if (thread_context_acquire(&ctx) == 0) {
if ((tail = ctx->dtors) != NULL) {
ctx->dtors = tail->prev;
if (execute) {
tail->routine(tail->arg);
}
ddsrt_free(tail);
}
}
return DDS_RETCODE_OK;
}

View file

@ -14,12 +14,6 @@
#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;

View file

@ -30,12 +30,24 @@
#include "dds/ddsrt/string.h"
#include "dds/ddsrt/threads_priv.h"
#include "dds/ddsrt/types.h"
#include "dds/ddsrt/static_assert.h"
typedef struct {
char *name;
ddsrt_thread_routine_t routine;
void *arg;
} thread_context_t;
#if defined(__linux)
#include <sys/syscall.h>
#include <dirent.h>
#define MAXTHREADNAMESIZE (15) /* 16 bytes including null-terminating byte. */
#elif defined(__APPLE__)
#include <mach/mach_init.h>
#include <mach/thread_info.h> /* MAXTHREADNAMESIZE */
#include <mach/task.h>
#include <mach/task_info.h>
#include <mach/vm_map.h>
#elif defined(__sun)
#define MAXTHREADNAMESIZE (31)
#elif defined(__FreeBSD__)
@ -74,7 +86,11 @@ ddsrt_thread_getname(char *str, size_t size)
(void)pthread_get_name_np(pthread_self(), buf, sizeof(buf));
cnt = ddsrt_strlcpy(str, buf, size);
#elif defined(__sun)
#if !(__SunOS_5_6 || __SunOS_5_7 || __SunOS_5_8 || __SunOS_5_9 || __SunOS_5_10)
(void)pthread_getname_np(pthread_self(), buf, sizeof(buf));
#else
buf[0] = 0;
#endif
cnt = ddsrt_strlcpy(str, buf, size);
#elif defined(__VXWORKS__)
{
@ -119,7 +135,9 @@ ddsrt_thread_setname(const char *__restrict name)
#elif defined(__sun)
/* Thread names are limited to 31 bytes on Solaris. Excess bytes are
silently truncated. */
#if !(__SunOS_5_6 || __SunOS_5_7 || __SunOS_5_8 || __SunOS_5_9 || __SunOS_5_10)
(void)pthread_setname_np(pthread_self(), name);
#endif
#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. */
@ -181,7 +199,7 @@ static void *os_startRoutineWrapper (void *threadContext)
return (void *)resultValue;
}
dds_retcode_t
dds_return_t
ddsrt_thread_create (
ddsrt_thread_t *threadptr,
const char *name,
@ -340,7 +358,7 @@ bool ddsrt_thread_equal(ddsrt_thread_t a, ddsrt_thread_t b)
return (pthread_equal(a.v, b.v) != 0);
}
dds_retcode_t
dds_return_t
ddsrt_thread_join(ddsrt_thread_t thread, uint32_t *thread_result)
{
int err;
@ -351,7 +369,7 @@ ddsrt_thread_join(ddsrt_thread_t thread, uint32_t *thread_result)
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);
DDS_ERROR ("pthread_join(0x%"PRIxMAX") failed with error %d\n", (uintmax_t)((uintptr_t)thread.v), err);
return DDS_RETCODE_ERROR;
}
@ -360,6 +378,104 @@ ddsrt_thread_join(ddsrt_thread_t thread, uint32_t *thread_result)
return DDS_RETCODE_OK;
}
#if defined __linux
dds_return_t
ddsrt_thread_list (
ddsrt_thread_list_id_t * __restrict tids,
size_t size)
{
DIR *dir;
struct dirent *de;
if ((dir = opendir ("/proc/self/task")) == NULL)
return DDS_RETCODE_ERROR;
dds_return_t n = 0;
while ((de = readdir (dir)) != NULL)
{
if (de->d_name[0] == '.' && (de->d_name[1] == 0 || (de->d_name[1] == '.' && de->d_name[2] == 0)))
continue;
int pos;
long tid;
if (sscanf (de->d_name, "%ld%n", &tid, &pos) != 1 || de->d_name[pos] != 0)
{
n = DDS_RETCODE_ERROR;
break;
}
if ((size_t) n < size)
tids[n] = (ddsrt_thread_list_id_t) tid;
n++;
}
closedir (dir);
/* If there were no threads, something must've gone badly wrong */
return (n == 0) ? DDS_RETCODE_ERROR : n;
}
dds_return_t
ddsrt_thread_getname_anythread (
ddsrt_thread_list_id_t tid,
char *__restrict name,
size_t size)
{
char file[100];
FILE *fp;
int pos;
pos = snprintf (file, sizeof (file), "/proc/self/task/%lu/stat", (unsigned long) tid);
if (pos < 0 || pos >= (int) sizeof (file))
return DDS_RETCODE_ERROR;
if ((fp = fopen (file, "r")) == NULL)
return DDS_RETCODE_NOT_FOUND;
int c;
size_t namelen = 0, namepos = 0;
while ((c = fgetc (fp)) != EOF)
if (c == '(')
break;
while ((c = fgetc (fp)) != EOF)
{
if (c == ')')
namelen = namepos;
if (namepos + 1 < size)
name[namepos++] = (char) c;
}
fclose (fp);
assert (size == 0 || namelen < size);
if (size > 0)
name[namelen] = 0;
return DDS_RETCODE_OK;
}
#elif defined __APPLE__
DDSRT_STATIC_ASSERT (sizeof (ddsrt_thread_list_id_t) == sizeof (mach_port_t));
dds_return_t
ddsrt_thread_list (
ddsrt_thread_list_id_t * __restrict tids,
size_t size)
{
thread_act_array_t tasks;
mach_msg_type_number_t count;
if (task_threads (mach_task_self (), &tasks, &count) != KERN_SUCCESS)
return DDS_RETCODE_ERROR;
for (mach_msg_type_number_t i = 0; i < count && (size_t) i < size; i++)
tids[i] = (ddsrt_thread_list_id_t) tasks[i];
vm_deallocate (mach_task_self (), (vm_address_t) tasks, count * sizeof (thread_act_t));
return (dds_return_t) count;
}
dds_return_t
ddsrt_thread_getname_anythread (
ddsrt_thread_list_id_t tid,
char *__restrict name,
size_t size)
{
if (size > 0)
{
pthread_t pt = pthread_from_mach_thread_np ((mach_port_t) tid);
name[0] = '\0';
if (pt == NULL || pthread_getname_np (pt, name, size) != 0 || name[0] == 0)
snprintf (name, size, "task%"PRIu64, (uint64_t) tid);
}
return DDS_RETCODE_OK;
}
#endif
static pthread_key_t thread_cleanup_key;
static pthread_once_t thread_once = PTHREAD_ONCE_INIT;
@ -380,7 +496,7 @@ 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)
dds_return_t ddsrt_thread_cleanup_push (void (*routine) (void *), void *arg)
{
int err;
thread_cleanup_t *prev, *tail;
@ -402,7 +518,7 @@ dds_retcode_t ddsrt_thread_cleanup_push (void (*routine) (void *), void *arg)
return DDS_RETCODE_OUT_OF_RESOURCES;
}
dds_retcode_t ddsrt_thread_cleanup_pop (int execute)
dds_return_t ddsrt_thread_cleanup_pop (int execute)
{
int err;
thread_cleanup_t *tail;

View file

@ -16,6 +16,66 @@
#include "dds/ddsrt/string.h"
#include "dds/ddsrt/threads_priv.h"
/* tlhelp32 for ddsrt_thread_list */
#include <stdio.h>
#include <stdlib.h>
#include <tlhelp32.h>
/* {Get,Set}ThreadDescription is the Windows 10 interface for dealing with thread names, but it at
least in some setups the linker can't find the symbols in kernel32.lib, even though kernel32.dll
exports them. (Perhaps it is just a broken installation, who knows ...) Looking them up
dynamically works fine. */
typedef HRESULT (WINAPI *SetThreadDescription_t) (HANDLE hThread, PCWSTR lpThreadDescription);
typedef HRESULT (WINAPI *GetThreadDescription_t) (HANDLE hThread, PWSTR *ppszThreadDescription);
static volatile SetThreadDescription_t SetThreadDescription_ptr = 0;
static volatile GetThreadDescription_t GetThreadDescription_ptr = 0;
static HRESULT WINAPI SetThreadDescription_dummy (HANDLE hThread, PCWSTR lpThreadDescription)
{
(void) hThread;
(void) lpThreadDescription;
return E_FAIL;
}
static HRESULT WINAPI GetThreadDescription_dummy (HANDLE hThread, PWSTR *ppszThreadDescription)
{
(void) hThread;
return E_FAIL;
}
static void getset_threaddescription_addresses (void)
{
/* Rely on MSVC's interpretation of the meaning of volatile
to order checking & setting the pointers */
if (GetThreadDescription_ptr == 0)
{
HMODULE mod;
FARPROC p;
if (!GetModuleHandleExA (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, "kernel32.dll", &mod))
{
SetThreadDescription_ptr = SetThreadDescription_dummy;
GetThreadDescription_ptr = GetThreadDescription_dummy;
}
else
{
if ((p = GetProcAddress (mod, "SetThreadDescription")) != 0)
SetThreadDescription_ptr = (SetThreadDescription_t) p;
else
SetThreadDescription_ptr = SetThreadDescription_dummy;
if ((p = GetProcAddress (mod, "GetThreadDescription")) != 0)
GetThreadDescription_ptr = (GetThreadDescription_t) p;
else
GetThreadDescription_ptr = GetThreadDescription_dummy;
}
}
}
typedef struct {
char *name;
ddsrt_thread_routine_t routine;
void *arg;
} thread_context_t;
static uint32_t
os_startRoutineWrapper(
void *threadContext)
@ -37,7 +97,7 @@ os_startRoutineWrapper(
return resultValue;
}
dds_retcode_t
dds_return_t
ddsrt_thread_create(
ddsrt_thread_t *thrptr,
const char *name,
@ -133,7 +193,7 @@ bool ddsrt_thread_equal(ddsrt_thread_t a, ddsrt_thread_t b)
* should not be closed until the os_threadWaitExit(...) call is called.
* CloseHandle (threadHandle);
*/
dds_retcode_t
dds_return_t
ddsrt_thread_join(
ddsrt_thread_t thread,
uint32_t *thread_result)
@ -170,7 +230,10 @@ ddsrt_thread_join(
}
/* 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. */
more storage than that as internal threads must adhere to that limit.
Use the thread-local variable instead of relying on GetThreadDescription
to avoid the dynamic memory allocation, as the thread name is used by
the logging code and the overhead there matters. */
static ddsrt_thread_local char thread_name[16] = "";
size_t
@ -191,6 +254,16 @@ ddsrt_thread_getname(
return cnt;
}
/** \brief Set thread name for debugging and system monitoring
*
* Windows 10 introduced the SetThreadDescription function, which is
* obviously the sane interface. For reasons unknown to me, the
* linker claims to have no knowledge of the function, even though
* they appear present, and so it seems to sensible to retain the
* old exception-based trick as a fall-back mechanism. At least
* until the reason for {Get,Set}Description's absence from the
* regular libraries.
*/
static const DWORD MS_VC_EXCEPTION=0x406D1388;
#pragma pack(push,8)
@ -203,19 +276,23 @@ typedef struct tagTHREADNAME_INFO
} 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);
assert (name != NULL);
getset_threaddescription_addresses ();
if (SetThreadDescription_ptr != SetThreadDescription_dummy)
{
size_t size = strlen (name) + 1;
wchar_t *wname = malloc (size * sizeof (*wname));
size_t cnt = 0;
mbstowcs_s (&cnt, wname, size, name, _TRUNCATE);
SetThreadDescription_ptr (GetCurrentThread (), wname);
free (wname);
}
else
{
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
@ -235,14 +312,77 @@ ddsrt_thread_setname(
/* Suppress warnings. */
}
#pragma warning(pop)
ddsrt_strlcpy(thread_name, name, sizeof(thread_name));
}
ddsrt_strlcpy (thread_name, name, sizeof (thread_name));
}
dds_return_t
ddsrt_thread_list (
ddsrt_thread_list_id_t * __restrict tids,
size_t size)
{
HANDLE hThreadSnap;
THREADENTRY32 te32;
const DWORD pid = GetCurrentProcessId ();
int32_t n = 0;
if ((hThreadSnap = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0)) == INVALID_HANDLE_VALUE)
return 0;
memset (&te32, 0, sizeof (te32));
te32.dwSize = sizeof (THREADENTRY32);
if (!Thread32First (hThreadSnap, &te32))
{
CloseHandle (hThreadSnap);
return 0;
}
do {
if (te32.th32OwnerProcessID != pid)
continue;
if ((size_t) n < size)
{
/* get a handle to the thread, not counting the thread the thread if no such
handle is obtainable */
if ((tids[n] = OpenThread (THREAD_QUERY_INFORMATION, FALSE, te32.th32ThreadID)) == NULL)
continue;
}
n++;
} while (Thread32Next (hThreadSnap, &te32));
CloseHandle (hThreadSnap);
return n;
}
dds_return_t
ddsrt_thread_getname_anythread (
ddsrt_thread_list_id_t tid,
char * __restrict name,
size_t size)
{
getset_threaddescription_addresses ();
if (size > 0)
{
PWSTR data;
HRESULT hr = GetThreadDescription_ptr (tid, &data);
if (! SUCCEEDED (hr))
name[0] = 0;
else
{
size_t cnt;
wcstombs_s (&cnt, name, size, data, _TRUNCATE);
LocalFree (data);
}
if (name[0] == 0)
{
snprintf (name, sizeof (name), "%"PRIdTID, GetThreadId (tid));
}
}
return DDS_RETCODE_OK;
}
static ddsrt_thread_local thread_cleanup_t *thread_cleanup = NULL;
dds_retcode_t ddsrt_thread_cleanup_push(void (*routine)(void *), void *arg)
dds_return_t ddsrt_thread_cleanup_push(void (*routine)(void *), void *arg)
{
thread_cleanup_t *tail;
@ -259,7 +399,7 @@ dds_retcode_t ddsrt_thread_cleanup_push(void (*routine)(void *), void *arg)
return DDS_RETCODE_OUT_OF_RESOURCES;
}
dds_retcode_t ddsrt_thread_cleanup_pop(int execute)
dds_return_t ddsrt_thread_cleanup_pop(int execute)
{
thread_cleanup_t *tail;

View file

@ -18,7 +18,7 @@
extern inline dds_time_t
ddsrt_time_add_duration(dds_time_t abstime, dds_duration_t reltime);
#if !defined(_WIN32)
#if !_WIN32 && !DDSRT_WITH_FREERTOS
#include <errno.h>
void dds_sleepfor(dds_duration_t n)
@ -47,7 +47,12 @@ size_t
ddsrt_ctime(dds_time_t n, char *str, size_t size)
{
struct tm tm;
#if __SunOS_5_6
/* Solaris 2.6 doesn't recognize %z so we just leave it out */
static const char fmt[] = "%Y-%m-%d %H:%M:%S";
#else
static const char fmt[] = "%Y-%m-%d %H:%M:%S%z";
#endif
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);
@ -61,12 +66,14 @@ ddsrt_ctime(dds_time_t n, char *str, size_t size)
#endif /* _WIN32 */
cnt = strftime(buf, sizeof(buf), fmt, &tm);
#if ! __SunOS_5_6
/* %z is without a separator between hours and minutes, fixup */
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] = ':';
#endif
(void)cnt;
return ddsrt_strlcpy(str, buf, size);

View file

@ -13,21 +13,29 @@
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12
#include <mach/mach_time.h>
#endif
#include "dds/ddsrt/time.h"
dds_time_t dds_time(void)
{
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
return (int64_t) clock_gettime_nsec_np (CLOCK_REALTIME);
#else
struct timeval tv;
(void)gettimeofday(&tv, NULL);
return ((tv.tv_sec * DDS_NSECS_IN_SEC) + (tv.tv_usec * DDS_NSECS_IN_USEC));
#endif
}
dds_time_t ddsrt_time_monotonic(void)
{
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
return (int64_t) clock_gettime_nsec_np (CLOCK_UPTIME_RAW);
#else
static mach_timebase_info_data_t timeInfo;
uint64_t mt;
@ -49,10 +57,15 @@ dds_time_t ddsrt_time_monotonic(void)
}
return (dds_time_t)(mt * timeInfo.numer / timeInfo.denom);
#endif
}
dds_time_t ddsrt_time_elapsed(void)
{
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
return (int64_t) clock_gettime_nsec_np (CLOCK_MONOTONIC_RAW);
#else
/* Elapsed time clock not (yet) supported on this platform. */
return ddsrt_time_monotonic();
#endif
}

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 <FreeRTOS.h>
#include <task.h>
#define _POSIX_TIMERS
#include <time.h>
#include "dds/ddsrt/time.h"
extern inline TickType_t ddsrt_duration_to_ticks_ceil(dds_duration_t reltime);
dds_time_t dds_time(void)
{
struct timespec ts;
#if __STDC_VERSION__ >= 201112L
timespec_get(&ts, TIME_UTC);
#else
(void)clock_gettime(CLOCK_REALTIME, &ts);
#endif
return (ts.tv_sec * DDS_NSECS_IN_SEC) + ts.tv_nsec;
}
#define NSECS_PER_TICK (DDS_NSECS_IN_SEC / configTICK_RATE_HZ)
dds_time_t ddsrt_time_monotonic (void)
{
return (xTaskGetTickCount() * NSECS_PER_TICK);
}
dds_time_t ddsrt_time_elapsed (void)
{
/* Elapsed time clock not (yet) supported on this platform. */
return ddsrt_time_monotonic ();
}
void dds_sleepfor (dds_duration_t reltime)
{
TickType_t ticks;
ticks = ddsrt_duration_to_ticks_ceil(reltime);
vTaskDelay(ticks);
}

View file

@ -0,0 +1,38 @@
/*
* 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)
{
return gethrtime ();
}
dds_time_t ddsrt_time_elapsed(void)
{
/* Elapsed time clock not worth the bother for now. */
return ddsrt_time_monotonic();
}

View file

@ -35,6 +35,7 @@ struct ddsrt_xmlp_state {
size_t cbufn; /* number of bytes in cbuf (cbufp <= cbufn) */
size_t cbufmax; /* allocated size of cbuf (cbufn <= cbufmax) */
size_t cbufmark; /* NORMARKER or marker position (cbufmark <= cbufp) for rewinding */
int eof; /* fake EOF (for treating missing close tags as EOF) */
char *cbuf; /* parser input buffer */
FILE *fp; /* file to refill cbuf from, or NULL if parsing a string */
int line; /* current line number */
@ -53,36 +54,40 @@ struct ddsrt_xmlp_state {
struct ddsrt_xmlp_callbacks cb; /* user-supplied callbacks (or stubs) */
};
static int cb_null_elem_open (void *varg, uintptr_t parentinfo, uintptr_t *eleminfo, const char *name)
static int cb_null_elem_open (void *varg, uintptr_t parentinfo, uintptr_t *eleminfo, const char *name, int line)
{
DDSRT_UNUSED_ARG (varg);
DDSRT_UNUSED_ARG (parentinfo);
DDSRT_UNUSED_ARG (eleminfo);
DDSRT_UNUSED_ARG (name);
DDSRT_UNUSED_ARG (line);
return 0;
}
static int cb_null_attr (void *varg, uintptr_t eleminfo, const char *name, const char *value)
static int cb_null_attr (void *varg, uintptr_t eleminfo, const char *name, const char *value, int line)
{
DDSRT_UNUSED_ARG (varg);
DDSRT_UNUSED_ARG (eleminfo);
DDSRT_UNUSED_ARG (name);
DDSRT_UNUSED_ARG (value);
DDSRT_UNUSED_ARG (line);
return 0;
}
static int cb_null_elem_data (void *varg, uintptr_t eleminfo, const char *data)
static int cb_null_elem_data (void *varg, uintptr_t eleminfo, const char *data, int line)
{
DDSRT_UNUSED_ARG (varg);
DDSRT_UNUSED_ARG (eleminfo);
DDSRT_UNUSED_ARG (data);
DDSRT_UNUSED_ARG (line);
return 0;
}
static int cb_null_elem_close (void *varg, uintptr_t eleminfo)
static int cb_null_elem_close (void *varg, uintptr_t eleminfo, int line)
{
DDSRT_UNUSED_ARG (varg);
DDSRT_UNUSED_ARG (eleminfo);
DDSRT_UNUSED_ARG (line);
return 0;
}
@ -97,6 +102,7 @@ static void ddsrt_xmlp_new_common (struct ddsrt_xmlp_state *st)
{
st->cbufp = 0;
st->cbufmark = NOMARKER;
st->eof = 0;
st->tpp = 0;
st->tpescp = 0;
st->tpsz = 1024;
@ -170,6 +176,9 @@ void ddsrt_xmlp_free (struct ddsrt_xmlp_state *st)
static int make_chars_available (struct ddsrt_xmlp_state *st, size_t nmin)
{
size_t n, pos;
if (st->eof) {
return 0;
}
pos = (st->cbufmark != NOMARKER) ? st->cbufmark : st->cbufp;
assert (st->cbufn >= st->cbufp);
assert (st->cbufmax >= st->cbufn);
@ -215,6 +224,11 @@ static void discard_input_marker (struct ddsrt_xmlp_state *st)
st->linemark = 0;
}
static int have_input_marker (struct ddsrt_xmlp_state *st)
{
return (st->cbufmark != NOMARKER);
}
static void rewind_to_input_marker (struct ddsrt_xmlp_state *st)
{
assert (st->cbufmark != NOMARKER);
@ -295,9 +309,9 @@ static char *unescape_into_utf8 (char *dst, unsigned cp)
return dst;
}
DDSRT_WARNING_MSVC_OFF(4996);
static int unescape_insitu (char *buffer, size_t *n)
{
DDSRT_WARNING_MSVC_OFF(4996);
const char *src = buffer;
char const * const srcend = buffer + *n;
char *dst = buffer;
@ -351,8 +365,8 @@ static int unescape_insitu (char *buffer, size_t *n)
}
*n = (size_t) (dst - buffer);
return 0;
DDSRT_WARNING_MSVC_ON(4996);
}
DDSRT_WARNING_MSVC_ON(4996);
static void discard_payload (struct ddsrt_xmlp_state *st)
{
@ -596,7 +610,7 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo)
PE_LOCAL_ERROR ("expecting '<'", 0);
}
if ((ret = st->cb.elem_open (st->varg, parentinfo, &eleminfo, name)) < 0) {
if ((ret = st->cb.elem_open (st->varg, parentinfo, &eleminfo, name, st->line)) < 0) {
PE_ERROR ("failed in element open callback", name);
}
@ -610,7 +624,7 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo)
ddsrt_free (content);
PE_LOCAL_ERROR ("expecting string value for attribute", aname);
}
ret = st->cb.attr (st->varg, eleminfo, aname, content);
ret = st->cb.attr (st->varg, eleminfo, aname, content, st->line);
ddsrt_free (content);
if (ret < 0) {
PE_ERROR2 ("failed in attribute callback", name, aname);
@ -623,7 +637,7 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo)
switch (tok)
{
case TOK_SHORTHAND_CLOSE_TAG:
ret = st->cb.elem_close (st->varg, eleminfo);
ret = st->cb.elem_close (st->varg, eleminfo, st->line);
goto ok;
case '>':
st->nest++;
@ -668,8 +682,8 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo)
if (save_payload (&content, st, 1) < 0) {
PE_ERROR ("invalid character sequence", 0);
} else if (content != NULL) {
if(*content != '\0') {
ret = st->cb.elem_data (st->varg, eleminfo, content);
if (*content != '\0') {
ret = st->cb.elem_data (st->varg, eleminfo, content, st->line);
ddsrt_free (content);
if (ret < 0) {
PE_ERROR ("failed in data callback", 0);
@ -680,13 +694,23 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo)
}
}
st->nest--;
set_input_marker (st);
if (((tok = next_token (st, &ename)) != TOK_CLOSE_TAG && tok != TOK_SHORTHAND_CLOSE_TAG) || next_char (st) != '>') {
PE_LOCAL_ERROR ("expecting closing tag", name);
if (!(st->options & DDSRT_XMLP_MISSING_CLOSE_AS_EOF)) {
PE_LOCAL_ERROR ("expecting closing tag", name);
} else {
rewind_to_input_marker (st);
st->eof = 1;
tok = TOK_SHORTHAND_CLOSE_TAG;
}
}
if (tok != TOK_SHORTHAND_CLOSE_TAG && strcmp (name, ename) != 0) {
PE_LOCAL_ERROR ("open/close tag mismatch", ename);
}
ret = st->cb.elem_close (st->varg, eleminfo);
if (have_input_marker (st)) {
discard_input_marker (st);
}
ret = st->cb.elem_close (st->varg, eleminfo, st->line);
goto ok;
default:
PE_LOCAL_ERROR ("expecting '/>' or '>'", 0);
@ -722,7 +746,3 @@ int ddsrt_xmlp_parse (struct ddsrt_xmlp_state *st)
}
}
}
int ddsrt_xmlUnescapeInsitu (char *buffer, size_t *n) {
return unescape_insitu (buffer, n);
}

View file

@ -10,65 +10,38 @@
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
include(CUnit)
include(GenerateExportHeader)
include(GenerateDummyExportHeader)
set(sources
"atomics.c"
"dynlib.c"
"environ.c"
"heap.c"
"ifaddrs.c"
"sync.c"
"strtoll.c"
"thread.c"
"thread_cleanup.c"
"string.c"
"log.c"
"random.c"
"strlcpy.c"
"socket.c"
"process.c"
"select.c")
list(APPEND sources
"atomics.c"
"dynlib.c"
"environ.c"
"heap.c"
"ifaddrs.c"
"sync.c"
"strtoll.c"
"thread.c"
"thread_cleanup.c"
"string.c"
"log.c"
"random.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")
if(HAVE_MULTI_PROCESS)
list(APPEND sources "process.c")
endif()
if(WITH_FREERTOS)
list(APPEND sources "tasklist.c")
endif()
add_cunit_executable(cunit_ddsrt ${sources})
target_link_libraries(
cunit_ddsrt PRIVATE ddsrt)
target_include_directories(
cunit_ddsrt PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>")
# Create a separate test application that will be used to
# test process management.
add_executable(process_app process_app.c)
target_link_libraries(process_app PRIVATE ddsrt)
target_include_directories(
process_app
PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>")
# Force the app to be at the same location, no matter what platform or build type.
set_target_properties(
process_app
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}
RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR}
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_BINARY_DIR}
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_BINARY_DIR} )
# Let the cunit application know the location and name of the test application.
set(process_app_name "${CMAKE_CURRENT_BINARY_DIR}/process_app${CMAKE_EXECUTABLE_SUFFIX}")
configure_file(
"process_test.h.in" "${CMAKE_CURRENT_BINARY_DIR}/include/process_test.h" @ONLY)
# Create a separate shared library that will be used to
# test dynamic library loading.
@ -89,7 +62,7 @@ set_target_properties(
LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_BINARY_DIR}
LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_BINARY_DIR} )
# Use proper export for this test lib.
generate_export_header(${test_lib_name} BASE_NAME LIB_TEST)
#generate_dummy_export_header(${test_lib_name} BASE_NAME dds LIB_TEST)
target_include_directories(${test_lib_name} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
# Let the cunit application know the location and name of the library.
file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}" test_lib_native_dir)
@ -112,3 +85,38 @@ foreach(libtest ${test_lib_tests})
endif()
endforeach()
generate_dummy_export_header(
cunit_ddsrt
BASE_NAME dds
EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/include/dds/export.h")
generate_dummy_export_header(
${test_lib_name}
BASE_NAME lib_test
EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/lib_test_export.h")
if(HAVE_MULTI_PROCESS)
# A separate application is required to test process management.
add_executable(process_app process_app.c)
target_link_libraries(process_app PRIVATE ddsrt)
target_include_directories(
process_app
PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>")
# Force the app to be at the same location, no matter what platform or build type.
# FIXME: What if custom targets are added?
# FIXME: What debug and release builds are mixed on Windows and macOS?
set_target_properties(
process_app
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}
RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR}
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_BINARY_DIR}
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_BINARY_DIR} )
# Let the cunit application know the location and name of the test application.
set(process_app_name "${CMAKE_CURRENT_BINARY_DIR}/process_app${CMAKE_EXECUTABLE_SUFFIX}")
configure_file(
"process_test.h.in" "${CMAKE_CURRENT_BINARY_DIR}/include/process_test.h" @ONLY)
endif()

View file

@ -13,12 +13,14 @@
static int g_val = -1;
LIB_TEST_EXPORT void set_int(int val)
LIB_TEST_EXPORT void set_int(int val);
void set_int(int val)
{
g_val = val;
}
LIB_TEST_EXPORT int get_int(void)
LIB_TEST_EXPORT int get_int(void);
int get_int(void)
{
return g_val;
}

View file

@ -25,10 +25,10 @@
#define TEST_ABORT_IF_NULL(var, msg) \
do { \
if (var == NULL) { \
char buffer[256]; \
r = ddsrt_dlerror(buffer, sizeof(buffer)); \
char err[256]; \
r = ddsrt_dlerror(err, sizeof(err)); \
CU_ASSERT_EQUAL_FATAL(r, DDS_RETCODE_OK); \
printf("\n%s", buffer); \
printf("\n%s", err); \
CU_FAIL_FATAL(msg); \
} \
} while(0)
@ -39,7 +39,7 @@ do { \
*/
CU_Test(ddsrt_library, dlopen_path)
{
dds_retcode_t r;
dds_return_t r;
ddsrt_dynlib_t l;
printf("Absolute lib: %s\n", TEST_LIB_ABSOLUTE);
@ -54,7 +54,7 @@ CU_Test(ddsrt_library, dlopen_path)
CU_Test(ddsrt_library, dlopen_file)
{
dds_retcode_t r;
dds_return_t r;
ddsrt_dynlib_t l;
r = ddsrt_dlopen(TEST_LIB_FILE, false, &l);
@ -68,7 +68,7 @@ CU_Test(ddsrt_library, dlopen_file)
CU_Test(ddsrt_library, dlopen_name)
{
dds_retcode_t r;
dds_return_t r;
ddsrt_dynlib_t l;
r = ddsrt_dlopen(TEST_LIB_NAME, true, &l);
@ -83,7 +83,7 @@ CU_Test(ddsrt_library, dlopen_name)
CU_Test(ddsrt_library, dlopen_unknown)
{
char buffer[256];
dds_retcode_t r;
dds_return_t r;
ddsrt_dynlib_t l;
r = ddsrt_dlopen("UnknownLib", false, &l);
@ -97,7 +97,7 @@ CU_Test(ddsrt_library, dlopen_unknown)
CU_Test(ddsrt_library, dlsym)
{
dds_retcode_t r;
dds_return_t r;
ddsrt_dynlib_t l;
void* f;
@ -118,7 +118,7 @@ CU_Test(ddsrt_library, dlsym)
CU_Test(ddsrt_library, dlsym_unknown)
{
char buffer[256];
dds_retcode_t r;
dds_return_t r;
ddsrt_dynlib_t l;
void* f;
@ -146,7 +146,7 @@ CU_Test(ddsrt_library, call)
int set_int = 1234;
func_get_int f_get;
func_set_int f_set;
dds_retcode_t r;
dds_return_t r;
ddsrt_dynlib_t l;
r = ddsrt_dlopen(TEST_LIB_NAME, true, &l);
@ -171,7 +171,7 @@ CU_Test(ddsrt_library, call)
CU_Test(ddsrt_library, dlclose_error)
{
dds_retcode_t r;
dds_return_t r;
ddsrt_dynlib_t l;
r = ddsrt_dlopen(TEST_LIB_NAME, true, &l);
@ -189,9 +189,10 @@ CU_Test(ddsrt_library, dlclose_error)
CU_Test(ddsrt_library, dlerror_notfound)
{
char buffer[256];
dds_retcode_t r;
dds_return_t r;
ddsrt_dlerror(buffer, sizeof(buffer));
r = ddsrt_dlerror(buffer, sizeof(buffer));
CU_ASSERT_EQUAL(r, DDS_RETCODE_NOT_FOUND);
}

View file

@ -22,7 +22,7 @@ CU_TheoryDataPoints(ddsrt_environ, bad_name) = {
CU_Theory((const char *name), ddsrt_environ, bad_name)
{
dds_retcode_t rc;
dds_return_t rc;
static const char value[] = "bar";
static char dummy[] = "foobar";
char *ptr;
@ -40,7 +40,7 @@ CU_Theory((const char *name), ddsrt_environ, bad_name)
DDSRT_WARNING_MSVC_OFF(4996)
CU_Test(ddsrt_environ, setenv)
{
dds_retcode_t rc;
dds_return_t rc;
static const char name[] = "foo";
static char value[] = "bar";
char *ptr;
@ -64,7 +64,7 @@ DDSRT_WARNING_MSVC_ON(4996)
CU_Test(ddsrt_environ, getenv)
{
dds_retcode_t rc;
dds_return_t rc;
static const char name[] = "foo";
static const char value[] = "bar";
static char dummy[] = "foobar";
@ -111,7 +111,7 @@ CU_TheoryDataPoints(ddsrt_environ, expand) = {
};
CU_Theory((const char *var, const char *expect), ddsrt_environ, expand)
{
dds_retcode_t rc;
dds_return_t rc;
static const char x_name[] = "X";
static const char x_value[] = "TEST";
static const char y_name[] = "Y";
@ -131,7 +131,7 @@ CU_Theory((const char *var, const char *expect), ddsrt_environ, expand)
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
/* Expand a string with available environment variables. */
ptr = ddsrt_expand_envvars(var);
ptr = ddsrt_expand_envvars(var,UINT32_MAX);
if (ptr) {
/* printf("==== %10s: expand(%s), expect(%s))\n", var, ptr, expect); */
CU_ASSERT_STRING_EQUAL(ptr, expect);
@ -163,7 +163,7 @@ CU_TheoryDataPoints(ddsrt_environ, expand_sh) = {
};
CU_Theory((const char *var, const char *expect), ddsrt_environ, expand_sh)
{
dds_retcode_t rc;
dds_return_t rc;
static const char x_name[] = "X";
static const char x_value[] = "TEST";
static const char y_name[] = "Y";
@ -183,7 +183,7 @@ CU_Theory((const char *var, const char *expect), ddsrt_environ, expand_sh)
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
/* Expand a string with available environment variables. */
ptr = ddsrt_expand_envvars_sh(var);
ptr = ddsrt_expand_envvars_sh(var,UINT32_MAX);
if (ptr) {
/* printf("==== %10s: expand(%s), expect(%s))\n", var, ptr, expect); */
CU_ASSERT_STRING_EQUAL(ptr, expect);

View file

@ -9,10 +9,10 @@
*
* 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"
#include "CUnit/Test.h"
/* FIXME: It's not possible to predict what network interfaces are available
on a given host. To properly test all combinations the abstracted
@ -64,7 +64,7 @@ CU_Clean(ddsrt_getifaddrs)
IFF_LOOPBACK flags are properly set. */
CU_Test(ddsrt_getifaddrs, ipv4)
{
dds_retcode_t ret;
dds_return_t ret;
int seen = 0;
ddsrt_ifaddrs_t *ifa_root, *ifa;
const int afs[] = { AF_INET, DDSRT_AF_TERM };
@ -90,7 +90,7 @@ CU_Test(ddsrt_getifaddrs, ipv4)
CU_Test(ddsrt_getifaddrs, null_filter)
{
dds_retcode_t ret;
dds_return_t ret;
int cnt = 0;
ddsrt_ifaddrs_t *ifa_root, *ifa;
@ -107,7 +107,7 @@ CU_Test(ddsrt_getifaddrs, null_filter)
CU_Test(ddsrt_getifaddrs, empty_filter)
{
dds_retcode_t ret;
dds_return_t ret;
ddsrt_ifaddrs_t *ifa_root;
const int afs[] = { DDSRT_AF_TERM };
@ -117,11 +117,11 @@ CU_Test(ddsrt_getifaddrs, empty_filter)
ddsrt_freeifaddrs(ifa_root);
}
#ifdef DDSRT_HAVE_IPV6
CU_Test(ddsrt_getifaddrs, ipv6)
{
#ifdef DDSRT_HAVE_IPV6
if (ipv6_enabled == 1) {
dds_retcode_t ret;
dds_return_t ret;
int have_ipv6 = 0;
ddsrt_ifaddrs_t *ifa_root, *ifa;
const int afs[] = { AF_INET6, DDSRT_AF_TERM };
@ -149,14 +149,18 @@ CU_Test(ddsrt_getifaddrs, ipv6)
} else {
CU_PASS("IPv6 disabled in test environment");
}
#else
CU_PASS("IPv6 is not supported");
#endif
}
/* 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 DDSRT_HAVE_IPV6
if (ipv6_enabled == 1) {
dds_retcode_t ret;
dds_return_t ret;
int have_ipv4 = 0;
int have_ipv6 = 0;
ddsrt_ifaddrs_t *ifa_root, *ifa;
@ -182,6 +186,8 @@ CU_Test(ddsrt_getifaddrs, ipv4_n_ipv6)
} else {
CU_PASS("IPv6 disabled in test environment");
}
#else
CU_PASS("IPv6 is not supported");
#endif /* DDSRT_HAVE_IPV6 */
}
#endif /* DDSRT_HAVE_IPV6 */

View file

@ -311,8 +311,8 @@ static ddsrt_mutex_t mutex;
struct arg {
ddsrt_cond_t *cond;
ddsrt_mutex_t *mutex;
dds_time_t stamp;
dds_duration_t pause;
dds_time_t before;
dds_time_t after;
};
static void dummy(void *ptr, const dds_log_data_t *data)
@ -326,10 +326,10 @@ 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();
arg->before = dds_time();
ddsrt_cond_broadcast(arg->cond);
ddsrt_mutex_unlock(arg->mutex);
dds_sleepfor(arg->pause);
arg->after = dds_time();
}
static uint32_t run(void *ptr)
@ -347,17 +347,15 @@ static uint32_t run(void *ptr)
CU_Test(dds_log, synchronous_sink_changes, .fini=reset)
{
struct arg arg;
dds_time_t diff, stamp;
ddsrt_thread_t tid;
ddsrt_threadattr_t tattr;
dds_retcode_t ret;
dds_return_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);
@ -366,9 +364,7 @@ CU_Test(dds_log, synchronous_sink_changes, .fini=reset)
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);
CU_ASSERT(arg.before < arg.after);
CU_ASSERT(arg.after < dds_time());
}

View file

@ -26,7 +26,7 @@
*/
static void create_and_test_exit(const char *arg, int code)
{
dds_retcode_t ret;
dds_return_t ret;
ddsrt_pid_t pid;
int32_t status;
char *argv[] = { NULL, NULL };
@ -64,7 +64,7 @@ CU_Test(ddsrt_process, create)
*/
CU_Test(ddsrt_process, kill)
{
dds_retcode_t ret;
dds_return_t ret;
ddsrt_pid_t pid;
/* Sleep for 20 seconds. It should be killed before then. */
@ -98,7 +98,7 @@ CU_Test(ddsrt_process, kill)
*/
CU_Test(ddsrt_process, pid)
{
dds_retcode_t ret;
dds_return_t ret;
ddsrt_pid_t pid;
int32_t status;
char *argv[] = { TEST_PID_ARG, NULL };
@ -126,7 +126,7 @@ CU_Test(ddsrt_process, pid)
*/
CU_Test(ddsrt_process, env)
{
dds_retcode_t ret;
dds_return_t ret;
ret = ddsrt_setenv(TEST_ENV_VAR_NAME, TEST_ENV_VAR_VALUE);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
@ -141,7 +141,7 @@ CU_Test(ddsrt_process, env)
*/
CU_Test(ddsrt_process, invalid)
{
dds_retcode_t ret;
dds_return_t ret;
ddsrt_pid_t pid;
ret = ddsrt_proc_create("ProbablyNotAnValidExecutable", NULL, &pid);
@ -177,7 +177,7 @@ CU_Test(ddsrt_process, arg_dquote)
*/
CU_Test(ddsrt_process, waitpids)
{
dds_retcode_t ret;
dds_return_t ret;
ddsrt_pid_t child;
ddsrt_pid_t pid1 = 0;
ddsrt_pid_t pid2 = 0;
@ -225,7 +225,7 @@ CU_Test(ddsrt_process, waitpids)
*/
CU_Test(ddsrt_process, waitpid_timeout)
{
dds_retcode_t ret;
dds_return_t ret;
ddsrt_pid_t pid;
/* Sleep for 20 seconds. We should have a timeout before then. */
@ -238,7 +238,7 @@ CU_Test(ddsrt_process, waitpid_timeout)
ret = ddsrt_proc_waitpid(pid, 0, NULL);
CU_ASSERT_EQUAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET);
/* Valid timeout should return DDS_RETCODE_TIMEOUT when alive. */
/* Valid timeout should return DDS_RETURN_TIMEOUT when alive. */
ret = ddsrt_proc_waitpid(pid, DDS_SECS(1), NULL);
CU_ASSERT_EQUAL(ret, DDS_RETCODE_TIMEOUT);
@ -257,7 +257,7 @@ CU_Test(ddsrt_process, waitpid_timeout)
*/
CU_Test(ddsrt_process, waitpids_timeout)
{
dds_retcode_t ret;
dds_return_t ret;
ddsrt_pid_t pid;
/* Sleep for 20 seconds. We should have a timeout before then. */
@ -270,7 +270,7 @@ CU_Test(ddsrt_process, waitpids_timeout)
ret = ddsrt_proc_waitpids(0, NULL, NULL);
CU_ASSERT_EQUAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET);
/* Valid timeout should return DDS_RETCODE_TIMEOUT when alive. */
/* Valid timeout should return DDS_RETURN_TIMEOUT when alive. */
ret = ddsrt_proc_waitpids(DDS_SECS(1), NULL, NULL);
CU_ASSERT_EQUAL(ret, DDS_RETCODE_TIMEOUT);

View file

@ -9,10 +9,10 @@
*
* 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/cdtors.h"
#include "dds/ddsrt/threads.h"
#include "CUnit/Theory.h"
CU_Init(ddsrt_select)
{
@ -36,8 +36,13 @@ 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;
dds_duration_t secs_max;
DDSRT_STATIC_ASSERT (CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 32 || CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 64);
if (CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 32)
secs_max = INT32_MAX;
else
secs_max = INT64_MAX;
if (DDS_INFINITY > secs_max) {
CU_ASSERT_EQUAL_FATAL(secs_max, INT32_MAX);
@ -107,40 +112,45 @@ typedef struct {
static void
sockets_pipe(ddsrt_socket_t socks[2])
{
dds_retcode_t rc;
dds_return_t rc;
ddsrt_socket_t sock;
int reuseaddr = 1;
socklen_t addrlen;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = htons(54321);
addr.sin_port = 0;
fprintf (stderr, "sockets_pipe ... begin\n");
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);
addrlen = (socklen_t) sizeof(addr);
rc = ddsrt_getsockname(sock, (struct sockaddr *)&addr, &addrlen);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
fprintf (stderr, "sockets_pipe ... listen\n");
rc = ddsrt_listen(sock, 1);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
fprintf (stderr, "sockets_pipe ... connect\n");
rc = ddsrt_connect(socks[1], (struct sockaddr *)&addr, sizeof(addr));
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
fprintf (stderr, "sockets_pipe ... accept\n");
rc = ddsrt_accept(sock, NULL, NULL, &socks[0]);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
ddsrt_close(sock);
fprintf (stderr, "sockets_pipe ... done\n");
}
static const char mesg[] = "foobar";
static uint32_t select_timeout_routine(void *ptr)
{
int cnt = -1;
dds_retcode_t rc;
int32_t cnt = -1;
dds_return_t rc;
dds_time_t before, after;
dds_duration_t delay;
fd_set rdset;
@ -148,7 +158,13 @@ static uint32_t select_timeout_routine(void *ptr)
uint32_t res = 0;
FD_ZERO(&rdset);
#if LWIP_SOCKET
DDSRT_WARNING_GNUC_OFF(sign-conversion)
#endif
FD_SET(arg->sock, &rdset);
#if LWIP_SOCKET
DDSRT_WARNING_GNUC_ON(sign-conversion)
#endif
before = dds_time();
rc = ddsrt_select(arg->sock + 1, &rdset, NULL, NULL, arg->delay, &cnt);
@ -157,11 +173,15 @@ static uint32_t select_timeout_routine(void *ptr)
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);
fprintf(stderr, "ddsrt_select returned %"PRId32"\n", rc);
fprintf(stderr, "ddsrt_select reported %"PRId32" ready\n", cnt);
if (rc == DDS_RETCODE_TIMEOUT) {
res = (((after - delay) >= (arg->delay - arg->skew)) && (cnt == 0));
/* Running in the FreeRTOS simulator causes some trouble as interrupts are
simulated using signals causing the select call to be interrupted. */
} else if (rc == DDS_RETCODE_INTERRUPTED) {
res = (cnt == -1);
}
return res;
@ -169,7 +189,7 @@ static uint32_t select_timeout_routine(void *ptr)
CU_Test(ddsrt_select, timeout)
{
dds_retcode_t rc;
dds_return_t rc;
ddsrt_socket_t socks[2];
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
@ -178,23 +198,26 @@ CU_Test(ddsrt_select, timeout)
sockets_pipe(socks);
arg.delay = DDS_MSECS(100);
arg.delay = DDS_MSECS(300);
/* 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.skew = DDS_MSECS(50);
arg.sock = socks[0];
fprintf (stderr, "create thread\n");
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. */
fprintf (stderr, "write data\n");
ssize_t sent = 0;
rc = ddsrt_send(socks[1], mesg, sizeof(mesg), 0, &sent);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
fprintf (stderr, "join thread\n");
rc = ddsrt_thread_join(thr, &res);
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(res, 1);
@ -207,13 +230,19 @@ static uint32_t recv_routine(void *ptr)
{
thread_arg_t *arg = (thread_arg_t*)ptr;
int nfds = 0;
int32_t nfds = 0;
fd_set rdset;
ssize_t rcvd = -1;
char buf[sizeof(mesg)];
FD_ZERO(&rdset);
#if LWIP_SOCKET
DDSRT_WARNING_GNUC_OFF(sign-conversion)
#endif
FD_SET(arg->sock, &rdset);
#if LWIP_SOCKET
DDSRT_WARNING_GNUC_ON(sign-conversion)
#endif
(void)ddsrt_select(arg->sock + 1, &rdset, NULL, NULL, arg->delay, &nfds);
@ -226,7 +255,7 @@ static uint32_t recv_routine(void *ptr)
CU_Test(ddsrt_select, send_recv)
{
dds_retcode_t rc;
dds_return_t rc;
ddsrt_socket_t socks[2];
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
@ -260,7 +289,7 @@ static uint32_t recvmsg_routine(void *ptr)
{
thread_arg_t *arg = (thread_arg_t*)ptr;
int nfds = 0;
int32_t nfds = 0;
fd_set rdset;
ssize_t rcvd = -1;
char buf[sizeof(mesg)];
@ -274,7 +303,13 @@ static uint32_t recvmsg_routine(void *ptr)
msg.msg_iovlen = 1;
FD_ZERO(&rdset);
#if LWIP_SOCKET
DDSRT_WARNING_GNUC_OFF(sign-conversion)
#endif
FD_SET(arg->sock, &rdset);
#if LWIP_SOCKET
DDSRT_WARNING_GNUC_ON(sign-conversion)
#endif
(void)ddsrt_select(arg->sock + 1, &rdset, NULL, NULL, arg->delay, &nfds);
@ -287,7 +322,7 @@ static uint32_t recvmsg_routine(void *ptr)
CU_Test(ddsrt_select, sendmsg_recvmsg)
{
dds_retcode_t rc;
dds_return_t rc;
ddsrt_socket_t socks[2];
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;

View file

@ -9,17 +9,17 @@
*
* 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/sockets.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"
#include "dds/ddsrt/string.h"
#include "CUnit/Theory.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
DDSRT_WARNING_MSVC_OFF(4305)
#if DDSRT_ENDIAN == DDSRT_BIG_ENDIAN
@ -48,15 +48,15 @@ static void teardown(void)
CU_Test(ddsrt_sockaddrfromstr, bad_family)
{
dds_retcode_t rc;
dds_return_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)
static void sockaddrfromstr_test(char *str, int af, dds_return_t exp)
{
dds_retcode_t rc;
dds_return_t rc;
struct sockaddr_storage ss;
rc = ddsrt_sockaddrfromstr(af, str, &ss);
CU_ASSERT_EQUAL(rc, exp);
@ -70,37 +70,44 @@ CU_TheoryDataPoints(ddsrt_sockaddrfromstr, ipv4) = {
"nip"),
CU_DataPoints(int, AF_INET, AF_INET,
AF_INET),
CU_DataPoints(dds_retcode_t, DDS_RETCODE_OK, DDS_RETCODE_OK,
CU_DataPoints(dds_return_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)
CU_Theory((char *str, int af, dds_return_t exp), ddsrt_sockaddrfromstr, ipv4, .init=setup, .fini=teardown)
{
sockaddrfromstr_test(str, af, exp);
}
#if DDSRT_HAVE_IPV6
CU_TheoryDataPoints(ddsrt_sockaddrfromstr, ipv6) = {
#if DDSRT_HAVE_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,
CU_DataPoints(dds_return_t, DDS_RETCODE_BAD_PARAMETER, DDS_RETCODE_OK,
DDS_RETCODE_BAD_PARAMETER, DDS_RETCODE_OK,
DDS_RETCODE_BAD_PARAMETER)
#endif /* DDSRT_HAVE_IPV6 */
};
CU_Theory((char *str, int af, dds_retcode_t exp), ddsrt_sockaddrfromstr, ipv6, .init=setup, .fini=teardown)
CU_Theory((char *str, int af, dds_return_t exp), ddsrt_sockaddrfromstr, ipv6, .init=setup, .fini=teardown)
{
#if DDSRT_HAVE_IPV6
sockaddrfromstr_test(str, af, exp);
}
#else
(void)str;
(void)af;
(void)exp;
CU_PASS("IPV6 is not supported");
#endif /* DDSRT_HAVE_IPV6 */
}
CU_Test(ddsrt_sockaddrtostr, bad_sockaddr, .init=setup, .fini=teardown)
{
dds_retcode_t rc;
dds_return_t rc;
char buf[128] = { 0 };
struct sockaddr_in sa;
memcpy(&sa, &ipv4_loopback, sizeof(ipv4_loopback));
@ -111,7 +118,7 @@ CU_Test(ddsrt_sockaddrtostr, bad_sockaddr, .init=setup, .fini=teardown)
CU_Test(ddsrt_sockaddrtostr, no_space, .init=setup, .fini=teardown)
{
dds_retcode_t rc;
dds_return_t rc;
char buf[1] = { 0 };
rc = ddsrt_sockaddrtostr(&ipv4_loopback, buf, sizeof(buf));
CU_ASSERT_EQUAL(rc, DDS_RETCODE_NOT_ENOUGH_SPACE);
@ -119,7 +126,7 @@ CU_Test(ddsrt_sockaddrtostr, no_space, .init=setup, .fini=teardown)
CU_Test(ddsrt_sockaddrtostr, ipv4)
{
dds_retcode_t rc;
dds_return_t rc;
char buf[128] = { 0 };
rc = ddsrt_sockaddrtostr(&ipv4_loopback, buf, sizeof(buf));
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
@ -128,17 +135,20 @@ CU_Test(ddsrt_sockaddrtostr, ipv4)
CU_Test(ddsrt_sockaddrtostr, ipv6)
{
dds_retcode_t rc;
#if DDSRT_HAVE_IPV6
dds_return_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");
#else
CU_PASS("IPv6 is not supported");
#endif
}
CU_Test(ddsrt_sockets, gethostname)
{
int ret;
dds_retcode_t rc;
dds_return_t rc;
char sysbuf[200], buf[200];
buf[0] = '\0';
@ -146,8 +156,12 @@ CU_Test(ddsrt_sockets, gethostname)
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
sysbuf[0] = '\0';
ret = gethostname(sysbuf, sizeof(sysbuf));
#if LWIP_SOCKET
ddsrt_strlcpy(sysbuf, "localhost", sizeof(sysbuf));
#else
int ret = gethostname(sysbuf, sizeof(sysbuf));
CU_ASSERT_EQUAL(ret, 0);
#endif
CU_ASSERT(strcmp(buf, sysbuf) == 0);
rc = ddsrt_gethostname(buf, strlen(buf) - 1);
@ -155,9 +169,9 @@ CU_Test(ddsrt_sockets, gethostname)
}
#if DDSRT_HAVE_DNS
static void gethostbyname_test(char *name, int af, dds_retcode_t exp)
static void gethostbyname_test(char *name, int af, dds_return_t exp)
{
dds_retcode_t rc;
dds_return_t rc;
ddsrt_hostent_t *hent = NULL;
rc = ddsrt_gethostbyname(name, af, &hent);
CU_ASSERT_EQUAL(rc, exp);
@ -169,30 +183,44 @@ static void gethostbyname_test(char *name, int af, dds_retcode_t exp)
}
ddsrt_free(hent);
}
#endif
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_DataPoints(dds_return_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)
CU_Theory((char *name, int af, dds_return_t exp), ddsrt_gethostbyname, ipv4, .init=setup, .fini=teardown)
{
#if DDSRT_HAVE_DNS
gethostbyname_test(name, af, exp);
#else
(void)name;
(void)af;
(void)exp;
CU_PASS("DNS is not supported");
#endif
}
#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) = {
#if DDSRT_HAVE_IPV6 && DDSRT_HAVE_DNS
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_DataPoints(dds_return_t, DDS_RETCODE_HOST_NOT_FOUND, DDS_RETCODE_OK, DDS_RETCODE_OK)
#endif /* DDSRT_HAVE_IPV6 */
};
CU_Theory((char *name, int af, dds_retcode_t exp), ddsrt_gethostbyname, ipv6, .init=setup, .fini=teardown)
CU_Theory((char *name, int af, dds_return_t exp), ddsrt_gethostbyname, ipv6, .init=setup, .fini=teardown)
{
#if DDSRT_HAVE_IPV6 && DDSRT_HAVE_DNS
gethostbyname_test(name, af, exp);
}
#else
(void)name;
(void)af;
(void)exp;
CU_PASS("DNS and IPv6 are not supported");
#endif /* DDSRT_HAVE_IPV6 */
#endif /* DDSRT_HAVE_DNS */
}

Some files were not shown because too many files have changed in this diff Show more