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:
parent
dba4e6d391
commit
aa2715f4fe
67 changed files with 3691 additions and 200 deletions
103
docs/dev/freertos.md
Normal file
103
docs/dev/freertos.md
Normal 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.
|
||||
|
126
ports/freertos-posix/CMakeLists.txt
Normal file
126
ports/freertos-posix/CMakeLists.txt
Normal 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}")
|
||||
|
83
ports/freertos-posix/README.md
Normal file
83
ports/freertos-posix/README.md
Normal 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.
|
||||
|
33
ports/freertos-posix/freertos-sim.cmake.in
Normal file
33
ports/freertos-posix/freertos-sim.cmake.in
Normal 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)
|
||||
|
74
ports/freertos-posix/include/FreeRTOSConfig.h
Normal file
74
ports/freertos-posix/include/FreeRTOSConfig.h
Normal 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 */
|
165
ports/freertos-posix/src/loader.c
Normal file
165
ports/freertos-posix/src/loader.c
Normal 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;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -11,7 +11,12 @@
|
|||
#
|
||||
set(CUNIT_HEADER "CUnit/CUnit.h")
|
||||
|
||||
find_path(CUNIT_INCLUDE_DIR ${CUNIT_HEADER})
|
||||
if(CONAN_INCLUDE_DIRS)
|
||||
find_path(CUNIT_INCLUDE_DIR ${CUNIT_HEADER} HINTS ${CONAN_INCLUDE_DIRS})
|
||||
else()
|
||||
find_path(CUNIT_INCLUDE_DIR ${CUNIT_HEADER})
|
||||
endif()
|
||||
|
||||
mark_as_advanced(CUNIT_INCLUDE_DIR)
|
||||
|
||||
if(CUNIT_INCLUDE_DIR AND EXISTS "${CUNIT_INCLUDE_DIR}/${CUNIT_HEADER}")
|
||||
|
@ -25,7 +30,11 @@ if(CUNIT_INCLUDE_DIR AND EXISTS "${CUNIT_INCLUDE_DIR}/${CUNIT_HEADER}")
|
|||
set(CUNIT_VERSION "${CUNIT_VERSION_MAJOR}.${CUNIT_VERSION_MINOR}-${CUNIT_VERSION_PATCH}")
|
||||
endif()
|
||||
|
||||
find_library(CUNIT_LIBRARY cunit)
|
||||
if(CONAN_LIB_DIRS)
|
||||
find_library(CUNIT_LIBRARY cunit HINTS ${CONAN_LIB_DIRS})
|
||||
else()
|
||||
find_library(CUNIT_LIBRARY cunit)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(
|
||||
|
|
51
src/cmake/modules/GenerateDummyExportHeader.cmake
Normal file
51
src/cmake/modules/GenerateDummyExportHeader.cmake
Normal 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()
|
||||
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -509,7 +509,7 @@ int os_sockWaitsetNextEvent (os_sockWaitsetCtx ctx, ddsi_tran_conn_t * conn)
|
|||
#define OSPL_PIPENAMESIZE 26
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#if !_WIN32 && !LWIP_SOCKET
|
||||
|
||||
#ifndef __VXWORKS__
|
||||
#include <sys/fcntl.h>
|
||||
|
@ -524,7 +524,7 @@ int os_sockWaitsetNextEvent (os_sockWaitsetCtx ctx, ddsi_tran_conn_t * conn)
|
|||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#endif /* _WIN32 */
|
||||
#endif /* !_WIN32 && !LWIP_SOCKET */
|
||||
|
||||
typedef struct os_sockWaitsetSet
|
||||
{
|
||||
|
@ -586,7 +586,7 @@ fail:
|
|||
closesocket (s2);
|
||||
return -1;
|
||||
}
|
||||
#elif defined (VXWORKS_RTP) || defined (_WRS_KERNEL)
|
||||
#elif defined(__VXWORKS__)
|
||||
static int make_pipe (int pfd[2])
|
||||
{
|
||||
char pipename[OSPL_PIPENAMESIZE];
|
||||
|
@ -609,7 +609,7 @@ fail_open0:
|
|||
fail_pipedev:
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
#elif !defined(LWIP_SOCKET)
|
||||
static int make_pipe (int pfd[2])
|
||||
{
|
||||
return pipe (pfd);
|
||||
|
@ -644,7 +644,11 @@ os_sockWaitset os_sockWaitsetNew (void)
|
|||
ws->fdmax_plus_1 = FD_SETSIZE;
|
||||
#endif
|
||||
|
||||
#if defined (VXWORKS_RTP) || defined (_WRS_KERNEL)
|
||||
#if defined(LWIP_SOCKET)
|
||||
ws->pipe[0] = -1;
|
||||
ws->pipe[1] = -1;
|
||||
result = 0;
|
||||
#elif defined(__VXWORKS__)
|
||||
int make_pipe (int pfd[2])
|
||||
{
|
||||
char pipename[OSPL_PIPENAMESIZE];
|
||||
|
@ -679,15 +683,21 @@ os_sockWaitset os_sockWaitsetNew (void)
|
|||
assert (result != -1);
|
||||
(void) result;
|
||||
|
||||
#if !defined(LWIP_SOCKET)
|
||||
ws->set.fds[0] = ws->pipe[0];
|
||||
#else
|
||||
ws->set.fds[0] = 0;
|
||||
#endif
|
||||
ws->set.conns[0] = NULL;
|
||||
|
||||
#if ! defined (VXWORKS_RTP) && ! defined ( _WRS_KERNEL ) && ! defined (_WIN32)
|
||||
#if !defined(__VXWORKS__) && !defined(_WIN32) && !defined(LWIP_SOCKET)
|
||||
fcntl (ws->pipe[0], F_SETFD, fcntl (ws->pipe[0], F_GETFD) | FD_CLOEXEC);
|
||||
fcntl (ws->pipe[1], F_SETFD, fcntl (ws->pipe[1], F_GETFD) | FD_CLOEXEC);
|
||||
#endif
|
||||
#if !defined(LWIP_SOCKET)
|
||||
FD_SET (ws->set.fds[0], &ws->ctx.rdset);
|
||||
#if ! defined (_WIN32)
|
||||
#endif
|
||||
#if !defined(_WIN32)
|
||||
ws->fdmax_plus_1 = ws->set.fds[0] + 1;
|
||||
#endif
|
||||
|
||||
|
@ -716,18 +726,18 @@ static void os_sockWaitsetFreeCtx (os_sockWaitsetCtx ctx)
|
|||
|
||||
void os_sockWaitsetFree (os_sockWaitset ws)
|
||||
{
|
||||
#ifdef VXWORKS_RTP
|
||||
#if defined(__VXWORKS__) && defined(__RTP__)
|
||||
char nameBuf[OSPL_PIPENAMESIZE];
|
||||
ioctl (ws->pipe[0], FIOGETNAME, &nameBuf);
|
||||
#endif
|
||||
#if defined (_WIN32)
|
||||
#if defined(_WIN32)
|
||||
closesocket (ws->pipe[0]);
|
||||
closesocket (ws->pipe[1]);
|
||||
#else
|
||||
#elif !defined(LWIP_SOCKET)
|
||||
close (ws->pipe[0]);
|
||||
close (ws->pipe[1]);
|
||||
#endif
|
||||
#ifdef VXWORKS_RTP
|
||||
#if defined(__VXWORKS__) && defined(__RTP__)
|
||||
pipeDevDelete ((char*) &nameBuf, 0);
|
||||
#endif
|
||||
os_sockWaitsetFreeSet (&ws->set);
|
||||
|
@ -738,6 +748,9 @@ void os_sockWaitsetFree (os_sockWaitset ws)
|
|||
|
||||
void os_sockWaitsetTrigger (os_sockWaitset ws)
|
||||
{
|
||||
#if defined(LWIP_SOCKET)
|
||||
(void)ws;
|
||||
#else
|
||||
char buf = 0;
|
||||
int n;
|
||||
|
||||
|
@ -750,6 +763,7 @@ void os_sockWaitsetTrigger (os_sockWaitset ws)
|
|||
{
|
||||
DDS_WARNING("os_sockWaitsetTrigger: write failed on trigger pipe\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int os_sockWaitsetAdd (os_sockWaitset ws, ddsi_tran_conn_t conn)
|
||||
|
@ -863,10 +877,19 @@ os_sockWaitsetCtx os_sockWaitsetWait (os_sockWaitset ws)
|
|||
|
||||
rdset = &ctx->rdset;
|
||||
FD_ZERO (rdset);
|
||||
#if !defined(LWIP_SOCKET)
|
||||
for (u = 0; u < dst->n; u++)
|
||||
{
|
||||
FD_SET (dst->fds[u], rdset);
|
||||
}
|
||||
#else
|
||||
for (u = 1; u < dst->n; u++)
|
||||
{
|
||||
DDSRT_WARNING_GNUC_OFF(sign-conversion)
|
||||
FD_SET (dst->fds[u], rdset);
|
||||
DDSRT_WARNING_GNUC_ON(sign-conversion)
|
||||
}
|
||||
#endif /* LWIP_SOCKET */
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -883,6 +906,7 @@ os_sockWaitsetCtx os_sockWaitsetWait (os_sockWaitset ws)
|
|||
{
|
||||
/* this simply skips the trigger fd */
|
||||
ctx->index = 1;
|
||||
#if ! defined(LWIP_SOCKET)
|
||||
if (FD_ISSET (dst->fds[0], rdset))
|
||||
{
|
||||
char buf;
|
||||
|
@ -898,19 +922,26 @@ os_sockWaitsetCtx os_sockWaitsetWait (os_sockWaitset ws)
|
|||
assert (0);
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_SOCKET */
|
||||
return ctx;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(LWIP_SOCKET)
|
||||
DDSRT_WARNING_GNUC_OFF(sign-conversion)
|
||||
#endif
|
||||
|
||||
int os_sockWaitsetNextEvent (os_sockWaitsetCtx ctx, ddsi_tran_conn_t * conn)
|
||||
{
|
||||
while (ctx->index < ctx->set.n)
|
||||
{
|
||||
unsigned idx = ctx->index++;
|
||||
ddsrt_socket_t fd = ctx->set.fds[idx];
|
||||
#if ! defined (LWIP_SOCKET)
|
||||
assert(idx > 0);
|
||||
#endif
|
||||
if (FD_ISSET (fd, &ctx->rdset))
|
||||
{
|
||||
*conn = ctx->set.conns[idx];
|
||||
|
@ -921,6 +952,10 @@ int os_sockWaitsetNextEvent (os_sockWaitsetCtx ctx, ddsi_tran_conn_t * conn)
|
|||
return -1;
|
||||
}
|
||||
|
||||
#if defined(LWIP_SOCKET)
|
||||
DDSRT_WARNING_GNUC_ON(sign-conversion)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "no mode selected"
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(ddsrt INTERFACE Threads::Threads)
|
||||
set(HAVE_MULTI_PROCESS ${HAVE_MULTI_PROCESS} PARENT_SCOPE)
|
||||
|
||||
if(NOT WITH_FREERTOS)
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(ddsrt INTERFACE Threads::Threads)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(ddsrt INTERFACE wsock32 ws2_32 iphlpapi bcrypt)
|
||||
|
|
23
src/ddsrt/cmake/ifaddrs.c
Normal file
23
src/ddsrt/cmake/ifaddrs.c
Normal 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
18
src/ddsrt/cmake/process.c
Normal 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
19
src/ddsrt/cmake/rusage.c
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -12,12 +12,17 @@
|
|||
#ifndef DDSRT_SOCKETS_POSIX_H
|
||||
#define DDSRT_SOCKETS_POSIX_H
|
||||
|
||||
#if DDSRT_WITH_LWIP
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/netdb.h>
|
||||
#else
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
|
@ -27,21 +32,38 @@ typedef int ddsrt_socket_t;
|
|||
#define DDSRT_INVALID_SOCKET (-1)
|
||||
#define PRIdSOCK "d"
|
||||
|
||||
#define DDSRT_HAVE_IPV6 1
|
||||
#define DDSRT_HAVE_DNS 1
|
||||
#define DDSRT_HAVE_SSM 1
|
||||
#if LWIP_SOCKET
|
||||
# if LWIP_IPV6
|
||||
# define DDSRT_HAVE_IPV6 1
|
||||
# endif
|
||||
# if LWIP_DNS && LWIP_SOCKET
|
||||
# define DDSRT_HAVE_DNS DDSRT_WITH_DNS
|
||||
# endif
|
||||
# define DDSRT_HAVE_SSM 0
|
||||
|
||||
# define IFF_UP 0x1
|
||||
# define IFF_BROADCAST 0x2
|
||||
# define IFF_LOOPBACK 0x8
|
||||
# define IFF_POINTOPOINT 0x10
|
||||
# define IFF_MULTICAST 0x1000
|
||||
#else /* LWIP_SOCKET */
|
||||
# define DDSRT_HAVE_IPV6 1
|
||||
# define DDSRT_HAVE_DNS DDSRT_WITH_DNS
|
||||
# define DDSRT_HAVE_SSM 1
|
||||
#endif /* LWIP_SOCKET */
|
||||
|
||||
typedef struct iovec ddsrt_iovec_t;
|
||||
typedef size_t ddsrt_iov_len_t;
|
||||
|
||||
#if defined(__linux)
|
||||
#if defined(__linux) && !LWIP_SOCKET
|
||||
typedef size_t ddsrt_msg_iovlen_t;
|
||||
#else /* POSIX says int (which macOS, FreeBSD, Solaris do) */
|
||||
typedef int ddsrt_msg_iovlen_t;
|
||||
#endif
|
||||
typedef struct msghdr ddsrt_msghdr_t;
|
||||
|
||||
#if defined(__sun) && !defined(_XPG4_2)
|
||||
#if (defined(__sun) && !defined(_XPG4_2)) || \
|
||||
(defined(LWIP_SOCKET))
|
||||
# define DDSRT_MSGHDR_FLAGS 0
|
||||
#else
|
||||
# define DDSRT_MSGHDR_FLAGS 1
|
||||
|
|
|
@ -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) && \
|
||||
|
|
|
@ -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"
|
||||
|
|
93
src/ddsrt/include/dds/ddsrt/sync/freertos.h
Normal file
93
src/ddsrt/include/dds/ddsrt/sync/freertos.h
Normal 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 */
|
|
@ -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
|
||||
|
|
35
src/ddsrt/include/dds/ddsrt/threads/freertos.h
Normal file
35
src/ddsrt/include/dds/ddsrt/threads/freertos.h
Normal 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 */
|
|
@ -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
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "dds/ddsrt/types.h"
|
||||
|
||||
#define DDSRT_HAVE_THREAD_SETNAME (1)
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
@ -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 */
|
||||
|
|
53
src/ddsrt/include/dds/ddsrt/time/freertos.h
Normal file
53
src/ddsrt/include/dds/ddsrt/time/freertos.h
Normal 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 */
|
|
@ -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 */
|
||||
|
|
136
src/ddsrt/src/heap/freertos/heap.c
Normal file
136
src/ddsrt/src/heap/freertos/heap.c
Normal 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);
|
||||
}
|
||||
}
|
207
src/ddsrt/src/ifaddrs/lwip/ifaddrs.c
Normal file
207
src/ddsrt/src/ifaddrs/lwip/ifaddrs.c
Normal 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;
|
||||
}
|
22
src/ddsrt/src/process/freertos/process.c
Normal file
22
src/ddsrt/src/process/freertos/process.c
Normal 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();
|
||||
}
|
||||
|
96
src/ddsrt/src/rusage/freertos/rusage.c
Normal file
96
src/ddsrt/src/rusage/freertos/rusage.c
Normal 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;
|
||||
}
|
|
@ -15,19 +15,21 @@
|
|||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
# if defined(__linux)
|
||||
# include <linux/if_packet.h> /* sockaddr_ll */
|
||||
# endif /* __linux */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include "dds/ddsrt/heap.h"
|
||||
#include "dds/ddsrt/log.h"
|
||||
#include "dds/ddsrt/sockets_priv.h"
|
||||
|
||||
#if !LWIP_SOCKET
|
||||
# if !defined(_WIN32)
|
||||
# include <arpa/inet.h>
|
||||
# include <netdb.h>
|
||||
# include <sys/socket.h>
|
||||
# if defined(__linux)
|
||||
# include <linux/if_packet.h> /* sockaddr_ll */
|
||||
# endif /* __linux */
|
||||
# endif /* _WIN32 */
|
||||
#endif /* LWIP_SOCKET */
|
||||
|
||||
extern inline struct timeval *
|
||||
ddsrt_duration_to_timeval_ceil(dds_duration_t reltime, struct timeval *tv);
|
||||
|
||||
|
@ -37,7 +39,7 @@ const struct in6_addr ddsrt_in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
|
|||
#endif
|
||||
|
||||
const int afs[] = {
|
||||
#ifdef __linux
|
||||
#if defined(__linux) && !LWIP_SOCKET
|
||||
AF_PACKET,
|
||||
#endif /* __linux */
|
||||
#if DDSRT_HAVE_IPV6
|
||||
|
@ -62,7 +64,7 @@ ddsrt_sockaddr_get_size(const struct sockaddr *const sa)
|
|||
sz = sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
#endif /* DDSRT_HAVE_IPV6 */
|
||||
#ifdef __linux
|
||||
#if defined(__linux) && !LWIP_SOCKET
|
||||
case AF_PACKET:
|
||||
sz = sizeof(struct sockaddr_ll);
|
||||
break;
|
||||
|
@ -218,6 +220,9 @@ dds_retcode_t ddsrt_sockaddrtostr(const void *sa, char *buf, size_t size)
|
|||
assert(sa != NULL);
|
||||
assert(buf != NULL);
|
||||
|
||||
#if LWIP_SOCKET
|
||||
DDSRT_WARNING_GNUC_OFF(sign-conversion)
|
||||
#endif
|
||||
switch (((struct sockaddr *)sa)->sa_family) {
|
||||
case AF_INET:
|
||||
ptr = inet_ntop(
|
||||
|
@ -232,6 +237,9 @@ dds_retcode_t ddsrt_sockaddrtostr(const void *sa, char *buf, size_t size)
|
|||
default:
|
||||
return DDS_RETCODE_BAD_PARAMETER;
|
||||
}
|
||||
#if LWIP_SOCKET
|
||||
DDSRT_WARNING_GNUC_ON(sign-conversion)
|
||||
#endif
|
||||
|
||||
if (ptr == NULL) {
|
||||
return DDS_RETCODE_NOT_ENOUGH_SPACE;
|
||||
|
@ -312,10 +320,14 @@ ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp)
|
|||
/* Other system error. */
|
||||
return DDS_RETCODE_ERROR;
|
||||
#endif
|
||||
#if defined(EAI_BADFLAGS)
|
||||
case EAI_BADFLAGS: /* Invalid flags in hints.ai_flags. */
|
||||
#endif
|
||||
case EAI_FAMILY: /* Address family not supported. */
|
||||
case EAI_SERVICE: /* Service not available for socket type. */
|
||||
#if defined(EAI_SOCKTYPE)
|
||||
case EAI_SOCKTYPE: /* Socket type not supported. */
|
||||
#endif
|
||||
case 0: {
|
||||
struct addrinfo *ai;
|
||||
size_t addrno, naddrs, size;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
469
src/ddsrt/src/sync/freertos/sync.c
Normal file
469
src/ddsrt/src/sync/freertos/sync.c
Normal 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;
|
||||
}
|
396
src/ddsrt/src/sync/freertos/tasklist.c
Normal file
396
src/ddsrt/src/sync/freertos/tasklist.c
Normal 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;
|
||||
}
|
545
src/ddsrt/src/threads/freertos/threads.c
Normal file
545
src/ddsrt/src/threads/freertos/threads.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
53
src/ddsrt/src/time/freertos/time.c
Normal file
53
src/ddsrt/src/time/freertos/time.c
Normal 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);
|
||||
}
|
|
@ -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,35 +26,37 @@ 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.
|
||||
add_executable(process_app process_app.c)
|
||||
target_link_libraries(process_app PRIVATE ddsrt)
|
||||
target_include_directories(
|
||||
if(HAVE_MULTI_PROCESS)
|
||||
# A separate application is required to test process management.
|
||||
add_executable(process_app process_app.c)
|
||||
target_link_libraries(process_app PRIVATE ddsrt)
|
||||
target_include_directories(
|
||||
process_app
|
||||
PRIVATE
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>")
|
||||
# Force the app to be at the same location, no matter what platform or build type.
|
||||
set_target_properties(
|
||||
# Force the app to be at the same location, no matter what platform or build type.
|
||||
# FIXME: What if custom targets are added?
|
||||
# FIXME: What debug and release builds are mixed on Windows and macOS?
|
||||
set_target_properties(
|
||||
process_app
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
|
@ -61,8 +64,9 @@ set_target_properties(
|
|||
RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR}
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_BINARY_DIR}
|
||||
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
# Let the cunit application know the location and name of the test application.
|
||||
set(process_app_name "${CMAKE_CURRENT_BINARY_DIR}/process_app${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
configure_file(
|
||||
# Let the cunit application know the location and name of the test application.
|
||||
set(process_app_name "${CMAKE_CURRENT_BINARY_DIR}/process_app${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
configure_file(
|
||||
"process_test.h.in" "${CMAKE_CURRENT_BINARY_DIR}/include/process_test.h" @ONLY)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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
341
src/ddsrt/tests/tasklist.c
Normal 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);
|
||||
}
|
|
@ -11,9 +11,12 @@
|
|||
*/
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#if !defined(_WIN32)
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
#if DDSRT_WITH_FREERTOS
|
||||
# include <FreeRTOS.h>
|
||||
# include <task.h>
|
||||
#elif !defined(_WIN32)
|
||||
# include <sched.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "CUnit/Theory.h"
|
||||
|
@ -30,7 +33,10 @@ static int32_t min_other_prio = 250;
|
|||
CU_Init(ddsrt_thread)
|
||||
{
|
||||
ddsrt_init();
|
||||
#if defined(WIN32)
|
||||
#if DDSRT_WITH_FREERTOS
|
||||
max_other_prio = max_fifo_prio = configMAX_PRIORITIES - 1;
|
||||
min_other_prio = min_fifo_prio = tskIDLE_PRIORITY + 1;
|
||||
#elif defined(WIN32)
|
||||
max_fifo_prio = THREAD_PRIORITY_HIGHEST;
|
||||
min_fifo_prio = THREAD_PRIORITY_LOWEST;
|
||||
max_other_prio = THREAD_PRIORITY_HIGHEST;
|
||||
|
@ -68,7 +74,12 @@ uint32_t thread_main(void *ptr)
|
|||
|
||||
attr = arg->attr;
|
||||
|
||||
#if _WIN32
|
||||
#if DDSRT_WITH_FREERTOS
|
||||
int prio = (int)uxTaskPriorityGet(NULL);
|
||||
if (prio == attr->schedPriority) {
|
||||
arg->res = 1;
|
||||
}
|
||||
#elif _WIN32
|
||||
int prio = GetThreadPriority(GetCurrentThread());
|
||||
if (prio == THREAD_PRIORITY_ERROR_RETURN)
|
||||
abort();
|
||||
|
@ -113,7 +124,12 @@ CU_Theory((ddsrt_sched_t sched, int32_t *prio, uint32_t exp), ddsrt_thread, crea
|
|||
ddsrt_threadattr_t attr;
|
||||
thread_arg_t arg;
|
||||
|
||||
#if defined(__VXWORKS__)
|
||||
#if DDSRT_WITH_FREERTOS
|
||||
if (sched == DDSRT_SCHED_TIMESHARE) {
|
||||
skip = 1;
|
||||
CU_PASS("FreeRTOS only support SCHED_FIFO");
|
||||
}
|
||||
#elif defined(__VXWORKS__)
|
||||
# if defined(_WRS_KERNEL)
|
||||
if (sched == DDSRT_SCHED_TIMESHARE) {
|
||||
skip = 1;
|
||||
|
@ -150,7 +166,9 @@ CU_Test(ddsrt_thread, thread_id)
|
|||
{
|
||||
int eq = 0;
|
||||
ddsrt_thread_t thr;
|
||||
#if defined(_WIN32)
|
||||
#if DDSRT_WITH_FREERTOS
|
||||
TaskHandle_t task;
|
||||
#elif defined(_WIN32)
|
||||
DWORD _tid;
|
||||
#else
|
||||
pthread_t _thr;
|
||||
|
@ -158,7 +176,10 @@ CU_Test(ddsrt_thread, thread_id)
|
|||
|
||||
thr = ddsrt_thread_self();
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if DDSRT_WITH_FREERTOS
|
||||
task = xTaskGetCurrentTaskHandle();
|
||||
eq = (thr.task == task);
|
||||
#elif defined(_WIN32)
|
||||
_tid = GetCurrentThreadId();
|
||||
eq = (thr.tid == _tid);
|
||||
#else
|
||||
|
@ -230,4 +251,3 @@ CU_Test(ddsrt_thread, attribute)
|
|||
CU_ASSERT_EQUAL(attr.schedPriority, 0);
|
||||
CU_ASSERT_EQUAL(attr.stackSize, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue