Add support for FreeRTOS and lwIP (#166)

Add support for FreeRTOS and lwIP

Signed-off-by: Jeroen Koekkoek <jeroen@koekkoek.nl>
This commit is contained in:
Jeroen Koekkoek 2019-05-23 14:27:56 +02:00 committed by eboasson
parent dba4e6d391
commit aa2715f4fe
67 changed files with 3691 additions and 200 deletions

View file

@ -191,11 +191,9 @@ endif()
add_subdirectory(examples)
if (BUILD_TESTING)
# Multi Process Tests
if(BUILD_TESTING AND HAVE_MULTI_PROCESS)
add_subdirectory(mpt)
endif()
# Pull-in CPack and support for generating <Package>Config.cmake and packages.
include(Packaging)

View file

@ -13,12 +13,8 @@
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <sysexits.h>
#else
#define EX_USAGE (64)
#define EX_SOFTWARE (70)
#endif /* _WIN32 */
#include <CUnit/Basic.h>
#include <CUnit/Automated.h>

View file

@ -11,7 +11,12 @@
#
set(CUNIT_HEADER "CUnit/CUnit.h")
find_path(CUNIT_INCLUDE_DIR ${CUNIT_HEADER})
if(CONAN_INCLUDE_DIRS)
find_path(CUNIT_INCLUDE_DIR ${CUNIT_HEADER} HINTS ${CONAN_INCLUDE_DIRS})
else()
find_path(CUNIT_INCLUDE_DIR ${CUNIT_HEADER})
endif()
mark_as_advanced(CUNIT_INCLUDE_DIR)
if(CUNIT_INCLUDE_DIR AND EXISTS "${CUNIT_INCLUDE_DIR}/${CUNIT_HEADER}")
@ -25,7 +30,11 @@ if(CUNIT_INCLUDE_DIR AND EXISTS "${CUNIT_INCLUDE_DIR}/${CUNIT_HEADER}")
set(CUNIT_VERSION "${CUNIT_VERSION_MAJOR}.${CUNIT_VERSION_MINOR}-${CUNIT_VERSION_PATCH}")
endif()
find_library(CUNIT_LIBRARY cunit)
if(CONAN_LIB_DIRS)
find_library(CUNIT_LIBRARY cunit HINTS ${CONAN_LIB_DIRS})
else()
find_library(CUNIT_LIBRARY cunit)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(

View file

@ -0,0 +1,51 @@
# 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
function(GENERATE_DUMMY_EXPORT_HEADER _target)
set(_opts)
set(_single_opts BASE_NAME EXPORT_FILE_NAME)
set(_multi_opts)
cmake_parse_arguments(_args "${_opts}" "${_single_opts}" "${_multi_opts}" ${ARGN})
if(NOT _target)
message(FATAL_ERROR "Target not specified")
elseif(NOT TARGET ${_target})
message(FATAL_ERROR "Target ${_target} does not exist")
endif()
string(TOUPPER _target_uc "${_target}")
string(TOLOWER _target_lc "${_target}")
if(_args_EXPORT_FILE_NAME)
set(_path "${_args_EXPORT_FILE_NAME}")
else()
set(_path "${CMAKE_CURRENT_BINARY_DIR}/${_target_lc}_export.h")
endif()
if(_args_BASE_NAME)
string(TOUPPER "${_args_BASE_NAME}" _base_name)
else()
set(_base_name "${_target_uc}")
endif()
get_filename_component(_dir "${_path}" DIRECTORY)
get_filename_component(_file "${_path}" NAME)
if(NOT IS_DIRECTORY "${_dir}")
file(MAKE_DIRECTORY "${_dir}")
endif()
set(_content
"/* Dummy export header generated by CMake. */
#define ${_base_name}_EXPORT\n")
file(WRITE "${_path}" "${_content}")
endfunction()

View file

@ -37,7 +37,7 @@ install(
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}Version.cmake"
DESTINATION "${CMAKE_INSTALL_CMAKEDIR}" COMPONENT dev)
if(DDSC_SHARED AND ((NOT DEFINED BUILD_SHARED_LIBS) OR BUILD_SHARED_LIBS))
if((NOT DEFINED BUILD_SHARED_LIBS) OR BUILD_SHARED_LIBS)
# Generates <Package>Targets.cmake file included by <Package>Config.cmake.
# The files are placed in CMakeFiles/Export in the build tree.
install(

View file

@ -19,16 +19,10 @@ FUNCTION(PREPEND var prefix)
SET(${var} "${listVar}" PARENT_SCOPE)
ENDFUNCTION(PREPEND)
option(DDSC_SHARED "Build DDSC as a shared library" ON)
if(DDSC_SHARED AND ((NOT DEFINED BUILD_SHARED_LIBS) OR BUILD_SHARED_LIBS))
# BUILD_SHARED_LIBS is set to off by for example VxWorks DKM environment
add_library(ddsc SHARED "")
if (BUILD_SHARED_LIBS OR NOT DEFINED BUILD_SHARED_LIBS)
add_library(ddsc SHARED)
else()
if(DDSC_SHARED)
message(STATUS "Option DDSC_SHARED ignored. Only static libraries supported on this platform.")
endif()
add_library(ddsc "")
add_library(ddsc)
endif()
add_definitions(-DDDSI_INCLUDE_NETWORK_PARTITIONS -DDDSI_INCLUDE_SSM)

View file

@ -92,7 +92,6 @@ CU_Test(ddsc_participant, create_with_conf_no_env) {
//invalid domain
participant = dds_create_participant (1, NULL, NULL);
printf("\n participant is %d\n", participant);
CU_ASSERT_FATAL(participant < 0);
//valid specific domain value

View file

@ -23,6 +23,7 @@ extern "C" {
#endif
/* LOG_THREAD_CPUTIME must be considered private. */
#if DDSRT_HAVE_RUSAGE
#define LOG_THREAD_CPUTIME(guard) \
do { \
if (dds_get_log_mask() & DDS_LC_TIMING) { \
@ -40,6 +41,9 @@ extern "C" {
} \
} \
} while (0)
#else
#define LOG_THREAD_CPUTIME(guard) (void)(guard)
#endif /* DDSRT_HAVE_RUSAGE */
#if defined (__cplusplus)
}

View file

@ -24,7 +24,7 @@
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/sockets.h"
#ifdef __linux
#if defined(__linux) && !LWIP_SOCKET
#include <linux/if_packet.h>
#include <sys/types.h>
#include <ifaddrs.h>

View file

@ -368,7 +368,13 @@ static bool ddsi_tcp_select (ddsrt_socket_t sock, bool read, size_t pos)
int32_t ready = 0;
FD_ZERO (&fds);
#if LWIP_SOCKET == 1
DDSRT_WARNING_GNUC_OFF(sign-conversion)
#endif
FD_SET (sock, &fds);
#if LWIP_SOCKET == 1
DDSRT_WARNING_GNUC_ON(sign-conversion)
#endif
DDS_LOG(DDS_LC_TCP, "%s blocked %s: sock %d\n", ddsi_name, read ? "read" : "write", (int) sock);
do {

View file

@ -118,13 +118,14 @@ static uint32_t threadmon_thread (struct ddsi_threadmon *sl)
was_alive = false;
}
#if DDSRT_HAVE_RUSAGE
if (dds_get_log_mask() & DDS_LC_TIMING)
{
ddsrt_rusage_t u;
if (ddsrt_getrusage (DDSRT_RUSAGE_SELF, &u) == DDS_RETCODE_OK)
{
DDS_LOG(DDS_LC_TIMING,
"rusage: utime %d.%09d stime %d.%09d maxrss %ld data %ld vcsw %ld ivcsw %ld\n",
"rusage: utime %d.%09d stime %d.%09d maxrss %zu data %zu vcsw %zu ivcsw %zu\n",
(int) (u.utime / DDS_NSECS_IN_SEC),
(int) (u.utime % DDS_NSECS_IN_SEC),
(int) (u.stime / DDS_NSECS_IN_SEC),
@ -132,6 +133,7 @@ static uint32_t threadmon_thread (struct ddsi_threadmon *sl)
u.maxrss, u.idrss, u.nvcsw, u.nivcsw);
}
}
#endif /* DDSRT_HAVE_RUSAGE */
/* While deaf, we need to make sure the receive thread wakes up
every now and then to try recreating sockets & rejoining multicast

View file

@ -138,9 +138,10 @@ static ssize_t ddsi_udp_conn_write (ddsi_tran_conn_t conn, const nn_locator_t *d
#if DDSRT_MSGHDR_FLAGS
msg.msg_flags = (int) flags;
#else
msg.msg_flags = 0;
DDSRT_UNUSED_ARG(flags);
#endif
#ifdef MSG_NOSIGNAL
#if MSG_NOSIGNAL && !LWIP_SOCKET
sendflags |= MSG_NOSIGNAL;
#endif
do {

View file

@ -96,12 +96,18 @@ static int set_rcvbuf (ddsrt_socket_t socket)
uint32_t ReceiveBufferSize;
socklen_t optlen = (socklen_t) sizeof (ReceiveBufferSize);
uint32_t socket_min_rcvbuf_size;
dds_retcode_t rc;
if (config.socket_min_rcvbuf_size.isdefault)
socket_min_rcvbuf_size = 1048576;
else
socket_min_rcvbuf_size = config.socket_min_rcvbuf_size.value;
if (ddsrt_getsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) &ReceiveBufferSize, &optlen) != DDS_RETCODE_OK)
{
rc = ddsrt_getsockopt(
socket, SOL_SOCKET, SO_RCVBUF, (char *) &ReceiveBufferSize, &optlen);
/* TCP/IP stack may not support SO_RCVBUF. */
if (rc == DDS_RETCODE_BAD_PARAMETER) {
DDS_LOG(DDS_LC_CONFIG, "cannot retrieve socket receive buffer size\n");
return 0;
} else if (rc != DDS_RETCODE_OK) {
print_sockerror ("get SO_RCVBUF");
return -2;
}
@ -139,8 +145,13 @@ static int set_sndbuf (ddsrt_socket_t socket)
{
unsigned SendBufferSize;
socklen_t optlen = (socklen_t) sizeof(SendBufferSize);
if (ddsrt_getsockopt(socket, SOL_SOCKET, SO_SNDBUF,(char *)&SendBufferSize, &optlen) != DDS_RETCODE_OK)
{
dds_retcode_t rc;
rc = ddsrt_getsockopt(
socket, SOL_SOCKET, SO_SNDBUF,(char *)&SendBufferSize, &optlen);
if (rc == DDS_RETCODE_BAD_PARAMETER) {
DDS_LOG(DDS_LC_CONFIG, "cannot retrieve socket send buffer size\n");
return 0;
} else if (rc != DDS_RETCODE_OK) {
print_sockerror ("get SO_SNDBUF");
return -2;
}
@ -191,12 +202,16 @@ static int set_reuse_options (ddsrt_socket_t socket)
/* Set REUSEADDR (if available on platform) for
multicast sockets, leave unicast sockets alone. */
int one = 1;
if (ddsrt_setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof (one)) != DDS_RETCODE_OK)
{
dds_retcode_t rc = ddsrt_setsockopt (
socket, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof (one));
if (rc == DDS_RETCODE_BAD_PARAMETER) {
DDS_LOG(DDS_LC_CONFIG, "cannot enable address reuse on socket\n");
return 0;
} else if (rc != DDS_RETCODE_OK) {
print_sockerror ("SO_REUSEADDR");
return -2;
}
return 0;
}
@ -266,7 +281,7 @@ static int set_mc_options_transmit_ipv4 (ddsrt_socket_t socket)
unsigned char loop;
dds_retcode_t ret;
#if defined __linux || defined __APPLE__
#if (defined(__linux) || defined(__APPLE__)) && !LWIP_SOCKET
if (config.use_multicast_if_mreqn)
{
struct ip_mreqn mreqn;
@ -470,7 +485,7 @@ int find_own_ip (const char *requested_address)
continue;
}
#ifdef __linux
#if defined(__linux) && !LWIP_SOCKET
if (ifa->addr->sa_family == AF_PACKET)
{
/* FIXME: weirdo warning warranted */

View file

@ -509,7 +509,7 @@ int os_sockWaitsetNextEvent (os_sockWaitsetCtx ctx, ddsi_tran_conn_t * conn)
#define OSPL_PIPENAMESIZE 26
#endif
#ifndef _WIN32
#if !_WIN32 && !LWIP_SOCKET
#ifndef __VXWORKS__
#include <sys/fcntl.h>
@ -524,7 +524,7 @@ int os_sockWaitsetNextEvent (os_sockWaitsetCtx ctx, ddsi_tran_conn_t * conn)
#include <fcntl.h>
#endif
#endif /* _WIN32 */
#endif /* !_WIN32 && !LWIP_SOCKET */
typedef struct os_sockWaitsetSet
{
@ -586,7 +586,7 @@ fail:
closesocket (s2);
return -1;
}
#elif defined (VXWORKS_RTP) || defined (_WRS_KERNEL)
#elif defined(__VXWORKS__)
static int make_pipe (int pfd[2])
{
char pipename[OSPL_PIPENAMESIZE];
@ -609,7 +609,7 @@ fail_open0:
fail_pipedev:
return -1;
}
#else
#elif !defined(LWIP_SOCKET)
static int make_pipe (int pfd[2])
{
return pipe (pfd);
@ -644,7 +644,11 @@ os_sockWaitset os_sockWaitsetNew (void)
ws->fdmax_plus_1 = FD_SETSIZE;
#endif
#if defined (VXWORKS_RTP) || defined (_WRS_KERNEL)
#if defined(LWIP_SOCKET)
ws->pipe[0] = -1;
ws->pipe[1] = -1;
result = 0;
#elif defined(__VXWORKS__)
int make_pipe (int pfd[2])
{
char pipename[OSPL_PIPENAMESIZE];
@ -679,15 +683,21 @@ os_sockWaitset os_sockWaitsetNew (void)
assert (result != -1);
(void) result;
#if !defined(LWIP_SOCKET)
ws->set.fds[0] = ws->pipe[0];
#else
ws->set.fds[0] = 0;
#endif
ws->set.conns[0] = NULL;
#if ! defined (VXWORKS_RTP) && ! defined ( _WRS_KERNEL ) && ! defined (_WIN32)
#if !defined(__VXWORKS__) && !defined(_WIN32) && !defined(LWIP_SOCKET)
fcntl (ws->pipe[0], F_SETFD, fcntl (ws->pipe[0], F_GETFD) | FD_CLOEXEC);
fcntl (ws->pipe[1], F_SETFD, fcntl (ws->pipe[1], F_GETFD) | FD_CLOEXEC);
#endif
#if !defined(LWIP_SOCKET)
FD_SET (ws->set.fds[0], &ws->ctx.rdset);
#if ! defined (_WIN32)
#endif
#if !defined(_WIN32)
ws->fdmax_plus_1 = ws->set.fds[0] + 1;
#endif
@ -716,18 +726,18 @@ static void os_sockWaitsetFreeCtx (os_sockWaitsetCtx ctx)
void os_sockWaitsetFree (os_sockWaitset ws)
{
#ifdef VXWORKS_RTP
#if defined(__VXWORKS__) && defined(__RTP__)
char nameBuf[OSPL_PIPENAMESIZE];
ioctl (ws->pipe[0], FIOGETNAME, &nameBuf);
#endif
#if defined (_WIN32)
#if defined(_WIN32)
closesocket (ws->pipe[0]);
closesocket (ws->pipe[1]);
#else
#elif !defined(LWIP_SOCKET)
close (ws->pipe[0]);
close (ws->pipe[1]);
#endif
#ifdef VXWORKS_RTP
#if defined(__VXWORKS__) && defined(__RTP__)
pipeDevDelete ((char*) &nameBuf, 0);
#endif
os_sockWaitsetFreeSet (&ws->set);
@ -738,6 +748,9 @@ void os_sockWaitsetFree (os_sockWaitset ws)
void os_sockWaitsetTrigger (os_sockWaitset ws)
{
#if defined(LWIP_SOCKET)
(void)ws;
#else
char buf = 0;
int n;
@ -750,6 +763,7 @@ void os_sockWaitsetTrigger (os_sockWaitset ws)
{
DDS_WARNING("os_sockWaitsetTrigger: write failed on trigger pipe\n");
}
#endif
}
int os_sockWaitsetAdd (os_sockWaitset ws, ddsi_tran_conn_t conn)
@ -863,10 +877,19 @@ os_sockWaitsetCtx os_sockWaitsetWait (os_sockWaitset ws)
rdset = &ctx->rdset;
FD_ZERO (rdset);
#if !defined(LWIP_SOCKET)
for (u = 0; u < dst->n; u++)
{
FD_SET (dst->fds[u], rdset);
}
#else
for (u = 1; u < dst->n; u++)
{
DDSRT_WARNING_GNUC_OFF(sign-conversion)
FD_SET (dst->fds[u], rdset);
DDSRT_WARNING_GNUC_ON(sign-conversion)
}
#endif /* LWIP_SOCKET */
do
{
@ -883,6 +906,7 @@ os_sockWaitsetCtx os_sockWaitsetWait (os_sockWaitset ws)
{
/* this simply skips the trigger fd */
ctx->index = 1;
#if ! defined(LWIP_SOCKET)
if (FD_ISSET (dst->fds[0], rdset))
{
char buf;
@ -898,19 +922,26 @@ os_sockWaitsetCtx os_sockWaitsetWait (os_sockWaitset ws)
assert (0);
}
}
#endif /* LWIP_SOCKET */
return ctx;
}
return NULL;
}
#if defined(LWIP_SOCKET)
DDSRT_WARNING_GNUC_OFF(sign-conversion)
#endif
int os_sockWaitsetNextEvent (os_sockWaitsetCtx ctx, ddsi_tran_conn_t * conn)
{
while (ctx->index < ctx->set.n)
{
unsigned idx = ctx->index++;
ddsrt_socket_t fd = ctx->set.fds[idx];
#if ! defined (LWIP_SOCKET)
assert(idx > 0);
#endif
if (FD_ISSET (fd, &ctx->rdset))
{
*conn = ctx->set.conns[idx];
@ -921,6 +952,10 @@ int os_sockWaitsetNextEvent (os_sockWaitsetCtx ctx, ddsi_tran_conn_t * conn)
return -1;
}
#if defined(LWIP_SOCKET)
DDSRT_WARNING_GNUC_ON(sign-conversion)
#endif
#else
#error "no mode selected"
#endif

View file

@ -20,7 +20,7 @@
#include "dds/ddsi/q_config.h"
#include "dds/ddsi/sysdeps.h"
#if !(defined __APPLE__ || defined __linux) || (__GNUC__ > 0 && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40100)
#if DDSRT_WITH_FREERTOS || !(defined __APPLE__ || defined __linux) || (__GNUC__ > 0 && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40100)
void log_stacktrace (const char *name, ddsrt_thread_t tid)
{
DDSRT_UNUSED_ARG (name);

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>"
@ -124,10 +167,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})
@ -137,7 +179,15 @@ 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")
@ -173,9 +223,13 @@ endforeach()
target_sources(ddsrt INTERFACE ${sources})
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
target_link_libraries(ddsrt INTERFACE Threads::Threads)
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)
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/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_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

@ -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

@ -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.
@ -205,6 +217,7 @@ DDS_EXPORT dds_retcode_t
ddsrt_proc_kill(
ddsrt_pid_t pid);
#endif /* DDSRT_HAVE_MULTI_PROCESS */
#if defined (__cplusplus)
}

View file

@ -14,6 +14,18 @@
#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
#else
# define DDSRT_HAVE_RUSAGE 1
#endif
#include "dds/ddsrt/time.h"
#include "dds/ddsrt/retcode.h"

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"

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 <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,38 @@ 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
# endif
# define DDSRT_HAVE_SSM 0
# define IFF_UP 0x1
# define IFF_BROADCAST 0x2
# define IFF_LOOPBACK 0x8
# define IFF_POINTOPOINT 0x10
# define IFF_MULTICAST 0x1000
#else /* LWIP_SOCKET */
# define DDSRT_HAVE_IPV6 1
# define DDSRT_HAVE_DNS DDSRT_WITH_DNS
# define DDSRT_HAVE_SSM 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

@ -13,7 +13,7 @@ typedef SOCKET ddsrt_socket_t;
#define PRIdSOCK PRIuPTR
#define DDSRT_HAVE_IPV6 1
#define DDSRT_HAVE_DNS 1
#define DDSRT_HAVE_DNS DDSRT_WITH_DNS
#if defined(NTDDI_VERSION) && \
defined(_WIN32_WINNT_WS03) && \

View file

@ -18,7 +18,9 @@
#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"
#else
#include "dds/ddsrt/sync/posix.h"

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

@ -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"
@ -206,9 +208,11 @@ 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
/**
* @brief Push cleanup handler onto the cleanup stack

View file

@ -0,0 +1,35 @@
/*
* 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)
#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,12 @@
#include <pthread.h>
#if defined(__VXWORKS__)
#define DDSRT_HAVE_THREAD_SETNAME (0)
#else
#define DDSRT_HAVE_THREAD_SETNAME (1)
#endif
#if defined (__cplusplus)
extern "C" {
#endif

View file

@ -14,6 +14,8 @@
#include "dds/ddsrt/types.h"
#define DDSRT_HAVE_THREAD_SETNAME (1)
#if defined (__cplusplus)
extern "C" {
#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

@ -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

@ -0,0 +1,207 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#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_retcode_t
copyaddr(
ddsrt_ifaddrs_t **ifap,
const struct netif *netif,
const ip_addr_t *addr)
{
dds_retcode_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;
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_retcode_t
ddsrt_getifaddrs(
ddsrt_ifaddrs_t **ifap,
const int *afs)
{
dds_retcode_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

@ -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

@ -0,0 +1,96 @@
/*
* 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_retcode_t
rusage_self(ddsrt_rusage_t *usage)
{
dds_retcode_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_retcode_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;
}
dds_retcode_t
ddsrt_getrusage(int who, ddsrt_rusage_t *usage)
{
dds_retcode_t rc;
assert(who == DDSRT_RUSAGE_SELF || who == DDSRT_RUSAGE_THREAD);
assert(usage != NULL);
if (who == DDSRT_RUSAGE_THREAD) {
rc = rusage_thread(usage);
} else {
rc = rusage_self(usage);
}
return rc;
}

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;
@ -218,6 +220,9 @@ dds_retcode_t ddsrt_sockaddrtostr(const void *sa, char *buf, size_t size)
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:
ptr = inet_ntop(
@ -232,6 +237,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;
@ -312,10 +320,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;

View file

@ -52,10 +52,10 @@ 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);
if (DDSRT_TIME_T_MAX == INT32_MAX) {
max_nsecs = INT32_MAX * DDS_NSECS_IN_SEC;
} else {
assert(DDSRT_TIME_T_MAX == INT64_MAX);
max_nsecs = DDSRT_TIME_T_MAX / DDS_NSECS_IN_SEC;
}

View file

@ -10,21 +10,41 @@
* 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"
#if LWIP_SOCKET
dds_retcode_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
dds_retcode_t
ddsrt_gethostname(
char *name,
@ -59,3 +79,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,10 +35,7 @@
#ifdef __APPLE__
#include <sys/sockio.h>
#endif /* __APPLE__ */
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/sockets_priv.h"
#endif /* LWIP_SOCKET */
dds_retcode_t
ddsrt_socket(ddsrt_socket_t *sockptr, int domain, int type, int protocol)
@ -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;
@ -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:
@ -405,6 +425,24 @@ ddsrt_recv(
return recv_error_to_retcode(errno);
}
#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_retcode_t
ddsrt_recvmsg(
ddsrt_socket_t sock,

View file

@ -0,0 +1,469 @@
/*
* 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) {
DDS_TRACE("Failed to lock 0x%p", mutex);
/* 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)) {
abort();
}
}
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_TRACE("Failed to unlock 0x%p", mutex->sem);
abort();
}
}
static dds_retcode_t
cond_timedwait(
ddsrt_cond_t *cond,
ddsrt_mutex_t *mutex,
dds_duration_t reltime)
{
dds_retcode_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_retcode_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_retcode_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,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_retcode_t
thread_context_create(thread_context_t **ctxptr)
{
dds_retcode_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_retcode_t
thread_context_acquire(thread_context_t **ctxptr)
{
dds_retcode_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_retcode_t
ddsrt_thread_create(
ddsrt_thread_t *thread,
const char *name,
const ddsrt_threadattr_t *attr,
ddsrt_thread_routine_t start_routine,
void *arg)
{
dds_retcode_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_retcode_t
ddsrt_thread_join(ddsrt_thread_t thread, uint32_t *thread_result)
{
dds_retcode_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_retcode_t
ddsrt_thread_cleanup_push(void (*routine)(void *), void *arg)
{
dds_retcode_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_retcode_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

@ -31,6 +31,12 @@
#include "dds/ddsrt/threads_priv.h"
#include "dds/ddsrt/types.h"
typedef struct {
char *name;
ddsrt_thread_routine_t routine;
void *arg;
} thread_context_t;
#if defined(__linux)
#include <sys/syscall.h>
#define MAXTHREADNAMESIZE (15) /* 16 bytes including null-terminating byte. */

View file

@ -16,6 +16,12 @@
#include "dds/ddsrt/string.h"
#include "dds/ddsrt/threads_priv.h"
typedef struct {
char *name;
ddsrt_thread_routine_t routine;
void *arg;
} thread_context_t;
static uint32_t
os_startRoutineWrapper(
void *threadContext)

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)

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

@ -10,59 +10,63 @@
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
include(CUnit)
include(GenerateDummyExportHeader)
set(sources
"atomics.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"
"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>")
generate_dummy_export_header(
cunit_ddsrt
BASE_NAME dds
EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/include/dds/export.h")
# 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)
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

@ -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
@ -117,9 +117,9 @@ 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;
int have_ipv6 = 0;
@ -149,12 +149,16 @@ 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;
int have_ipv4 = 0;
@ -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,7 +347,6 @@ 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;
@ -357,7 +356,6 @@ CU_Test(dds_log, synchronous_sink_changes, .fini=reset)
(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

@ -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)
{
@ -139,7 +139,7 @@ static const char mesg[] = "foobar";
static uint32_t select_timeout_routine(void *ptr)
{
int cnt = -1;
int32_t cnt = -1;
dds_retcode_t rc;
dds_time_t before, after;
dds_duration_t delay;
@ -148,7 +148,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 +163,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;
@ -207,13 +217,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);
@ -260,7 +276,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 +290,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);

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
@ -79,8 +79,8 @@ CU_Theory((char *str, int af, dds_retcode_t exp), ddsrt_sockaddrfromstr, ipv4, .
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"),
@ -90,13 +90,20 @@ CU_TheoryDataPoints(ddsrt_sockaddrfromstr, ipv6) = {
CU_DataPoints(dds_retcode_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)
{
#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)
{
@ -128,16 +135,19 @@ CU_Test(ddsrt_sockaddrtostr, ipv4)
CU_Test(ddsrt_sockaddrtostr, ipv6)
{
#if DDSRT_HAVE_IPV6
dds_retcode_t rc;
char buf[128] = { 0 };
rc = ddsrt_sockaddrtostr(&ipv6_loopback, buf, sizeof(buf));
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
CU_ASSERT_STRING_EQUAL(buf, "::1");
#else
CU_PASS("IPv6 is not supported");
#endif
}
CU_Test(ddsrt_sockets, gethostname)
{
int ret;
dds_retcode_t rc;
char sysbuf[200], buf[200];
@ -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);
@ -169,6 +183,7 @@ 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"),
@ -178,21 +193,34 @@ CU_TheoryDataPoints(ddsrt_gethostbyname, ipv4) = {
CU_Theory((char *name, int af, dds_retcode_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)
#endif /* DDSRT_HAVE_IPV6 */
};
CU_Theory((char *name, int af, dds_retcode_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 */
}

View file

@ -270,7 +270,7 @@ static uint32_t waitfor_routine(void *ptr)
reltime = after - before;
fprintf(stderr, "waited for %"PRId64" (nanoseconds)\n", reltime);
fprintf(stderr, "expected to wait %"PRId64" (nanoseconds)\n", arg->reltime);
fprintf(stderr, "woke up %u times\n", cnt);
fprintf(stderr, "woke up %"PRIu32" times\n", cnt);
ddsrt_mutex_unlock(&arg->lock);
if (reltime >= arg->reltime) {
/* Ensure that the condition variable at least waited for the amount of
@ -322,7 +322,7 @@ static uint32_t waituntil_routine(void *ptr)
ddsrt_mutex_unlock(&arg->lock);
fprintf(stderr, "waited until %"PRId64" (nanoseconds)\n", after);
fprintf(stderr, "expected to wait until %"PRId64" (nanoseconds)\n", arg->abstime);
fprintf(stderr, "woke up %u times\n", cnt);
fprintf(stderr, "woke up %"PRIu32" times\n", cnt);
if (after > arg->abstime) {
res = cnt < 3; /* An arbitrary number to ensure the implementation
did not just spin, aka is completely broken. */

341
src/ddsrt/tests/tasklist.c Normal file
View file

@ -0,0 +1,341 @@
/*
* 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/sync.h"
#include "CUnit/Theory.h"
/* FreeRTOS specific! */
static void fill(ddsrt_tasklist_t *list)
{
CU_ASSERT_PTR_NOT_NULL_FATAL(list);
CU_ASSERT_EQUAL_FATAL(list->len, DDSRT_TASKLIST_INITIAL);
for (size_t i = 1; i <= DDSRT_TASKLIST_INITIAL; i++) {
ddsrt_tasklist_push(list, (TaskHandle_t)i);
CU_ASSERT_EQUAL_FATAL(list->cnt, i);
CU_ASSERT_EQUAL_FATAL(list->off, 0);
CU_ASSERT_EQUAL_FATAL(list->end, i - 1);
}
CU_ASSERT_EQUAL_FATAL(list->len, DDSRT_TASKLIST_INITIAL);
CU_ASSERT_EQUAL_FATAL(list->cnt, DDSRT_TASKLIST_INITIAL);
CU_ASSERT_EQUAL_FATAL(list->off, 0);
CU_ASSERT_EQUAL_FATAL(list->end, DDSRT_TASKLIST_INITIAL - 1);
}
static void fill_wrapped(ddsrt_tasklist_t *list)
{
size_t i;
fill(list);
for (i = 1; i <= DDSRT_TASKLIST_CHUNK; i++) {
ddsrt_tasklist_pop(list, NULL);
CU_ASSERT_EQUAL_FATAL(list->cnt, DDSRT_TASKLIST_INITIAL - i);
CU_ASSERT_EQUAL_FATAL(list->off, i);
CU_ASSERT_EQUAL_FATAL(list->end, DDSRT_TASKLIST_INITIAL - 1);
}
for (i = (DDSRT_TASKLIST_INITIAL+1); i <= (DDSRT_TASKLIST_INITIAL+DDSRT_TASKLIST_CHUNK); i++) {
ddsrt_tasklist_push(list, (TaskHandle_t)i);
CU_ASSERT_EQUAL_FATAL(list->cnt, i - DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL_FATAL(list->off, DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL_FATAL(list->end, (i - 1) - DDSRT_TASKLIST_INITIAL);
}
CU_ASSERT_EQUAL_FATAL(list->len, DDSRT_TASKLIST_INITIAL);
CU_ASSERT_EQUAL_FATAL(list->cnt, DDSRT_TASKLIST_INITIAL);
CU_ASSERT_EQUAL_FATAL(list->off, DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL_FATAL(list->end, DDSRT_TASKLIST_CHUNK - 1);
}
typedef void(*fill_t)(ddsrt_tasklist_t *);
CU_TheoryDataPoints(ddsrt_sync, tasklist_pop_all) = {
CU_DataPoints(fill_t, &fill, &fill_wrapped),
CU_DataPoints(size_t, 1, DDSRT_TASKLIST_CHUNK + 1),
CU_DataPoints(size_t, DDSRT_TASKLIST_INITIAL, DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK)
};
/* Most basic test to verify behavior is correct for simple use case. */
CU_Theory((fill_t func, size_t first, size_t last), ddsrt_sync, tasklist_pop_all)
{
TaskHandle_t task;
ddsrt_tasklist_t list;
ddsrt_tasklist_init(&list);
func(&list);
task = ddsrt_tasklist_pop(&list, NULL);
CU_ASSERT_PTR_EQUAL(task, (TaskHandle_t)first);
for (size_t i = first + 1; i < last; i++) {
task = ddsrt_tasklist_pop(&list, NULL);
CU_ASSERT_PTR_EQUAL(task, (TaskHandle_t)i);
}
CU_ASSERT_EQUAL(list.cnt, 1);
CU_ASSERT_EQUAL(list.off, ((DDSRT_TASKLIST_INITIAL*2) - last) - 1);
CU_ASSERT_EQUAL(list.end, ((DDSRT_TASKLIST_INITIAL*2) - last) - 1);
task = ddsrt_tasklist_pop(&list, NULL);
CU_ASSERT_PTR_EQUAL(task, (TaskHandle_t)last);
task = ddsrt_tasklist_pop(&list, NULL);
CU_ASSERT_PTR_NULL(task);
CU_ASSERT_EQUAL(list.cnt, 0);
CU_ASSERT_EQUAL(list.off, 0);
CU_ASSERT_EQUAL(list.end, 0);
ddsrt_tasklist_fini(&list);
}
CU_TheoryDataPoints(ddsrt_sync, tasklist_pop_n_push) = {
CU_DataPoints(fill_t,
&fill, &fill, &fill, &fill,
&fill_wrapped, &fill_wrapped, &fill_wrapped, &fill_wrapped, &fill_wrapped),
CU_DataPoints(TaskHandle_t, /* Task to pop. */
(TaskHandle_t)NULL,
(TaskHandle_t)1,
(TaskHandle_t)DDSRT_TASKLIST_CHUNK,
(TaskHandle_t)DDSRT_TASKLIST_INITIAL,
(TaskHandle_t)NULL,
(TaskHandle_t)(DDSRT_TASKLIST_CHUNK + 1),
(TaskHandle_t)DDSRT_TASKLIST_INITIAL,
(TaskHandle_t)(DDSRT_TASKLIST_INITIAL + 1),
(TaskHandle_t)(DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK)),
CU_DataPoints(size_t, /* Expected position to clear. */
0, 0, DDSRT_TASKLIST_CHUNK - 1, DDSRT_TASKLIST_INITIAL - 1,
DDSRT_TASKLIST_CHUNK, DDSRT_TASKLIST_CHUNK, DDSRT_TASKLIST_INITIAL - 1, 0, DDSRT_TASKLIST_CHUNK - 1),
CU_DataPoints(size_t, /* Expected position of pushed task. */
0, 0, DDSRT_TASKLIST_INITIAL - 1, DDSRT_TASKLIST_INITIAL - 1,
DDSRT_TASKLIST_CHUNK, DDSRT_TASKLIST_CHUNK, DDSRT_TASKLIST_CHUNK, DDSRT_TASKLIST_CHUNK - 1, DDSRT_TASKLIST_CHUNK - 1)
};
/* Test to verify tasklist is correctly updated (trimmed and packed) when the
tasklist is sparse. */
CU_Theory((fill_t func, TaskHandle_t task, size_t pos, size_t end), ddsrt_sync, tasklist_pop_n_push)
{
ddsrt_tasklist_t list;
ddsrt_tasklist_init(&list);
func(&list);
if (task == NULL) {
ddsrt_tasklist_pop(&list, NULL);
} else {
CU_ASSERT_PTR_EQUAL(ddsrt_tasklist_pop(&list, task), task);
CU_ASSERT_PTR_NULL(ddsrt_tasklist_pop(&list, task));
}
CU_ASSERT_PTR_EQUAL(list.tasks[pos], NULL);
task = (TaskHandle_t)(DDSRT_TASKLIST_INITIAL*2);
CU_ASSERT_NOT_EQUAL_FATAL(ddsrt_tasklist_push(&list, task), -1);
CU_ASSERT_PTR_EQUAL(list.tasks[end], task);
CU_ASSERT_EQUAL(list.len, DDSRT_TASKLIST_INITIAL);
CU_ASSERT_EQUAL(list.cnt, DDSRT_TASKLIST_INITIAL);
ddsrt_tasklist_fini(&list);
}
CU_Test(ddsrt_sync, tasklist_ltrim)
{
ddsrt_tasklist_t list;
ddsrt_tasklist_init(&list);
fill(&list);
ddsrt_tasklist_pop(&list, (TaskHandle_t)2);
ddsrt_tasklist_pop(&list, (TaskHandle_t)3);
CU_ASSERT_EQUAL(list.cnt, DDSRT_TASKLIST_INITIAL - 2);
CU_ASSERT_EQUAL(list.off, 0);
CU_ASSERT_EQUAL(list.end, 9);
ddsrt_tasklist_pop(&list, (TaskHandle_t)1);
CU_ASSERT_EQUAL(list.cnt, DDSRT_TASKLIST_INITIAL - 3);
CU_ASSERT_EQUAL(list.off, 3);
CU_ASSERT_EQUAL(list.end, 9);
ddsrt_tasklist_fini(&list);
}
CU_Test(ddsrt_sync, tasklist_rtrim)
{
ddsrt_tasklist_t list;
ddsrt_tasklist_init(&list);
fill(&list);
ddsrt_tasklist_pop(&list, (TaskHandle_t)(DDSRT_TASKLIST_INITIAL - 1));
ddsrt_tasklist_pop(&list, (TaskHandle_t)(DDSRT_TASKLIST_INITIAL - 2));
CU_ASSERT_EQUAL(list.cnt, DDSRT_TASKLIST_INITIAL - 2);
CU_ASSERT_EQUAL(list.off, 0);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_INITIAL - 1);
ddsrt_tasklist_pop(&list, (TaskHandle_t)DDSRT_TASKLIST_INITIAL);
CU_ASSERT_EQUAL(list.cnt, DDSRT_TASKLIST_INITIAL - 3);
CU_ASSERT_EQUAL(list.off, 0);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_INITIAL - 4);
ddsrt_tasklist_fini(&list);
}
CU_Test(ddsrt_sync, tasklist_wrapped_ltrim)
{
ddsrt_tasklist_t list;
ddsrt_tasklist_init(&list);
fill_wrapped(&list);
for (size_t i = DDSRT_TASKLIST_CHUNK+2; i < DDSRT_TASKLIST_INITIAL; i++) {
ddsrt_tasklist_pop(&list, (TaskHandle_t)i);
}
CU_ASSERT_EQUAL(list.cnt, DDSRT_TASKLIST_INITIAL - (DDSRT_TASKLIST_CHUNK - 2));
CU_ASSERT_EQUAL(list.off, DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_CHUNK - 1);
ddsrt_tasklist_pop(&list, (TaskHandle_t)(DDSRT_TASKLIST_CHUNK+1));
CU_ASSERT_EQUAL(list.cnt, DDSRT_TASKLIST_INITIAL - (DDSRT_TASKLIST_CHUNK - 1));
CU_ASSERT_EQUAL(list.off, DDSRT_TASKLIST_INITIAL - 1);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_CHUNK - 1);
ddsrt_tasklist_pop(&list, (TaskHandle_t)(DDSRT_TASKLIST_INITIAL+1));
ddsrt_tasklist_pop(&list, (TaskHandle_t)DDSRT_TASKLIST_INITIAL);
CU_ASSERT_EQUAL(list.cnt, DDSRT_TASKLIST_INITIAL - (DDSRT_TASKLIST_CHUNK + 1));
CU_ASSERT_EQUAL(list.off, 1);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_CHUNK - 1);
ddsrt_tasklist_fini(&list);
}
CU_Test(ddsrt_sync, tasklist_wrapped_rtrim)
{
ddsrt_tasklist_t list;
size_t last = DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK;
ddsrt_tasklist_init(&list);
fill_wrapped(&list);
for (size_t i = last - 1; i > DDSRT_TASKLIST_INITIAL + 1; i--) {
ddsrt_tasklist_pop(&list, (TaskHandle_t)i);
}
CU_ASSERT_EQUAL(list.cnt, (DDSRT_TASKLIST_INITIAL - DDSRT_TASKLIST_CHUNK) + 2);
CU_ASSERT_EQUAL(list.off, DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_CHUNK - 1);
ddsrt_tasklist_pop(&list, (TaskHandle_t)(DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK));
CU_ASSERT_EQUAL(list.cnt, (DDSRT_TASKLIST_INITIAL - DDSRT_TASKLIST_CHUNK) + 1);
CU_ASSERT_EQUAL(list.off, DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL(list.end, 0);
ddsrt_tasklist_pop(&list, (TaskHandle_t)(DDSRT_TASKLIST_INITIAL - 1));
ddsrt_tasklist_pop(&list, (TaskHandle_t)(DDSRT_TASKLIST_INITIAL - 2));
ddsrt_tasklist_pop(&list, (TaskHandle_t)(DDSRT_TASKLIST_INITIAL + 1));
CU_ASSERT_EQUAL(list.cnt, (DDSRT_TASKLIST_INITIAL - DDSRT_TASKLIST_CHUNK) - 2);
CU_ASSERT_EQUAL(list.off, DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_INITIAL - 1);
ddsrt_tasklist_pop(&list, (TaskHandle_t)DDSRT_TASKLIST_INITIAL);
CU_ASSERT_EQUAL(list.cnt, (DDSRT_TASKLIST_INITIAL - DDSRT_TASKLIST_CHUNK) - 3);
CU_ASSERT_EQUAL(list.off, DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_INITIAL - 4);
ddsrt_tasklist_fini(&list);
}
CU_Test(ddsrt_sync, tasklist_resize)
{
ddsrt_tasklist_t list;
int ret;
ddsrt_tasklist_init(&list);
fill(&list);
/* Grow one past initial. Buffer should increase by chunk. */
ret = ddsrt_tasklist_push(&list, (TaskHandle_t)(DDSRT_TASKLIST_INITIAL + 1));
CU_ASSERT_EQUAL_FATAL(ret, 0);
CU_ASSERT_EQUAL(list.len, DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL(list.off, 0);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_INITIAL);
/* Grow one past initial+chunk. Buffer should increase by chunk again. */
for (size_t i = 2; i <= DDSRT_TASKLIST_CHUNK + 1; i++) {
ret = ddsrt_tasklist_push(&list, (TaskHandle_t)(DDSRT_TASKLIST_INITIAL + i));
CU_ASSERT_EQUAL_FATAL(ret, 0);
}
CU_ASSERT_EQUAL(list.len, DDSRT_TASKLIST_INITIAL + (DDSRT_TASKLIST_CHUNK*2));
CU_ASSERT_EQUAL(list.off, 0);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK);
/* Shrink one past initial+chunk. Buffer should not decrease by chunk. */
for (size_t i = 1; i <= DDSRT_TASKLIST_CHUNK; i++) {
ddsrt_tasklist_pop(&list, (TaskHandle_t)i);
}
CU_ASSERT_EQUAL(list.len, DDSRT_TASKLIST_INITIAL + (DDSRT_TASKLIST_CHUNK*2));
CU_ASSERT_EQUAL(list.off, DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK);
/* Shrink to initial. Buffer should decrease by chunk. */
ddsrt_tasklist_pop(&list, (TaskHandle_t)(DDSRT_TASKLIST_CHUNK + 1));
CU_ASSERT_EQUAL(list.len, DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL(list.off, 0);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_INITIAL - 1);
/* Shrink to initial-chunk. Buffer should decrease by chunk. */
for (size_t i = DDSRT_TASKLIST_CHUNK+1; i <= (DDSRT_TASKLIST_CHUNK*2)+1; i++) {
ddsrt_tasklist_pop(&list, (TaskHandle_t)i);
CU_ASSERT_EQUAL_FATAL(ret, 0);
}
CU_ASSERT_EQUAL(list.len, DDSRT_TASKLIST_INITIAL);
CU_ASSERT_EQUAL(list.off, 0);
CU_ASSERT_EQUAL(list.end, (DDSRT_TASKLIST_INITIAL - DDSRT_TASKLIST_CHUNK) - 1);
ddsrt_tasklist_fini(&list);
}
CU_Test(ddsrt_sync, tasklist_wrapped_resize)
{
ddsrt_tasklist_t list;
int ret;
ddsrt_tasklist_init(&list);
fill_wrapped(&list);
/* Grow one past initial. Buffer should increase by chunk. */
ret = ddsrt_tasklist_push(&list, (TaskHandle_t)(DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK + 1));
CU_ASSERT_EQUAL_FATAL(ret, 0);
CU_ASSERT_EQUAL(list.len, DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL(list.off, DDSRT_TASKLIST_INITIAL);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_CHUNK);
/* Grow one past initial+chunk. Buffer should increase by chunk again. */
for (size_t i = 2; i <= (DDSRT_TASKLIST_CHUNK + 1); i++) {
ret = ddsrt_tasklist_push(&list, (TaskHandle_t)(DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK + i));
CU_ASSERT_EQUAL_FATAL(ret, 0);
}
CU_ASSERT_EQUAL(list.len, DDSRT_TASKLIST_INITIAL + (DDSRT_TASKLIST_CHUNK*2));
CU_ASSERT_EQUAL(list.off, DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_INITIAL);
/* Shrink one past initial+chunk. Buffer should not decrease by chunk. */
for (size_t i = 1; i <= DDSRT_TASKLIST_CHUNK; i++) {
ddsrt_tasklist_pop(&list, (TaskHandle_t)(DDSRT_TASKLIST_CHUNK + i));
}
CU_ASSERT_EQUAL(list.len, DDSRT_TASKLIST_INITIAL + (DDSRT_TASKLIST_CHUNK*2));
CU_ASSERT_EQUAL(list.off, 0);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_INITIAL);
/* Shrink to initial. Buffer should decrease by chunk. */
ddsrt_tasklist_pop(&list, (TaskHandle_t)((DDSRT_TASKLIST_CHUNK*2) + 1));
CU_ASSERT_EQUAL(list.len, DDSRT_TASKLIST_INITIAL + DDSRT_TASKLIST_CHUNK);
CU_ASSERT_EQUAL(list.off, 0);
CU_ASSERT_EQUAL(list.end, DDSRT_TASKLIST_INITIAL - 1);
/* Shrink to initial-chunk. Buffer should decrease by chunk. */
for (size_t i = 2; i <= DDSRT_TASKLIST_CHUNK + 1; i++) {
ddsrt_tasklist_pop(&list, (TaskHandle_t)((DDSRT_TASKLIST_CHUNK*2) + i));
}
CU_ASSERT_EQUAL(list.len, DDSRT_TASKLIST_INITIAL);
CU_ASSERT_EQUAL(list.off, 0);
CU_ASSERT_EQUAL(list.end, (DDSRT_TASKLIST_INITIAL - DDSRT_TASKLIST_CHUNK) - 1);
ddsrt_tasklist_fini(&list);
}

View file

@ -11,9 +11,12 @@
*/
#include <assert.h>
#include <stdlib.h>
#if !defined(_WIN32)
#include <sched.h>
#include <unistd.h>
#if DDSRT_WITH_FREERTOS
# include <FreeRTOS.h>
# include <task.h>
#elif !defined(_WIN32)
# include <sched.h>
# include <unistd.h>
#endif
#include "CUnit/Theory.h"
@ -30,7 +33,10 @@ static int32_t min_other_prio = 250;
CU_Init(ddsrt_thread)
{
ddsrt_init();
#if defined(WIN32)
#if DDSRT_WITH_FREERTOS
max_other_prio = max_fifo_prio = configMAX_PRIORITIES - 1;
min_other_prio = min_fifo_prio = tskIDLE_PRIORITY + 1;
#elif defined(WIN32)
max_fifo_prio = THREAD_PRIORITY_HIGHEST;
min_fifo_prio = THREAD_PRIORITY_LOWEST;
max_other_prio = THREAD_PRIORITY_HIGHEST;
@ -68,7 +74,12 @@ uint32_t thread_main(void *ptr)
attr = arg->attr;
#if _WIN32
#if DDSRT_WITH_FREERTOS
int prio = (int)uxTaskPriorityGet(NULL);
if (prio == attr->schedPriority) {
arg->res = 1;
}
#elif _WIN32
int prio = GetThreadPriority(GetCurrentThread());
if (prio == THREAD_PRIORITY_ERROR_RETURN)
abort();
@ -113,7 +124,12 @@ CU_Theory((ddsrt_sched_t sched, int32_t *prio, uint32_t exp), ddsrt_thread, crea
ddsrt_threadattr_t attr;
thread_arg_t arg;
#if defined(__VXWORKS__)
#if DDSRT_WITH_FREERTOS
if (sched == DDSRT_SCHED_TIMESHARE) {
skip = 1;
CU_PASS("FreeRTOS only support SCHED_FIFO");
}
#elif defined(__VXWORKS__)
# if defined(_WRS_KERNEL)
if (sched == DDSRT_SCHED_TIMESHARE) {
skip = 1;
@ -150,7 +166,9 @@ CU_Test(ddsrt_thread, thread_id)
{
int eq = 0;
ddsrt_thread_t thr;
#if defined(_WIN32)
#if DDSRT_WITH_FREERTOS
TaskHandle_t task;
#elif defined(_WIN32)
DWORD _tid;
#else
pthread_t _thr;
@ -158,7 +176,10 @@ CU_Test(ddsrt_thread, thread_id)
thr = ddsrt_thread_self();
#if defined(_WIN32)
#if DDSRT_WITH_FREERTOS
task = xTaskGetCurrentTaskHandle();
eq = (thr.task == task);
#elif defined(_WIN32)
_tid = GetCurrentThreadId();
eq = (thr.tid == _tid);
#else
@ -230,4 +251,3 @@ CU_Test(ddsrt_thread, attribute)
CU_ASSERT_EQUAL(attr.schedPriority, 0);
CU_ASSERT_EQUAL(attr.stackSize, 0);
}

View file

@ -116,7 +116,7 @@ static bool CtrlHandler (DWORD fdwCtrlType)
dds_waitset_set_trigger (waitSet, true);
return true; //Don't let other handlers handle this key
}
#else
#elif !DDSRT_WITH_FREERTOS
static void CtrlHandler (int sig)
{
(void)sig;
@ -249,7 +249,7 @@ int main (int argc, char *argv[])
/* Register handler for Ctrl-C */
#ifdef _WIN32
SetConsoleCtrlHandler ((PHANDLER_ROUTINE)CtrlHandler, TRUE);
#else
#elif !DDSRT_WITH_FREERTOS
struct sigaction sat, oldAction;
sat.sa_handler = CtrlHandler;
sigemptyset (&sat.sa_mask);
@ -411,7 +411,7 @@ done:
#ifdef _WIN32
SetConsoleCtrlHandler (0, FALSE);
#else
#elif !DDSRT_WITH_FREERTOS
sigaction (SIGINT, &oldAction, 0);
#endif

View file

@ -20,7 +20,7 @@ static bool CtrlHandler (DWORD fdwCtrlType)
dds_waitset_set_trigger (waitSet, true);
return true; //Don't let other handlers handle this key
}
#else
#elif !DDSRT_WITH_FREERTOS
static void CtrlHandler (int sig)
{
(void)sig;
@ -87,7 +87,7 @@ int main (int argc, char *argv[])
#ifdef _WIN32
SetConsoleCtrlHandler ((PHANDLER_ROUTINE)CtrlHandler, TRUE);
#else
#elif !DDSRT_WITH_FREERTOS
struct sigaction sat, oldAction;
sat.sa_handler = CtrlHandler;
sigemptyset (&sat.sa_mask);
@ -130,7 +130,7 @@ int main (int argc, char *argv[])
#ifdef _WIN32
SetConsoleCtrlHandler (0, FALSE);
#else
#elif !DDSRT_WITH_FREERTOS
sigaction (SIGINT, &oldAction, 0);
#endif

View file

@ -19,9 +19,6 @@
#include <assert.h>
#include <limits.h>
#include <math.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <getopt.h>
#include "dds/dds.h"
@ -36,6 +33,10 @@
#include "dds/ddsrt/avl.h"
#include "dds/ddsrt/fibheap.h"
#if !defined(_WIN32) && !defined(LWIP_SOCKET)
#include <errno.h>
#endif
#define UDATA_MAGIC "DDSPerf:"
#define UDATA_MAGIC_SIZE (sizeof (UDATA_MAGIC) - 1)
@ -1383,14 +1384,16 @@ static void subthread_arg_fini (struct subthread_arg *arg)
free (arg->iseq);
}
#if !DDSRT_WITH_FREERTOS
static void signal_handler (int sig)
{
(void) sig;
termflag = 1;
dds_set_guardcondition (termcond, true);
}
#endif
#ifndef _WIN32
#if !_WIN32 && !DDSRT_WITH_FREERTOS
static uint32_t sigthread (void *varg)
{
sigset_t *set = varg;
@ -1642,7 +1645,7 @@ int main (int argc, char *argv[])
int opt;
ddsrt_threadattr_t attr;
ddsrt_thread_t pubtid, subtid, subpingtid, subpongtid;
#ifndef _WIN32
#if !_WIN32 && !DDSRT_WITH_FREERTOS
sigset_t sigset, osigset;
ddsrt_thread_t sigtid;
#endif
@ -1841,7 +1844,7 @@ int main (int argc, char *argv[])
/* I hate Unix signals in multi-threaded processes ... */
#ifdef _WIN32
signal (SIGINT, signal_handler);
#else
#elif !DDSRT_WITH_FREERTOS
sigemptyset (&sigset);
sigaddset (&sigset, SIGINT);
sigaddset (&sigset, SIGTERM);
@ -1989,7 +1992,7 @@ int main (int argc, char *argv[])
#if _WIN32
signal_handler (SIGINT);
#else
#elif !DDSRT_WITH_FREERTOS
{
/* get the attention of the signal handler thread */
void (*osigint) (int);