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

103
docs/dev/freertos.md Normal file
View file

@ -0,0 +1,103 @@
# FreeRTOS
[FreeRTOS][1] is real-time operating system kernel for embedded devices. Think
of it as a thread library rather than a general purpose operating system like
Linux or Microsoft Windows. Out-of-the-box, FreeRTOS provides support for
tasks (threads), mutexes, semaphores and software times. Third-party modules
are available to add features. e.g. [lwIP][2] can be used to add networking.
> FreeRTOS+lwIP is currently supported by Eclipse Cyclone DDS. Support for other
> network stacks, e.g. [FreeRTOS+TCP][3], may be added in the future.
> Eclipse Cyclone DDS does not make use of [FreeRTOS+POSIX][4] because it was
> not available at the time. Future versions of Eclipse Cyclone DDS may or may
> not require FreeRTOS+POSIX for compatibility when it becomes stable.
[1]: https://www.freertos.org/
[2]: https://savannah.nongnu.org/projects/lwip/
[3]: https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/index.html
[4]: https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_POSIX/index.html
## Target
FreeRTOS provides an operating system kernel. Batteries are not included. i.e.
no C library or device drivers. Third-party distributions, known as board
support packages (BSP), for various (hardware) platforms are available though.
Board support packages, apart from FreeRTOS, contain:
* C library. Often ships with the compiler toolchain, e.g.
[IAR Embedded Workbench][5] includes the DLIB runtime, but open source
libraries can also be used. e.g. The [Xilinx Software Development Kit][6]
includes newlib.
* Device drivers. Generally available from the hardware vendor, e.g. NXP or
Xilinx. Device drivers for extra components, like a real-time clock, must
also be included in the board support package.
[5]: https://www.iar.com/iar-embedded-workbench/
[6]: https://www.xilinx.com/products/design-tools/embedded-software/sdk.html
A board support package is linked with the application by the toolchain to
generate a binary that can be flashed to the target.
### Requirements
Eclipse Cyclone DDS requires certain compile-time options to be enabled in
FreeRTOS (`FreeRTOSConfig.h`) and lwIP (`lwipopts.h`) for correct operation.
The compiler will croak when a required compile-time option is not enabled.
Apart from the aforementioned compile-time options, the target and toolchain
must provide the following.
* Support for thread-local storage (TLS) from the compiler and linker.
* Berkeley socket API compatible socket interface.
* Real-time clock (RTC). A high-precision real-time clock is preferred, but
the monotonic clock can be combined with an offset obtained from e.g. the
network if the target lacks an actual real-time clock. A proper
`clock_gettime` implementation is required to retrieve the wall clock time.
### Thread-local storage
FreeRTOS tasks are not threads and compiler supported thread-local storage
(tls) might not work as desired/expected under FreeRTOS on embedded targets.
i.e. the address of a given variable defined with *__thread* may be the same
for different tasks.
The compiler generates code to retrieve a unique address per thread when it
encounters a variable defined with *__thread*. What code it generates depends
on the compiler and the target it generates the code for. e.g. `iccarm.exe`
that comes with IAR Embedded Workbench requires `__aeabi_read_tp` to be
implemented and `mb-gcc` that comes with the Xilinx SDK requires
`__tls_get_addr` to be implemented.
The implementation for each of these functions is more-or-less the same.
Generally speaking they require the number of bytes to allocate, call
`pvTaskGetThreadLocalStoragePointer` and return the address of the memory
block to the caller.
## Simulator
FreeRTOS ports for Windows and POSIX exist to test compatibility. How to
cross-compile Eclipse Cyclone DDS for the [FreeRTOS Windows Port][7] or
the unofficial [FreeRTOS POSIX Port][8] can be found in the msvc and
[posix](/ports/freertos-posix) port directories.
[7]: https://www.freertos.org/FreeRTOS-Windows-Simulator-Emulator-for-Visual-Studio-and-Eclipse-MingW.html
[8]: https://github.com/shlinym/FreeRTOS-Sim.git
## Known Limitations
Triggering the socket waitset is not (yet) implemented for FreeRTOS+lwIP. This
introduces issues in scenarios where it is required.
* Receive threads require a trigger to shutdown or a thread may block
indefinitely if no packet arrives from the network.
* Sockets are created dynamically if ManySocketsMode is used and a participant
is created, or TCP is used. A trigger is issued after the sockets are added
to the set if I/O multiplexing logic does not automatically wait for data
on the newly created sockets as well.

View file

@ -0,0 +1,126 @@
#
# 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
#
cmake_minimum_required(VERSION 3.5)
project(FreeRTOS-Sim VERSION 10.0.2.0)
include(GNUInstallDirs)
# Some distributions place libraries in lib64 when the architecture is x86_64,
# but since the simulator is compiled with -m32, lib is a better name.
if(UNIX AND CMAKE_INSTALL_LIBDIR STREQUAL "lib64")
set(CMAKE_INSTALL_LIBDIR "lib")
endif()
# Conflicts may be introduced when placing the libraries or headers in the
# default system locations, i.e. /usr/lib and /usr/include on *NIX platforms.
# The install prefix must therefore be postfixed with the project name.
if(UNIX)
set(CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/${CMAKE_PROJECT_NAME}")
endif()
set(ENTRYPOINT "real_main"
CACHE STRING "Alternate name of original entrypoint")
set(FREERTOS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/FreeRTOS-Sim"
CACHE STRING "Location of FreeRTOS POSIX Port sources")
set(source_path "${FREERTOS_SOURCE_DIR}/Source")
list(APPEND sources
"${source_path}/croutine.c"
"${source_path}/event_groups.c"
"${source_path}/list.c"
"${source_path}/queue.c"
"${source_path}/tasks.c"
"${source_path}/timers.c"
"${source_path}/portable/MemMang/heap_3.c"
"${source_path}/portable/GCC/POSIX/port.c")
list(APPEND headers
"${source_path}/include/croutine.h"
"${source_path}/include/deprecated_definitions.h"
"${source_path}/include/event_groups.h"
"${source_path}/include/FreeRTOS.h"
"${source_path}/include/list.h"
"${source_path}/include/mpu_prototypes.h"
"${source_path}/include/mpu_wrappers.h"
"${source_path}/include/portable.h"
"${source_path}/include/projdefs.h"
"${source_path}/include/queue.h"
"${source_path}/include/semphr.h"
"${source_path}/include/StackMacros.h"
"${source_path}/include/task.h"
"${source_path}/include/timers.h"
"${source_path}/portable/GCC/POSIX/portmacro.h")
list(APPEND headers
"${CMAKE_CURRENT_SOURCE_DIR}/include/FreeRTOSConfig.h")
add_library(freertos-sim ${sources})
target_compile_definitions(
freertos-sim PUBLIC __GCC_POSIX=1 MAX_NUMBER_OF_TASKS=300)
target_compile_options(
freertos-sim
PUBLIC
-m32
PRIVATE
-W -Wall -Werror -Wmissing-braces -Wno-cast-align -Wparentheses -Wshadow
-Wno-sign-compare -Wswitch -Wuninitialized -Wunknown-pragmas
-Wunused-function -Wunused-label -Wunused-parameter -Wunused-value
-Wunused-variable -Wmissing-prototypes)
target_include_directories(
freertos-sim
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${source_path}/include>"
"$<BUILD_INTERFACE:${source_path}/portable/GCC/POSIX>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_link_libraries(
freertos-sim PUBLIC -m32 -pthread)
if(CMAKE_BUILD_TYPE STREQUAL "DEBUG" OR
CMAKE_BUILD_TYPE STREQUAL "RELWITHDEBINFO")
target_compile_options(freertos-sim PUBLIC -ggdb)
target_link_libraries(freertos-sim PUBLIC -ggdb)
endif()
# The FreeRTOS POSIX Port does not require hardware to be initialized (unless
# lwIP is used), but the scheduler must be started before it is safe to execute
# application code. A "loader" is built to avoid modifications to existing
# code. The generated toolchain file will automatically redefine "main" to
# "real_main". The "real_main" function is executed once the scheduler is
# started.
#
# The loader is not part of the freertos-sim target as it has no place in the
# board support package.
add_library(freertos-sim-loader
"${CMAKE_CURRENT_SOURCE_DIR}/src/loader.c")
set_source_files_properties(
"${CMAKE_CURRENT_SOURCE_DIR}/src/loader.c"
PROPERTIES COMPILE_DEFINITIONS real_main=${ENTRYPOINT})
target_link_libraries(freertos-sim-loader freertos-sim)
install(
FILES ${headers}
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
configure_file("freertos-sim.cmake.in" "freertos-sim.cmake" @ONLY)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/freertos-sim.cmake"
DESTINATION "${CMAKE_INSTALL_DATADIR}")
install(
TARGETS freertos-sim freertos-sim-loader
EXPORT "${CMAKE_PROJECT_NAME}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")

View file

@ -0,0 +1,83 @@
# FreeRTOS POSIX Port
FreeRTOS is a supported platform for Eclipse Cyclone DDS. This document
explains how to build and run Eclipse Cyclone DDS on the FreeRTOS POSIX Port.
For basic information, see: [freertos.md](/docs/dev/freertos.md).
As the steps for building and running on the FreeRTOS POSIX Port are largely
the same as building and running on an actual embedded target, this document
should provide an excellent starting point for users. Apart from that, the
simulator can be used to verify commits do not break FreeRTOS compatibility.
> lwIP can also be used in combination with both UNIX and Windows targets, but
> the simulator does not yet have integration. Once integration between both
> is figured out, this document should be updated accordingly.
## Build and install the simulator
The FreeRTOS POSIX Port is not maintained by the FreeRTOS project. Various
projects are maintained across the internet. At the time of writing, the
version maintained by [Shilin][1] seemed the best as the version maintained by
[megakilo][2] was archived.
[1]: https://github.com/shlinym/FreeRTOS-Sim.git
[2]: https://github.com/megakilo/FreeRTOS-Sim
> A [FreeRTOS Linux Port][3] is in the works. Once it becomes stable, please
> update this document accordingly.
[3]: https://sourceforge.net/p/freertos/discussion/382005/thread/f28af711/
1. Clone the repository. The `CMakeLists.txt` in this directory assumes the
sources are available `./FreeRTOS-Sim` by default, but a different location
can be specified using the CMake option `FREERTOS_SOURCE_DIR`.
```
git clone https://github.com/shlinym/FreeRTOS-Sim.git
```
2. Specify an installation prefix and build the simulator like any other
CMake project.
```
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=$(pwd)/install ..
cmake --build . --target install
```
> A CMake toolchain file is generated and installed into a `share` directory
> located under CMAKE\_INSTALL\_PREFIX/FreeRTOS-Sim. The compiler that CMake
> discovers and uses to build the simulator is exported in the toolchain file
> and will also be used to build Eclipse Cyclone DDS in the following steps.
## Build Eclipse Cyclone DDS for the simulator
1. Change to the root of the repository and install the dependencies.
```
mkdir build
cd build
conan install -s arch=x86 ..
```
> For actual cross-compilation environments the instructions above will not
> install the correct packages. Even when e.g. Clang instead of GCC was used
> to build the simulator, the mismatch between Conan and CMake will break the
> build. To install the correct packages for the target, specify the required
> settings e.g. when the simulator was built using Clang 7.0, use
> `conan install -s arch=x86 -s compiler=clang -s compiler.version=7.0 ..`.
> If packages are not yet available for the target, as is usually the case
> with actual embedded targets, export the path to the toolchain file in the
> `CONAN_CMAKE_TOOLCHAIN_FILE` environment variable and add the `-b` flag to
> build the packages.
2. Build Eclipse Cyclone DDS.
```
$ cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/toolchain/file -DWITH_FREERTOS=on ../src
```
> Examples (and tests) can be executed like usual. The simulator provides a
> *loader* that initializes the hardware (not used on non-embedded targets),
> starts the scheduler and loads the application.

View file

@ -0,0 +1,33 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
#
# CMake toolchain file generated by @CMAKE_PROJECT_NAME@
#
set(CMAKE_C_COMPILER "@CMAKE_C_COMPILER@")
set(CMAKE_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
set(include_path "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@")
set(library_path "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@")
set(CMAKE_C_FLAGS "-I${include_path} -Dmain=@ENTRYPOINT@ -m32")
set(CMAKE_EXE_LINKER_FLAGS "-L${library_path}")
set(CMAKE_SHARED_LINKER_FLAGS "-L${library_path}")
set(CMAKE_C_STANDARD_LIBRARIES "-Wl,--start-group,-lfreertos-sim,-lfreertos-sim-loader,--end-group -m32 -lpthread")
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

View file

@ -0,0 +1,74 @@
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 1
#define configUSE_TICK_HOOK 1
#define configTICK_RATE_HZ ( ( portTickType ) 1000 )
#define configMINIMAL_STACK_SIZE ( ( unsigned portSHORT ) 64 ) /* This can be made smaller if required. */
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 64 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1
#define configCHECK_FOR_STACK_OVERFLOW 0 /* Do not use this option on the PC port. */
#define configUSE_RECURSIVE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 20
#define configUSE_MALLOC_FAILED_HOOK 1
#define configUSE_APPLICATION_TASK_TAG 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_ALTERNATIVE_API 0
//#define configMAX_SYSCALL_INTERRUPT_PRIORITY 1
#define configUSE_QUEUE_SETS 1
#define configUSE_TASK_NOTIFICATIONS 1
/* Software timer related configuration options. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 20
#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 )
#define configMAX_PRIORITIES ( 10 )
#define configGENERATE_RUN_TIME_STATS 1
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. In most cases the linker will remove unused
functions anyway. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_uxTaskGetStackHighWaterMark 0 /* Do not use this option on the PC port. */
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_pcTaskGetTaskName 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
/* It is a good idea to define configASSERT() while developing. configASSERT()
uses the same semantics as the standard C assert() macro. */
extern void vAssertCalled( unsigned long ulLine, const char * const pcFileName );
#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __LINE__, __FILE__ )
#endif /* FREERTOS_CONFIG_H */

View file

@ -0,0 +1,165 @@
/*
* 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
*/
/*
* Launcher to run existing programs in the FreeRTOS+lwIP Simulator.
*
* Verification of FreeRTOS+lwIP compatibility in Continuous Integration (CI)
* setups is another intended purpose.
*/
#include <assert.h>
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if _WIN32
# define EX_OK (0)
# define EX_USAGE (64)
# define LF "\r\n"
#else
# include <sysexits.h>
# define LF "\n"
#endif
#include <FreeRTOS.h>
#include <task.h>
/* Setup system hardware. */
void prvSetupHardware(void)
{
/* No hardware to setup when running in the simulator. */
return;
}
void vAssertCalled(unsigned long ulLine, const char * const pcFileName)
{
taskENTER_CRITICAL();
{
fprintf(stderr, "[ASSERT] %s:%lu"LF, pcFileName, ulLine);
}
taskEXIT_CRITICAL();
abort();
}
void vApplicationMallocFailedHook(void)
{
vAssertCalled(__LINE__, __FILE__);
}
void vApplicationIdleHook(void) { return; }
void vApplicationTickHook( void ) { return; }
static void usage(const char *name)
{
static const char fmt[] =
"Usage: %s LAUNCHER_OPTIONS -- PROGRAM_OPTIONS"LF
"Try '%s -h' for more information"LF;
fprintf(stderr, fmt, name, name);
}
static void help(const char *name)
{
static const char fmt[] =
"Usage: %s LAUNCHER_OPTIONS -- PROGRAM_OPTIONS"LF
""LF
"Launcher options:"LF
" -h Show this help message and exit"LF;
fprintf(stdout, fmt, name);
}
typedef struct {
int argc;
char **argv;
} args_t;
extern int real_main(int argc, char *argv[]);
static void vMainTask(void *ptr)
{
args_t *args = (args_t *)ptr;
/* Reset getopt global variables. */
opterr = 1;
optind = 1;
(void)real_main(args->argc, args->argv);
vPortFree(args->argv);
vPortFree(args);
vTaskDelete(NULL);
_Exit(0);
}
int
main(int argc, char *argv[])
{
int opt;
char *name;
args_t *args = NULL;
/* Determine program name. */
assert(argc >= 0 && argv[0] != NULL);
name = strrchr(argv[0], '/');
if (name != NULL) {
name++;
} else {
name = argv[0];
}
if ((args = pvPortMalloc(sizeof(*args))) == NULL) {
return EX_OSERR;
}
memset(args, 0, sizeof(*args));
/* Parse command line options. */
while ((opt = getopt(argc, argv, ":a:dg:hn:")) != -1) {
switch (opt) {
case 'h':
help(name);
exit(EX_OK);
case '?':
fprintf(stderr, "Unknown option '%c'"LF, opt);
usage(name);
exit(EX_USAGE);
case ':':
/* fall through */
default:
fprintf(stderr, "Option '%c' requires an argument"LF, opt);
usage(name);
exit(EX_USAGE);
}
}
/* Copy leftover arguments into a new array. */
args->argc = (argc - optind) + 1;
args->argv = pvPortMalloc((args->argc + 1) * sizeof(*args->argv));
if (args->argv == NULL) {
return EX_OSERR;
}
args->argv[0] = argv[0];
for (int i = optind, j = 1; i < argc; i++, j++) {
args->argv[j] = argv[i];
}
prvSetupHardware();
xTaskCreate(vMainTask, name,
configMINIMAL_STACK_SIZE, args, (tskIDLE_PRIORITY + 1UL),
(xTaskHandle *) NULL);
vTaskStartScheduler();
return EX_SOFTWARE;
}

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")
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()
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,14 +683,20 @@ 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);
#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)
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)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${feature}.c")
check_runtime_feature(cmake/${feature}.c)
else()
set(HAVE_${feature_uc} TRUE)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${feature}.c")
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(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"
#if LWIP_SOCKET
# if LWIP_IPV6
# define DDSRT_HAVE_IPV6 1
#define DDSRT_HAVE_DNS 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,6 +15,11 @@
#include <stdbool.h>
#include <string.h>
#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>
@ -23,10 +28,7 @@
# 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"
#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)
#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,8 +10,9 @@
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
include(CUnit)
include(GenerateDummyExportHeader)
set(sources
list(APPEND sources
"atomics.c"
"environ.c"
"heap.c"
@ -25,27 +26,27 @@ set(sources
"random.c"
"strlcpy.c"
"socket.c"
"process.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.
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(
@ -53,6 +54,8 @@ target_include_directories(
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
@ -65,4 +68,5 @@ set_target_properties(
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,7 +11,10 @@
*/
#include <assert.h>
#include <stdlib.h>
#if !defined(_WIN32)
#if DDSRT_WITH_FREERTOS
# include <FreeRTOS.h>
# include <task.h>
#elif !defined(_WIN32)
# include <sched.h>
# include <unistd.h>
#endif
@ -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);